Joda:将系统日期和时间转换为另一个区域中的日期/时间

时间:2017-08-22 17:15:27

标签: java datetime timezone jodatime datetime-format

我在SO阅读了很多帖子,并测试了大部分内容。他们都没有为我工作。这是我的代码:

DateTimeZone fromTimeZone = DateTimeZone.forID("America/New_York");
DateTimeZone toTimeZone = DateTimeZone.forID("US/Central");  
Date now = new Date();        
DateTime dateTime = new DateTime(now, fromTimeZone); 
DateTime newDateTime = dateTime.withZone(toTimeZone);
System.out.println(dateTime.toDate() + "--" + newDateTime.toDate());

这是我印刷的内容:

  

Tue Aug 22 13:08:13 EDT 2017 - Tue Aug 22 13:08:13 EDT 2017

我希望为第二个时区显示"Tue Aug 22 12:08:13 CDT 2017"

1 个答案:

答案 0 :(得分:1)

java.util.Date doesn't have timezone information。 Joda的DateTime有,但它包含在Chronologytranslate this instant to "human readable" date/time fields中。

但最后,这两个对象只是represent points (instants) in the time-line

只需检查dateTime.getMillis()newDateTime.getMillis()dateTime.toDate().getTime()newDateTime.toDate().getTime()的值。它们都完全相同,此值表示自纪元(1970-01-01T00:00Z)以来的毫秒数。

传递给DateTime对象的时区只会影响toString()的输出(当此毫秒值被“转换”为本地日期和时间时),但它不会更改毫秒值本身。所以如果你这样做:

DateTime dateTime = new DateTime(now, fromTimeZone);
System.out.println(dateTime);

它将打印相当于毫秒值的日期和时间,但转换为fromTimeZone(America / New_York):

  

2017-08-22T13:33:08.345-04:00

withZone方法只设置为不同的时区,但keeps the same milliseconds value

DateTime newDateTime = dateTime.withZone(toTimeZone);
System.out.println(newDateTime);

上面的代码保留了瞬间(毫秒值),但在toTimeZone(美国/中部)中打印了等效的日期和时间:

  

2017-08-22T12:33:08.345-05:00

.toDate()方法返回java.util.Date,它只包含相同的毫秒值,没有时区信息。然后,System.out.println隐含调用Date::toString() methodconverts the milliseconds value to the JVM's default timezone。在这种情况下,两者都将是:

  

Tue Aug 22 13:33:08 EDT 2017

因为两个日期代表同一时刻(与纪元相同的毫秒数)。

如果您希望获得包含特定格式的日期的String,可以使用org.joda.time.format.DateTimeFormatter

DateTimeFormatter fmt = DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss z yyyy").withLocale(Locale.ENGLISH);
System.out.println(fmt.print(new DateTime(DateTimeZone.forID("US/Central"))));

没有必要转换日期对象,因为实际上没有真正发生转换:上面的所有方法都不会改变毫秒值。

另请注意,我使用了java.util.Locale来确保一周中的月份和星期几是英文的。如果您没有指定语言环境,则将使用JVM默认值,并且不保证始终为英语(即使在运行时也可以更改它,因此最好始终指定它)。

然后我获取当前日期并设置打印时使用的时区。请注意,您可以直接获得DateTime,无需创建java.util.Date

输出将是:

  

Tue Aug 22 12:33:08 CDT 2017

要获得您想要的完全相同的输出(包含两个日期),您可以执行以下操作:

DateTimeFormatter fmt = DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss z yyyy").withLocale(Locale.ENGLISH);
DateTime nowNy = new DateTime(DateTimeZone.forID("America/New_York"));
DateTime nowCentral = nowNy.withZone(DateTimeZone.forID("US/Central"));
System.out.println(fmt.print(nowNy) + "--" + fmt.print(nowCentral));

输出将是:

  

Tue Aug 22 13:33:08 EDT 2017 - Tue Aug 22 12:33:08 CDT 2017

Java新日期/时间API

Joda-Time处于维护模式并被新API取代,因此我不建议使用它来启动新项目。即使在joda's website中它也说:“请注意,Joda-Time被认为是一个很大程度上”完成“的项目。没有计划大的增强。如果使用Java SE 8,请迁移到java.time(JSR) -310)。“ (如果你不想或不能从Joda迁移到另一个API,你可以考虑这个部分)

如果您使用的是 Java 8 ,请考虑使用new java.time API。它更容易,less bugged and less error-prone than the old APIs

如果您使用的是 Java< = 7 ,则可以使用ThreeTen Backport,这是Java 8新日期/时间类的绝佳后端。对于 Android ,有ThreeTenABP(更多关于如何使用它here)。

以下代码适用于两者。 唯一的区别是包名称(在Java 8中为java.time,在ThreeTen Backport(或Android的ThreeTenABP)中为org.threeten.bp),但类和方法名称是相同的

相关课程为DateTimeFormatter(以特定格式将日期格式化为String),ZonedDateTime(代表特定时区的日期和时间)和{ {1}}(代表时区):

ZoneId

输出与上述相同。