java - 如何将 DateTime 保存为包含时区偏移量的日期?

标签 java datetime datetimeoffset java-6 java.util.date

我有一些 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();

但是结果是这样的:

Thu May 31 22:00:00 UTC 2012

将日期时间结果保存为日期的最佳方法是包括时区偏移量,因此事务日期应为2012-06-01。我可以修改 GregorianCalendar,但这不是我喜欢的。这应该更容易,不是吗?

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

最佳答案

不幸的是,accepted answer是误导。事实上,

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

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

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

java.time

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

此外,下面引用的是 Home Page of Joda-Time 的通知:

Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.

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

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

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

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

如何以 UTC 格式获取日期时间:

有多种方法。最简单的方法是将其转换为 Instant。它代表时间轴上的一个瞬时点,采用 UTC。

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

或者,

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

如何从中获取 java.util.Date:

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

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

请注意,java.util.Date 对象不是像 modern date-time types 这样的真正的日期时间对象。 ;相反,它表示自称为“纪元”的标准基准时间以来的毫秒数,即 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

了解有关 java.time 的更多信息,modern date-time API * 来自 Trail: Date Time .


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

关于java - 如何将 DateTime 保存为包含时区偏移量的日期?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11192006/

相关文章:

sql - 使用 PostgreSQL 处理时间

Ruby - 如何将 Unix 时间戳(纪元)四舍五入到最近的月份

python - 如何更改python代码中pd.DateOffset中的参数?

java - Git/JGit 与 SVNKit 类似的 Java 访问代码(方法)

java - Eclipse 和 Gradle 类路径不同步 : cannot be resolved to a type

java - 如何解析XML文件?

sql - 显示外出状态的最新日期

iphone - Objective C/iPhone - Date Time Picker 如何格式化它的日期(例如 strip YYYY)以及如何检索这些格式?

datetime - os.time() 是否使用了 isdst 字段?

java - 对(可能的)Android 内存泄漏一无所知