在不更改日期的情况下更改 Date 对象的时区

Change timezone of Date object without changing date

我可以在 java 代码中更改 Date 对象的时区而不更改日期吗? 当我写 Date date = new Date(longValue); 我在当地时区得到这个日期。我想得到这个日期,但我的时区应该是我的用户 ID(例如 "America/Chicago")的数据库(不是本地)中的时区。

在此先感谢您的帮助。

您可能会发现 ZonedDateTime 很有帮助:

或者您可以创建另一个 Date 对象并手动对其应用一些偏移量。

如何使用 Java8 ZonedDateTime class:

的示例
Date date = new Date(longValue);
ZoneId = ZoneId.of("America/Chicago");
ZonedDateTime dt = ZonedDateTime.ofInstant(date.toInstant(), zoneId);

您已经用 Joda 标记了问题,但实际上 Java8 您不再需要它了。

tl;博士

ZonedDateTime zdtMontreal = 
    ZonedDateTime.now( ZoneId.of( "America/Montreal" ) );

ZonedDateTime zdtAuckland = 
    zdtMontreal.withZoneSameLocal( ZoneId.of( "Pacific/Auckland" ) );  

不是同一时刻。zdtAuckland时刻发生在几个小时前.

确定这确实是您的意图。我有一种你做错事的感觉,对日期时间处理的工作方式感到困惑。日期时间工作 令人困惑 。请务必搜索和研究 Stack Overflow。

java.time

Joda-Time project, now in maintenance mode,建议迁移到java.time。

Local… classes 故意没有时区或 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.

指定 proper time zone name in the format of continent/region, such as America/Montreal, Africa/CasablancaPacific/Auckland。切勿使用 ESTISTCST 等 3-4 个字母的缩写,因为它们 不是 真实时区,未标准化,也不是甚至是独一无二的(!)。

ZoneId zMontreal = ZoneId.of( "America/Montreal" );
ZonedDateTime zdtMontreal = ZonedDateTime.of( ld , lt , zMontreal );

要查看以标准 ISO 8601 格式表示此值的字符串,请调用 toString。实际上,ZonedDateTime class 通过在方括号中明智地附加时区名称来扩展标准格式。

String outputMontreal = zdtMontreal.toString();

2016-01-23T12:34:56-05:00[America/Montreal]

要在另一个时区获得相同的日期和相同的时间,请重复该过程。

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[America/Montreal]

2016-01-23T12:34:56+01:00[Europe/Paris]

2016-01-23T12:34:56+13:00[Pacific/Auckland]

当前时刻

要获取当前时刻,请调用 Instant.nowInstant class represents a moment on the timeline in UTC with a resolution of 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" ) );

我再说一遍:这个结果是时间线上的不同点。 zdtAucklandzdtMontreal 发生前几个小时发生。

要保持​​同一时刻,请调用 ZonedDateTime::withZoneSameInstant

数据库

通常最好将日期时间值存储在 UTC 中的数据库中。已经在 Stack Overflow 上进行了广泛讨论。搜索更多信息。


关于java.time

java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

Joda-Time project, now in maintenance mode,建议迁移到java.time。

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

从哪里获得java.time classes?

  • Java SE 8 and SE 9 及更高版本
    • 内置。
    • 标准 Java API 的一部分,带有捆绑实施。
    • Java 9 添加了一些小功能和修复。
  • Java SE 6 and SE 7
  • Android
    • ThreeTenABP项目专门为Android改编了ThreeTen-Backport(上面提到的)。
    • 参见

ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.