我正在开发一个库,用于在对象中存储复杂数据。此对象中的一个字段是日期。当我使用setter方法设置日期时,假设日期对象在GMT时区。在内部,Date存储为从epoch起以毫秒为单位的长。在我的get()
方法中,我正在执行以下操作:
return new Date(storedDateinMilliseconds);
问题是,如果有人在返回的对象上调用toString()
,它会使用默认时区来返回日期。因此,返回的日期并不总是与GMT中提供的日期匹配。有办法解决这个问题吗?以便该实现的用户在调用toString()
时始终获得GMT日期?我尝试了以下方法:
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
但这会修改使用它的应用程序的默认时区。
正如Sotirios Delimanolis的评论所说,您正在向调用的程序员提供一个java.util.Date对象。她用它做什么取决于她。这取决于她理解该对象带来的所有愚蠢问题,包括它的toString
方法,该方法在生成其日期-时间值的字符串表示时应用JVM的当前默认时区。
如果要返回具有指定时区的日期时间值,请返回其他对象。
替代日期时间对象
除了返回java.util.Date对象,您至少有三种选择。
java.time
在Java8及更高版本中,显而易见的选择是使用新的Java.time框架(教程(。给调用程序员一个ZonedDateTime
对象,它基本上是Instant
对象加上ZoneId
对象。
提示:指定时区时,请使用正确的时区名称。切勿使用像EST
或IST
这样的3-4个字母的代码。
Joda时间
Joda Time是java.Time的灵感来源。这个第三方库非常棒,而且在流行使用中已经过时了。它还支持Java和Android的多个版本。
DateTime
类是时间线上的一个时刻加上一个时区,类似于java.time的ZonedDateTime
。
ISO 8601
第三种选择是给调用程序员一个日期-时间值的字符串表示。格式的明显选择是使用ISO 8601标准定义的格式。这些格式是合理的、经过深思熟虑的、明确的。
2015-09-16T18:06:14Z
…或…
2015-09-16 t11:06:14-07:00
在解析和生成字符串时,java.time和JodaTime默认都使用这些格式。java.time明智地扩展了这些格式,将时区的正确名称附加在方括号中。
2015-09-16T11:06:14-07:00〔美国/洛杉矶〕
从不调整默认时区
您表示,设置默认时区会影响您的整个应用程序。错误的它会影响JVM中运行的所有线程中所有应用程序的所有代码。更糟糕的是,当其他代码正在运行时,它会在运行时立即执行此操作。
只有当解决日期时间问题的所有其他方法都已用尽时,才将默认时区设置为最后手段。这是罕见的。通常的解决方案是:
- 使用java.time或Joda time
- 始终指定所需/预期的时区,而不是隐含地依赖默认时区
- 在您的大部分业务逻辑、数据存储和数据交换中使用UTC
- 尽可能避免java.util.Date/.Calendar的混乱
搜索堆栈溢出
所有这些主题都在StackOverflow.com上进行了多次讨论。请搜索更多信息和示例。
AFAIK,您有两个选项:
选项1。这听起来可能有些过头了,但您可以为您的这个复杂类推出自己的Date对象,并覆盖toString((方法。也许像
public class GMTDate extends java.util.Date {
@Override
public String toString() {
//return GMTDate
}
}
选项2:将日期保持为java.util.date,但不要为其公开公共getter。相反,公开一个以GMT格式返回日期的公共getter,或者一个以长(从epoch开始的毫秒数(返回日期的公用getter
编辑:还有第三个选项:AspectJ。您可以使用面向方面的编程来拦截对toString((方法的调用,并返回GMT字符串日期相关堆栈溢出问题:AspectJ:拦截方法执行/调用并使其返回