2

我有一些 DateTime,包括 TimeZone Europe/Vienna (+0200)。它是通过这种方法获取的:

settlementService.getPendingPeriodStart()

并像这样查看 toString:

2012-06-01T00:00:00.000+02:00

现在我想将这个日期 2012-06-01 保存为 java.util.Date,所以我尝试了这样的事情:

transactionDate = settlementService.getPendingPeriodStart().withTime(0, 0, 0, 0).toDate();

但结果是这样的:

2012 年 5 月 31 日星期四 22:00:00 UTC

将 DateTime 结果保存为包含TimeZone 偏移量的 Date 的最佳方法是什么,因此 transactionDate 应该是2012-06-01。我可以修补 GregorianCalendar,但这不是我喜欢的。这应该更容易,不是吗?

顺便说一句(如果不清楚的话)。本地系统在 UTC 上运行。这就是为什么结果是Thu May 31 22:00:00 UTC 2012

4

3 回答 3

1

不幸的是,接受的答案具有误导性。事实上,

2012-06-01T00:00:00.000+02:00 = 2012-05-31T22:00:00Z

Z右侧是零时区偏移的时区指示符。它代表 Zulu 并指定Etc/UTC时区(时区偏移量为+00:00小时)。

2012-06-01T00:00:00.000+02:00as 2012-06-01,虽然只是一个函数调用,但对于任何依赖于时区的业务逻辑都是危险的,因为它可能在时区中具有不同的日期,具有不同的偏移值,例如如上所示。2012-06-01只是一个LocalDate应该用于跟踪诸如出生日期、婚礼日期等事件的文件。

java.time

旧的日期时间 API(java.util日期时间类型及其格式类型SimpleDateFormat等)已过时且容易出错。建议完全停止使用它并切换到java.time现代日期时间 API *

此外,下面引用的是Joda-Time 主页上的通知:

请注意,从 Java SE 8 开始,用户被要求迁移到 java.time (JSR-310) - JDK 的核心部分,它取代了这个项目。

使用java.time现代 API 的解决方案:

如何解析给定的日期时间字符串:

给定的日期时间字符串有一个时区偏移量,因此它应该被解析为OffsetDateTime. 由于现代日期时间 API 基于ISO 8601DateTimeFormatter ,并且只要日期时间字符串符合 ISO 8601 标准,就不需要显式使用对象。

OffsetDateTime odt = OffsetDateTime.parse("2012-06-01T00:00:00.000+02:00"); // 2012-06-01T00:00+02:00

如何在 UTC 中获取日期时间:

有多种方法。最简单的方法是将其转换为InstantUTC 时间轴上的瞬时点。

Instant instant = odt.toInstant(); // 2012-05-31T22:00:00Z

或者,

OffsetDateTime odtUtc = odt.withOffsetSameInstant(ZoneOffset.UTC); // 2012-05-31T22:00Z

如何java.util.Date摆脱它:

如果您需要java.util.Date来自 的实例的实例OffsetDateTime,您可以使用Date#from(Instant instant).

Date date = Date.from(instant); // Thu May 31 23:00:00 BST 2012 <--In my timezone

请注意,java.util.Date对象不是像现代日期时间类型那样的真实日期时间对象;相反,它表示自称为“纪元” January 1, 1970, 00:00:00 GMT(或 UTC)的标准基准时间以来的毫秒数。当您打印 的对象时java.util.Date,其toString方法会返回 JVM 时区中的日期时间,根据此毫秒值计算得出。如果您需要在不同的时区打印日期时间,则需要将时区设置为SimpleDateFormat并从中获取格式化的字符串,例如

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
System.out.println(sdf.format(date)); // 2012-05-31T22:00:00.000Z

如何从中获取日期部分:

正如我已经解释过的,任何依赖于时区的业务逻辑都是危险的。但是,这只是一个简单的函数调用问题。

LocalDate localDate = odt.toLocalDate(); // 2012-06-01

Trail: Date Time了解更多关于java.time现代日期时间 API *的信息。


* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,则可以使用ThreeTen-Backport,它将大部分java.time功能向后移植到 Java 6 和 7。如果您正在为 Android 项目和 Android API 工作level 仍然不符合 Java-8,请检查Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project

于 2021-05-21T14:32:21.480 回答
0

用户的日期和时区是两个不同的东西。一个是日期,另一个是偏好或表示参数。

不要试图将它们存储在同一个字段中。

考虑到甚至不可能将它们有效地存储在一起(不丢失精度),因为日期可以存储在 long 中,因为它被指定为 UTC 日期。

您可以将时区保存为偏移[hh]:[mm]量(由于非常小的情况,经常建议将分钟保留在此偏移量 ( ) 中)。

于 2012-06-25T15:25:03.833 回答
0

我想我找到了解决办法。(如果您知道更好的解决方案,请告诉我)

DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

DateTime dateTimeWithTimeZone = new DateTime(DateTimeZone.forID("Europe/Vienna")).withDate(2012, 06, 01).withTime(0, 0, 0, 0);      
Date dateWithTimeZoneIncluded = dateTimeWithTimeZone.toLocalDate().toDate();

System.out.println(dateFormat.format(dateWithTimeZoneIncluded));

结果如预期的那样是2012-06-01 。

于 2012-06-25T19:58:22.340 回答