更改Date对象的时区而不更改日期

use*_*226 2 jodatime java-8

我可以在不更改日期的情况下更改Java代码中Date对象的时区吗?当我写作时, Date date = new Date(longValue); 我会在当地时区得到这个日期.我希望得到这个日期,但我的时区应该是我的用户ID(例如"America/Chicago")在DB(非本地)中存在的时区.

在此先感谢您的帮助.

Bas*_*que 10

TL;博士

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

ZonedDateTime zdtAuckland = 
    zdtMontreal.withZoneSameLocal( ZoneId.of( "Pacific/Auckland" ) );  
Run Code Online (Sandbox Code Playgroud)

一样的时刻.这个zdtAuckland时刻发生在几个小时之前.

确定这是你真正的意图.我有一种沉闷的感觉,你做错了事,对日期时间处理的工作方式感到困惑.日期-时间的工作令人困惑的.一定要搜索和研究Stack Overflow.

java.time

现在处于维护模式Joda-Time项目建议迁移到java.time.

这些Local…类故意没有时区或从UTC信息偏移.

LocalDate ld = LocalDate.of( 2016 , Month.January , 23 ); // 2016-01-23
LocalTime lt = LocalTime.of( 12 , 34 , 56 );  // 12:34:56
Run Code Online (Sandbox Code Playgroud)

这些值都没有还表示时间轴上的一个点.那是奥克兰新西兰,巴黎FR或蒙特利尔加州的中午时间吗?我们必须应用时区来确定实际时刻.我们申请一个ZoneId来获得一个ZonedDateTime.

指定适当的时区名称,格式continent/region,如America/Montreal,Africa/CasablancaPacific/Auckland.切勿使用3-4个字母的缩写,如ESTISTCST因为他们没有真正的时区,不规范,甚至不是唯一的(!).

ZoneId zMontreal = ZoneId.of( "America/Montreal" );
ZonedDateTime zdtMontreal = ZonedDateTime.of( ld , lt , zMontreal );
Run Code Online (Sandbox Code Playgroud)

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

String outputMontreal = zdtMontreal.toString();
Run Code Online (Sandbox Code Playgroud)

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 );
Run Code Online (Sandbox Code Playgroud)

但要知道你正在得到一个不同的时刻.奥克兰的中午发生在巴黎正午前几个小时,蒙特利尔的中午甚至更晚,因为三个不同的时间恰好相同的挂钟时间.

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,分辨率为纳秒(最多9个(9)小数的位数).

Instant instance = Instance.now();
Run Code Online (Sandbox Code Playgroud)

应用a ZoneId调整到时区.

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instance.atZone( z );
Run Code Online (Sandbox Code Playgroud)

对其他所需时区重复此过程,类似于我们上面所做的.

作为捷径,您可以ZonedDateTime直接获得.

ZonedDateTime zdtMontreal = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) );
Run Code Online (Sandbox Code Playgroud)

作为另一种快捷方式,您可以应用不同的时区,同时保留相同的日期和相同的时间(相同的挂钟时间).打电话ZonedDateTime::withZoneSameLocal.

ZonedDateTime zdtAuckland = zdtMontreal.withZoneSameLocal( ZoneId.of( "Pacific/Auckland" ) );
Run Code Online (Sandbox Code Playgroud)

我再说一遍:这个结果是时间线上的不同点.在zdtAuckland正在发生几个小时前zdtMontreal发生.

保持同一时刻,而不是打电话ZonedDateTime::withZoneSameInstant.

数据库

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


关于java.time

java.time框架是建立在Java 8和更高版本.这些类取代麻烦的老传统日期时间类,如java.util.Date,Calendar,和SimpleDateFormat.

现在处于维护模式Joda-Time项目建议迁移到java.time.

要了解更多信息,请参阅Oracle教程.并搜索Stack Overflow以获取许多示例和解释.规范是JSR 310.

从哪里获取java.time类?

ThreeTen-额外项目与其他类扩展java.time.该项目是未来可能添加到java.time的试验场.您可以在此比如找到一些有用的类Interval,YearWeek,YearQuarter,和更多.