我在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"
。
答案 0 :(得分:1)
java.util.Date
doesn't have timezone information。 Joda的DateTime
有,但它包含在Chronology
到translate 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()
method和converts 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
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
输出与上述相同。