我们正在运行基于 JAVA 和 J2EE 产品的应用程序,并将 postgres 作为数据库服务器,在设计架构师犯了一个错误并将所有日期和时间列存储在 IST 的本地时区中。现在应用程序的用户要求在本地区域显示所有时间。来自伦敦的用户希望应用程序以格林威治标准时间显示所有日期和时间。
是否有任何解决方案或方法最适合此处且更改最少。此外,我认为使用 Java 时间或 JODA 时间 在这里也无济于事,因为我需要做更多的工作。
1) 正在考虑将所有现有日期和时间转换为 UTC(简单、可行且更易于实现)
2) 我将如何处理显示部分,因为在搜索屏幕中,我们允许用户不仅选择日期而且选择时间来查找所有匹配的交易,这里的时间假设是用户的本地时间。
最佳答案
背景
在 Postgres 中,TIMESTAMP
和 TIMESTAMP WITH TIMEZONE
的存储方式相同 - 自 Postgres 纪元 (2000-01-01) 以来的秒数。主要区别在于 Postgres 在保存诸如 2004-10-19 10:23:54+02
之类的时间戳值时执行的操作:
- 没有 TZ,
+02
就被剥离了 - 使用 TZ 执行
-02
校正以使其成为 UTC
现在有趣的是 JDBC 驱动程序何时加载值:
- 在没有 TZ 的情况下,存储的值由用户的(JVM/OS)TZ 移动
- 对于 TZ,该值被认为是 UTC
在这两种情况下,您最终都会得到带有用户默认 TZ 的 java.sql.Timestamp
对象。
时区
没有 TZ 的时间戳非常有限。如果您有两个系统连接到您的数据库,都具有不同的 TZ,它们将以不同的方式解释时间戳。
您可以 tell JDBC通过 ResultSet#getTimestamp(String, Calendar)
读取时间戳时应该使用哪种 TZ .摘自 JavaDoc:
This method uses the given calendar to construct an appropriate millisecond value for the timestamp if the underlying database does not store timezone information.
一旦有了时间戳(在没有 TZ 的情况下),您现在就可以可靠地使用 Joda-Time。 Joda-Time 提供各种内置格式化程序,您也可以定义自己的格式化程序。但对于写日志或报告,最好的选择可能是 ISO 8601 格式。该格式恰好是 Joda-Time 和 java.time 使用的默认格式。
示例代码
java.sql.Timestamp timestamp = resultSet.getTimestamp(i);
DateTime dateTimeUtc = new DateTime( DateTimeZone.UTC ); // Defaults to now, this moment.
// Convert as needed for presentation to user in local time zone.
DateTimeZone timeZone = DateTimeZone.forID("Europe/Paris");
DateTime dateTimeZoned = dateTimeUtc.toDateTime( timeZone );
关于java - 时区中性应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35745847/