Joda:将系统日期和时间转换为另一个区域中的 date/time
Joda: convert the system date and time to date/time in another zone
我在 SO 阅读了很多帖子并测试了其中的大部分。 None 为我工作。这是我的代码:
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"
第二时区。
A java.util.Date
doesn't have timezone information. Joda's DateTime
has, but it's wrapped into a Chronology
to 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()
的输出(当此毫秒值是 "translated" 到本地日期和时间时),但它不会更改毫秒值本身。所以如果你这样做:
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
(US/Central):
中打印了等效的日期和时间
2017-08-22T12:33:08.345-05:00
.toDate()
方法returns一个java.util.Date
,它只包含相同的毫秒值,没有时区信息。然后,System.out.println
隐式调用 Date::toString()
method, and this 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
Java新Date/TimeAPI
Joda-Time 处于维护模式并被新的 APIs 取代,所以我不建议用它开始一个新项目。即使在 joda's website 它说:"Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310)." (如果你不想或不能从 Joda 迁移到另一个 API, 你可以不考虑这个部分).
如果您正在使用 Java 8,请考虑使用 new java.time API. It's easier, less bugged and less error-prone than the old APIs.
如果您使用 Java <= 7,您可以使用 ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it ).
下面的代码适用于两者。
唯一的区别是包名称(在 Java 8 中是 java.time
,在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是 org.threeten.bp
),但是 类和方法名称相同。
相关的类是DateTimeFormatter
(将日期格式化为特定格式的String
),ZonedDateTime
(表示日期和时间特定时区)和 ZoneId
(代表时区):
// formatter - use English locale for month and day of week
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH);
// current date/time in New York timezone
ZonedDateTime nowNy = ZonedDateTime.now(ZoneId.of("America/New_York"));
// convert to another timezone (US/Central)
ZonedDateTime nowCentral = nowNy.withZoneSameInstant(ZoneId.of("US/Central"));
// format dates
System.out.println(fmt.format(nowNy) + "--" + fmt.format(nowCentral));
输出同上
我在 SO 阅读了很多帖子并测试了其中的大部分。 None 为我工作。这是我的代码:
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"
第二时区。
A java.util.Date
doesn't have timezone information. Joda's DateTime
has, but it's wrapped into a Chronology
to 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()
的输出(当此毫秒值是 "translated" 到本地日期和时间时),但它不会更改毫秒值本身。所以如果你这样做:
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
(US/Central):
2017-08-22T12:33:08.345-05:00
.toDate()
方法returns一个java.util.Date
,它只包含相同的毫秒值,没有时区信息。然后,System.out.println
隐式调用 Date::toString()
method, and this 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
Java新Date/TimeAPI
Joda-Time 处于维护模式并被新的 APIs 取代,所以我不建议用它开始一个新项目。即使在 joda's website 它说:"Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310)." (如果你不想或不能从 Joda 迁移到另一个 API, 你可以不考虑这个部分).
如果您正在使用 Java 8,请考虑使用 new java.time API. It's easier, less bugged and less error-prone than the old APIs.
如果您使用 Java <= 7,您可以使用 ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it
下面的代码适用于两者。
唯一的区别是包名称(在 Java 8 中是 java.time
,在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是 org.threeten.bp
),但是 类和方法名称相同。
相关的类是DateTimeFormatter
(将日期格式化为特定格式的String
),ZonedDateTime
(表示日期和时间特定时区)和 ZoneId
(代表时区):
// formatter - use English locale for month and day of week
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH);
// current date/time in New York timezone
ZonedDateTime nowNy = ZonedDateTime.now(ZoneId.of("America/New_York"));
// convert to another timezone (US/Central)
ZonedDateTime nowCentral = nowNy.withZoneSameInstant(ZoneId.of("US/Central"));
// format dates
System.out.println(fmt.format(nowNy) + "--" + fmt.format(nowCentral));
输出同上