在 Java 7 中处理日期对象和时区

Dealing with Date Object and TimeZone in Java 7

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

return new Date(storedDateinMilliseconds);

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

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

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

据我所知,你有 2 个选择:

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

public class GMTDate extends java.util.Date {

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

}

选项 2:将日期保留为 java.util.Date,但不要为其公开 public getter。相反,公开 public getter return 是 GMT 格式的日期,也许 public getter return 是你的日期long(从纪元开始的毫秒数)

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

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

如果您想要 return 具有指定时区的日期时间值,则 return 一个不同的对象。

替代日期时间对象

您至少有三个替代方案来 returning java.util.Date 对象。

java.time

在 Java 8 及更高版本中,显而易见的选择是使用新的 java.time framework (Tutorial). Give the calling programmer a ZonedDateTime object which is basically a Instant object plus a ZoneId 对象。

提示:指定时区时,请使用 proper time zone name。切勿使用 ESTIST.

等 3-4 个字母的代码

乔达时间

Joda-Time 是 java.time 的灵​​感来源。这个第 3 方库非常好,并且因广泛使用而陈旧。它也支持 Java 和 Android 的多个版本。

DateTime class是时间轴上的一个时刻加上一个时区,类似于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[America/Los_Angeles]

从不调整默认时区

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

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

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

搜索 Whosebug

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