简述
Instant.ofEpochMilli( 1_317_816_735_000L )
.atZone( ZoneId.of( "Pacific/Auckland" ) )
.format( DateTimeFormatter.ofLocalizedDateTime( FormatStyle.MEDIUM ).withLocale( new Locale( "en" , "NZ" ) ) )
…同样也…
LocalDateTime.parse( "2011-10-06 03:35:05".replace( " " , "T" ) )
.atZone( ZoneId.of( "Pacific/Auckland" ) )
java.time
问题和大多数答案使用Java早期版本中过时的日期时间类。这些旧类已被证明是麻烦和令人困惑的。请避免使用它们,而是使用java.time类。
ISO 8601
您的输入字符串几乎符合标准的ISO 8601格式。只需将中间的空格替换为
T
即可。
String input = "2011-10-06 03:35:05".replace( " " , "T" );
LocalDateTime
现在解析为LocalDateTime
,因为输入缺乏有关偏移量或时区的任何信息。 LocalDateTime
没有偏移量或时区的概念,因此它不代表时间线上的实际时刻。
LocalDateTime ldt = LocalDateTime.parse( input );
ZoneOffset
您似乎是在说,从业务上下文中,您知道此字符串的意图是表示比UTC快13个小时的时刻。因此,我们实例化一个ZoneOffset
。
ZoneOffset offset = ZoneOffset.ofHours( 13 ); // 13 hours ahead of UTC, in the far east of the globe.
OffsetDateTime
应用它以获取一个OffsetDateTime
对象。这将成为时间轴上的一个实际时刻。
OffsetDateTime odt = ldt.atOffset( offset);
ZoneId
但是你提到了新西兰。所以你有一个特定的时区在脑海中。时区是距离UTC的偏移量加上一组处理异常情况(如夏令时)的规则。因此,我们可以将ZoneId
指定给ZonedDateTime
,而不仅仅是一个简单的偏移量。
请指定正确的时区名称。永远不要使用3-4个字母的缩写,例如EST
或IST
,因为它们不是真正的时区,没有标准化,甚至不是唯一的(!)。例如,Pacific/Auckland
。
ZoneId z = ZoneId.of( "Pacific/Auckland" );
ZonedDateTime
应用 ZoneId
。
ZonedDateTime zdt = ldt.atZone( z );
你可以在时间轴上同一时刻轻松调整到另一个区域。
ZoneId zParis = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdtParis = zdt.withZoneSameInstant( zParis ); // Same moment in time, but seen through lens of Paris wall-clock time.
从纪元开始计数
我强烈建议不要将日期时间值处理为从纪元开始的计数,比如从1970年UTC开始的毫秒数。但如果你必须这样做,可以使用一个Instant
对象从这样的数字中创建。
Instant instant = Instant.ofEpochMilli( 1_317_816_735_000L );
如果需要,可以像上面所示一样分配一个时区,以远离UTC。
ZoneId z = ZoneId.of( "Pacific/Auckland" );
ZonedDateTime zdt = instant.atZone( z );
您的值为1_317_816_735_000L
:
2011-10-05T12:12:15Z
(2011年10月5日星期三,格林威治标准时间12:12:15)
2011-10-06T01:12:15+13:00[Pacific/Auckland]
(新西兰奥克兰时间2011年10月6日星期四01:12:15)
生成字符串
要生成标准ISO 8601格式的字符串,只需调用toString
。请注意,ZonedDateTime
明智地通过在方括号中附加时区名称来扩展标准格式。
String output = zdt.toString();
对于其他格式,请在 Stack Overflow 中搜索
DateTimeFormatter
类。已经有很多相关的讨论了。
指定一个
FormatStyle
和一个
Locale
。
Locale l = new Locale( "en" , "NZ" );
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.MEDIUM ).withLocale( l );
String output = zdt.format( f );
请注意,时区与语言环境无关。您可以将
Europe/Paris
的日期和时间显示为日本语言和文化规范,或将
Asia/Kolkata
的日期和时间显示为葡萄牙语和巴西文化规范。
关于java.time
java.time框架内置于Java 8及更高版本中。这些类替代了麻烦的旧日期时间类,如
java.util.Date
,
.Calendar
和
java.text.SimpleDateFormat
。
Joda-Time项目现在处于
维护模式,建议迁移到java.time。
要了解更多信息,请参见
Oracle教程。并在Stack Overflow上搜索许多示例和说明。
许多java.time的功能被移植到Java 6和7中,可以使用ThreeTen-Backport进行进一步适配,并在ThreeTenABP中适用于Android(请参见如何使用…)。
ThreeTen-Extra项目通过添加其他类来扩展java.time。该项目是java.time可能未来添加的可靠依据。您可能会发现一些有用的类,例如Interval
、YearWeek
、YearQuarter
等。
1317816735000L
是2011-10-06 03:35:05 GMT
的错误时间戳。否则,您的方法是正确的。 - augurarjava.util.Date
、java.util.Calendar
和java.text.SimpleDateFormat
这样的老旧日期时间类现在已经是遗留系统,被 Java 8 及更高版本内置的 java.time 类所取代。请参见 Oracle 的教程。 - Basil Bourque