我的J2EE应用程序部署在集群中,服务器可以位于多个时区。例如,一个服务器在EST,另一个服务器在CST。
考虑这样一个场景:请求以EST发送到服务器,并将日期和时间存储在数据库中(没有时区)。还有另一个请求检索相同的日期。但该请求可能会发送到CST中的另一台服务器。
是否有办法确定哪个时区日期存储在数据库中?
PS:我正在使用Oracle/Java/Hibernate
No。如果存储的DATE
不带时区,则无法查询时区。
作为开发人员,您需要决定如何处理时区。请记住您有3个时区:
- 数据库服务器时区。
- Web应用服务器时区。
- Client Browser时区。
如果一个在洛杉矶的用户输入时间,一个在巴黎的用户应该看到什么?
如果悉尼的用户执行一个操作,那么多伦多的用户应该看到什么操作时间戳?
除非你能回答这些问题,即定义你的需求,否则解决方案/实现是不可能编码/验证的。
正如评论中提到的,基本上有两种处理时区的方法:
- 将所有日期存储在固定时区,例如UTC,并在需要时进行转换,这几乎无处不在。
- 使用时区存储日期,并根据需要转换或显示时区。用户可能更喜欢转换,但这是你做出的设计决定。
当你使用数据类型DATE
或TIMESTAMP
时,你没有任何关于时区的信息-除非你的应用程序确保在插入或更新数据时总是一个特定的时区(例如UTC)。
Andreas语句不完全正确,在Oracle数据库中有三个时区:
-
数据库时区
你可以用
DBTIMEZONE
询问它。它只与TIMESTAMP WITH LOCAL TIME ZONE
数据类型列相关,并定义了存储格式。因此,如果数据库包含一个具有TIMESTAMP WITH LOCAL TIME ZONE
列的表,并且该列包含数据,则不能更改数据库上的DBTIMEZONE
。注意,这是不是SYSDATE
和SYSTIMESTAMP
的时区 -
数据库服务器操作系统时区
该时区与
SYSDATE
和SYSTIMESTAMP
的结果有关。 -
会话的时区
你可以用
SESSIONTIMEZONE
询问它。它可能由您的Web应用程序服务器或客户端浏览器时区决定。(我不是web技术专家)如果是胖客户端,可以在注册表或环境变量ORA_SDTZ
中设置。我不知道哪一个有优先级,当它们中的任何一个都没有定义时,您得到的值是哪个,它也可能因数据库提供程序和驱动程序而异。SESSIONTIMEZONE可以随时由用户通过ALTER SESSION SET TIME_ZONE=...
修改
日期类型TIMESTAMP WITH TIME ZONE
使用时区信息存储时间。您可以根据自己的需求,将它们转换为客户端本地时区,或者按照插入的方式填充或其他方式填充。您可以使用EXTRACT函数或转换为字符串(例如TO_CHAR(TS_VALUE, TZH:TZM)
或TO_CHAR(TS_VALUE, TZR)
)获得时区值。
日期类型TIMESTAMP WITH LOCAL TIME ZONE
还存储带有时区信息的时间。但是,它总是显示客户端的当前会话时区的时间,您不能将其转换为任何其他时区(除非事先执行CAST)。因此,当您尝试使用TIMESTAMP WITH LOCAL TIME ZONE
值执行TO_CHAR(TS_VALUE, 'hh24:mi:ss TZH:TZM')
时,您会得到一个错误!