tl;博士
ZonedDateTime zdtMontreal =
ZonedDateTime.now( ZoneId.of( "America/Montreal" ) );
ZonedDateTime zdtAuckland =
zdtMontreal.withZoneSameLocal( ZoneId.of( "Pacific/Auckland" ) );
不是同一时刻。zdtAuckland时刻发生在几个小时之前。
确定这确实是您的意图。我有一种下沉的感觉,你在做错事,对日期时间处理的工作方式感到困惑。日期时间工作令人困惑。请务必搜索和研究 Stack Overflow。
java.time
Joda-Time 项目现在位于 maintenance mode,建议迁移到 java.time。
Local… 类故意没有时区或offset-from-UTC 信息。
LocalDate ld = LocalDate.of( 2016 , Month.January , 23 ); // 2016-01-23
LocalTime lt = LocalTime.of( 12 , 34 , 56 ); // 12:34:56
这些值不代表时间线上的一个点。那会是新西兰奥克兰、法国巴黎或加利福尼亚蒙特利尔的中午时间吗?我们必须应用时区来确定实际时刻。我们应用ZoneId 来获得ZonedDateTime。
以continent/region 的格式指定proper time zone name,例如America/Montreal、Africa/Casablanca 或Pacific/Auckland。切勿使用 3-4 个字母的缩写,例如 EST 或 IST 或 CST,因为它们不是真正的时区,没有标准化,甚至不是唯一的 (!)。
ZoneId zMontreal = ZoneId.of( "America/Montreal" );
ZonedDateTime zdtMontreal = ZonedDateTime.of( ld , lt , zMontreal );
要查看以标准 ISO 8601 格式表示此值的字符串,请调用 toString。实际上,ZonedDateTime 类通过在方括号中巧妙地附加时区名称来扩展标准格式。
String outputMontreal = zdtMontreal.toString();
2016-01-23T12:34:56-05:00[美国/蒙特利尔]
要在另一个时区获取相同的日期和时间,请重复该过程。
ZoneId zParis = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdtParis = ZonedDateTime.of( ld , lt , zParis );
ZoneId zAuckland = ZoneId.of( "Pacific/Auckland" );
ZonedDateTime zdtAuckland = ZonedDateTime.of( ld , lt , zAuckland );
但要知道,您正在经历一个不同的时刻。奥克兰的中午发生在巴黎中午前几个小时,蒙特利尔的中午甚至更晚,因为三个不同的时间点碰巧共享相同的wall-clock time。
2016-01-23T12:34:56-05:00[美国/蒙特利尔]
2016-01-23T12:34:56+01:00[欧洲/巴黎]
2016-01-23T12:34:56+13:00[太平洋/奥克兰]
当前时刻
要获取当前时刻,请致电Instant.now。 Instant 类代表UTC 中时间线上的时刻,分辨率为nanoseconds(最多九 (9) 位小数)。
Instant instance = Instance.now();
应用ZoneId 调整到时区。
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instance.atZone( z );
对其他所需时区重复该过程,类似于我们在上面所做的。
作为快捷方式,您可以直接获取ZonedDateTime。
ZonedDateTime zdtMontreal = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) );
作为另一个快捷方式,您可以应用不同的时区,同时保留相同的日期和时间(相同的挂钟时间)。致电ZonedDateTime::withZoneSameLocal。
ZonedDateTime zdtAuckland = zdtMontreal.withZoneSameLocal( ZoneId.of( "Pacific/Auckland" ) );
我再说一遍:这个结果是时间线上的不同点。 zdtAuckland 发生在 zdtMontreal 发生前几个小时。
要保持相同的时刻,请致电ZonedDateTime::withZoneSameInstant。
数据库
通常最好将您的日期时间值存储在UTC 的数据库中。已经在 Stack Overflow 上进行了广泛讨论。搜索更多信息。
关于java.time
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date、Calendar 和 SimpleDateFormat。
Joda-Time 项目现在位于 maintenance mode,建议迁移到 java.time。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。
从哪里获得 java.time 类?
ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如Interval、YearWeek、YearQuarter 和more。