tl;博士
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,因为输入缺少任何关于从UTC 偏移或时区的信息。 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 的偏移量加上一组用于处理异常情况的规则,例如夏令时 (DST)。所以我们可以将ZoneId 指定为ZonedDateTime 而不仅仅是偏移量。
指定proper time zone name。切勿使用 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 项目现在位于maintenance mode,建议迁移到 java.time。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。
大部分 java.time 功能在ThreeTen-Backport 中向后移植到Java 6 和7,并进一步适应ThreeTenABP 中的Android(参见How to use…)。
ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如Interval、YearWeek、YearQuarter 等等。