tl; dr
永远不要使用遗留类java.util.Date 。
Instant // The modern way to represent a moment in UTC with a resolution of nanoseconds. Supplants the terrible `java.util.Date` class.
.ofEpochSecond( // Parse a count since epoch reference of 1970-01-01T00:00:00Z.
0L , // Passing zero for the count of whole seconds, to let the class determine this number from the 2nd argument.
Long.parse( "1558439504711000000" ) // Count of nanoseconds since the epoch reference of 1970-01-01T00:00:00Z.
) // Returns a `Instant` object.
.atZone( // Adjust from UTC to the wall-clock time used by the people of a specific region (a time zone).
ZoneId.of( "Europe/London" )
) // Returns a `ZonedDateTime` object. Same moment as the `Instant`, same point on the timeline, different wall-clock time.
.format( // Generate text to communicate the value of the moment as seen through this time zone.
DateTimeFormatter.ofPattern( // Define how to format our generated text.
"dd-MM-uuuu HH:mm:ss" , // Specify your desired formatting pattern.
Locale.UK // Pass a `Locale` to be used in localizing, to (a) determine human language used in translating name of day-of-week and such, and (b) determine cultural norms to decide issues of capitalization, abbreviation, etc. Not really needed for this particular formatting pattern, but a good habit to specify `Locale`.
) // Returns a `DateTimeFormatter` object.
) // Returns a `String` object containing our text.
21-05-2019 12:51:44
…要么…
Instant
.ofEpochSecond (
TimeUnit.NANOSECONDS.toSeconds(
Long.parse( "1558439504711000000" )
) ,
( 1_558_439_504_711_000_000L % 1_000_000_000L )
)
.toString()
2019-05-21T11:51:44.711Z
注意时差,因为时区比UTC早一小时。
避免使用旧的日期时间类
java.util.Date类很糟糕 。 连同它的Calendar和SimpleDateFormat ,真是一团糟。 避免他们。 Sun,Oracle和JCP社区在采用JSR 310时放弃了它们。
Instant
一个java.util.Date对象用UTC表示一个时刻,分辨率为毫秒 。 它的替换内容是java.time.Instant ,也是UTC中的一刻,但分辨率为纳秒 。
为了避免处理巨大的数字, Instant在内部跟踪自1970年以来的整数秒, 外加小数秒(以纳秒为单位)。 两个单独的数字。
使用Long类将输入字符串解析为long 。 顺便说一句,请注意您的值正在逼近64位整数的限制 。
long totalNanos = Long.parse( "1558439504711000000" ) ;
使用TimeUnit 枚举来算出整秒的数学运算。
long secondsPortion = TimeUnit.NANOSECONDS.toSeconds( totalNanos ) ;
模为十亿分之一,其余为小数秒的纳秒。
long nanosPortion = ( totalNanos % 1_000_000_000L ) ;
实例化一个Instant 。
Instant instant = Instant.ofEpochSecond( secondsPortion , nanosPortion ) ;
我的时间戳以6个零结尾,这表明时间以纳秒为单位。
实际上,纳秒的计数高达十亿,因此九(9)位数字不是六(6)位。 从纪元开始711000000是711000000 ,即711,000,000纳秒。 您的总秒数为1558439504或1,558,439,504(十亿分之一)。 作为小数点:
自1970-01-01T00:00Z起1,558,439,504.711000000秒
时区
我遇到了一些示例,其中人们使用了我不需要的时区。
为了表示一个时刻,即时间轴上的特定点, 您始终需要一个时区 (或从UTC偏移小时-分钟-秒)。
要查看特定区域(时区)的人们在墙上时钟所用的同一时刻,请应用ZoneId来获取ZonedDateTime 。
以Continent/Region的格式指定正确的时区名称 ,例如America/Montreal , Africa/Casablanca或Pacific/Auckland 。 切勿使用2-4个字母的缩写,例如BST或EST或IST因为它们不是真实的时区,不是标准化的,甚至不是唯一的(!)。
ZoneId z = ZoneId.of( "Europe/London" ) ;
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, same point on the timeline, different wall-clock time.
2019-05-21T12:51:44.711 + 01:00 [欧洲/伦敦]
请注意一天中的时间调整,从11点到12点。这很有意义,因为Europe/London地区比该日期的UTC早一个小时。 同一时刻,时间轴上的同一点,不同的时钟时间。
捷径
正如Ole VV在评论中指出的,您可以跳过上面讨论的数学。 将完整的纳秒数作为ofEpochSecond的第二个参数。 该类在内部进行数学运算,以将整秒与小数秒分开。
Instant instant = Instant.ofEpochSecond( 0L , 1_558_439_504_711_000_000L ) ;
产生文字
以标准ISO 8601格式生成表示该ZonedDateTime值的文本,该格式已扩展为将时区的名称附加在方括号中。
String output = zdt.toString() ;
2019-05-21T12:51:44.711 + 01:00 [欧洲/伦敦]
或者让java.time自动为您本地化。
Locale locale = Locale.UK;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.SHORT ).withLocale( locale );
String output = zdt.format( f );
21/05/2019,12:51
或指定自定义格式。
Locale locale = Locale.UK;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd-MM-uuuu HH:mm:ss" , locale ) ;
String output = zdt.format( f );
21-05-2019 12:51:44
提示:在提供日期时间时要非常小心,不要显式指定区域。 这会产生歧义,用户可能会假设正在玩一个不同的区域/偏移。