【问题标题】:Dealing with Date Object and TimeZone in Java 7在 Java 7 中处理日期对象和时区
【发布时间】:2015-09-16 16:05:42
【问题描述】:

我正在开发一个库来将复杂数据存储在一个对象中。此对象中的字段之一是日期。当我使用 setter 方法设置日期时,假定日期对象位于 GMT 时区。在内部,Date 存储为一个 long 和从 epoch 开始的毫秒数。在我的get() 方法中,我正在执行以下操作:

return new Date(storedDateinMilliseconds);

问题是,如果有人在返回的对象上调用toString(),它会使用默认时区来返回日期。因此,返回的日期并不总是与 GMT 提供的日期匹配。有没有办法来解决这个问题?这样这个实现的用户在调用toString() 时总是会得到 GMT 日期? 我尝试了以下方法:

TimeZone.setDefault(TimeZone.getTimeZone("UTC"));

但这会修改​​使用它的应用程序的默认时区。

【问题讨论】:

  • 不要打电话给toString()。使用SimpleDateFormat 对其进行适当的格式化。
  • @SotiriosDelimanolis 我认为他的问题是“如果有人在返回的对象上调用 toString()”,而不是他正在调用 toString()。
  • @chrisl08 客户可能会做很多错误的事情。您,设计者,决定返回一个Date 对象。他们用它做什么取决于他们。
  • 如果您绝对希望日期与时区相结合,请不要使用日期。因为日期没有时区。使用公历。或者更好的是,joda-time DateTime。但你不应该打扰:如果客户不明白 Date 是什么,而且它没有时区,那是客户的问题,而不是你的问题。
  • 感谢所有 cmets。我了解 java.sql.Date 或 java.util.Date 有问题。但是我无法控制返回 Date 对象后用户会做什么。我想了解如何设定期望值。

标签: java date timezone


【解决方案1】:

正如 Sotirios Delimanolis 的评论所说,您将 java.util.Date 对象提供给调用程序员。她用它做什么取决于她。她有责任了解该对象带来的所有愚蠢问题,包括其 toString 方法,该方法应用 JVM 的当前默认时区来生成其日期时间值的字符串表示形式。

如果你想返回一个指定时区的日期时间值,那么返回一个不同的对象。

替代日期时间对象

您至少有三种方法可以返回 java.util.Date 对象。

java.time

在 Java 8 及更高版本中,显而易见的选择是使用新的java.time framework (Tutorial)。给调用程序员一个ZonedDateTime 对象,它基本上是一个Instant 对象加上一个ZoneId 对象。

提示:指定时区时,请使用proper time zone name。切勿使用 3-4 个字母的代码,例如 ESTIST

乔达时间

Joda-Time 是 java.time 的灵感来源。这个第 3 方库非常出色,并且从流行使用中久经考验。它也支持多个版本的 Java 和 Android。

DateTime 类是时间线上的一个时刻加上一个时区,类似于 java.time 的 ZonedDateTime

ISO 8601

第三种选择是给调用程序员一个日期时间值的字符串表示。格式的明显选择是使用ISO 8601 标准定义的格式。这些格式是明智的、深思熟虑的、明确的。

2015-09-16T18:06:14Z

……或者……

2015-09-16T11:06:14-07:00

java.time 和 Joda-Time 在解析和生成字符串时默认使用这些格式。 java.time 明智地扩展了格式,将时区的正确名称附加在方括号中。

2015-09-16T11:06:14-07:00[美国/洛杉矶]

从不调整默认时区

您表示设置默认时区会影响您的整个应用。错误的。它会影响在该 JVM 中运行的所有线程中所有应用程序的所有代码。更糟糕的是,当其他代码正在运行时,它会在运行时立即执行此操作。

设置默认时区仅作为解决日期时间问题的所有其他方法都已用尽的最后手段。这是罕见的。通常的解决方案是:

  • 使用 java.time 或 Joda-Time。
  • 始终指定所需/预期的时区,而不是隐式依赖默认值。
  • 在您的大部分业务逻辑、数据存储和数据交换中使用UTC
  • 尽可能避免 java.util.Date/.Calendar 的混乱。

搜索 StackOverflow

所有这些主题都在 StackOverflow.com 上讨论过很多次。请搜索更多信息和示例。

【讨论】:

  • 我同意所有这些,除了第三个项目符号。 UTC 可能或可能不适用于业务逻辑。实际上,很多业务逻辑都关注没有时间或时区的本地日期,因此 UTC 仅在您谈论特定时间时才有意义。例如,我需要知道采购订单下周五到期。 UTC 对此无济于事。
  • @Basil :感谢您的详细回答。
  • @MattJohnson 同意,您的业务逻辑中有“本地”日期时间(无时区)或本地化日期时间(分配特定时区)的时间。所以我在我的措辞中添加了“大部分”。但我不同意你关于学位的看法。根据我使用商业应用程序的经验,大多数数据应该采用 UTC,转换为时区仅用于呈现给用户(或输出到报告)。对于周五到期的采购订单,我肯定会将其保留为 UTC。我会在法律适用的时区的中午(或午夜,无论如何)到达星期五,然后转换为 UTC 进行存储。
【解决方案2】:

AFAIK,你有两个选择:

选项 1。这听起来可能有点矫枉过正,但您可以为您的这个复杂类推出自己的 Date 对象,并覆盖 toString() 方法。也许像

public class GMTDate extends java.util.Date {

    @Override
    public String toString() {
        //return GMTDate
    }

}

选项 2:将日期保留为 java.util.Date,但不要为其公开公共 getter。而是公开一个以 GMT 格式返回您的日期的公共 getter,并且可能是一个返回您的日期的公共 getter(从纪元开始的毫秒数)

编辑: 第三个选项:AspectJ。您可以使用面向方面的编程来拦截对 toString() 方法的调用并返回 GMT 字符串日期 相关堆栈溢出问题:AspectJ: Intercept method execution/call and make it return

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-08
    • 1970-01-01
    • 1970-01-01
    • 2021-09-18
    • 1970-01-01
    • 1970-01-01
    • 2015-12-22
    相关资源
    最近更新 更多