使用 JAVA 在数据库中存储 date/time 信息?

Using JAVA to store date/time info in the DB?

什么是最好的 way/approach 来存储 date/time 信息(以及一般的时间戳)以便可以在不同时区显示的信息?

我的想法是让数据库以指定格式(如 GMT 或 UTC)保存时间。当从数据库读取时,将收集到的任何 date/time/时间戳数据转换为该区域的本地时间戳。

将数据插入数据库时​​。以下将适用。

  1. Collect the time from the User Interface as a string
  2. convert the time to the local date/time representation (where the timezone is included)
  3. convert the local date/time to GMT (or UTC)
  4. Save to the DB in GMT / UTC format

我看过 Joda Time 包,也考虑过使用它。

人们解决这个问题的通常方法是什么?我希望这不是太含糊——我已经看到 Oracle DB 在这里保存 date/time 时区似乎是本地的。

例如:我得到以下信息:

SQL> SELECT EXTRACT(TIMEZONE_HOUR FROM SYSTIMESTAMP)||':'||
       EXTRACT(TIMEZONE_MINUTE FROM SYSTIMESTAMP)
FROM dual;  
Result  => -5:0

任何有关此问题的提示都将不胜感激。

TIA

更新

完成了以下操作:

SQL> ALTER DATABASE SET TIME_ZONE = 'UTC';

系统是"bounced"

SQL>  select dbtimezone from dual;
DBT
---
UTC

出于好奇,您如何向数据库表中插入数据,以便将时区考虑在内?对列使用 TIMESTAMP 类型时出现错误:

SQL> create table shot (t timestamp);
Table created.

SQL> insert into shot values( '26-FEB-09 11.36.25.390713 AM Pacific/Auckland');
insert into shot values( '26-FEB-09 11.36.25.390713 AM Pacific/Auckland')
                         *
ERROR at line 1:
ORA-01830: date format picture ends before converting entire input string

SQL>  insert into shot values( '26-FEB-09 11.36.25.390713 AM');
1 row created.

更新 在 java/jdbc/Oracle 中设置 "session timezone" 时,还将 link 添加到旧的 post。如果我理解正确,需要一个特定的 .jar 文件来确保 "session timezone" 与 "database timezone" 连接到数据库时与 运行 java 相同代码。

Setting session timezone with spring jdbc oracle

我建议使用数据类型 TIMESTAMP WITH LOCAL TIME ZONETIMESTAMP WITH LOCAL TIME ZONE 的所有值都在内部存储在 DBTIMEZONE 中,在您的情况下为 UTC(因此,一旦您插入了此数据类型的任何数据,就无法再更改 DBTIMEZONE)。当您 select 这样的列时,时间 总是 显示在当前用户会话时区 SESSIONTIMEZONE 中。因此,正确设置会话时区非常重要。

当你 运行 insert into shot values( '26-FEB-09 11.36.25.390713 AM Pacific/Auckland'); 时你会得到一个错误,因为 '26-FEB-09 11.36.25.390713 AM Pacific/Auckland' 是一个 字符串 - 不是时间戳!

您可以通过多种方式插入时间戳值,例如:

  • TIMESTAMP '2009-02-16 23:36:25.390713 Pacific/Auckland'
  • TO_TIMESTAMP_TZ('26-FEB-09 11.36.25.390713 AM Pacific/Auckland', 'DD-MON-RR HH:MI:SS.FF AM TZR')
  • FROM_TZ(TIMESTAMP '2000-03-28 18:00:00', 'Pacific/Auckland')
  • FROM_TZ(TIMESTAMP '2000-03-28 18:00:00', SESSIONTIMEZONE)(虽然您可以跳过它,因为 SESSIONTIMEZONE 是默认值)
  • FROM_TZ(TO_TIMESTAMP('26-FEB-09 11.36.25.390713 AM', 'DD-MON-RR HH:MI:SS.FF AM'), 'Pacific/Auckland')

注意这些表达式:

  • TIMESTAMP '1999-10-29 01:30:00' AT TIME ZONE 'Pacific/Auckland'
  • TO_TIMESTAMP('26-FEB-09 11.36.25.390713 AM', 'DD-MON-RR HH:MI:SS.FF AM') AT TIME ZONE 'Pacific/Auckland'

TIMESTAMP '1999-10-29 01:30:00' AT TIME ZONE 'Pacific/Auckland' 实际上意味着 (FROM_TZ(TIMESTAMP '1999-10-29 01:30:00', 'SESSIONTIMEZONE') AT TIME ZONE 'Pacific/Auckland',因此您可能会得到不想要的时间偏移。

请注意,当您使用 TIMESTAMP literal 时,格式固定为 YYYY-MM-DD HH24:MI:SS

如果您不指定任何时区信息(例如 TIMESTAMP '2009-02-16 11:36:25'),那么 Oracle 会将其视为当前用户会话时区 SESSIONTIMEZONE

  • SYSTIMESTAMP returns 数据库服务器操作系统时区的当前时间,而不是 DBTIMEZONE - 尽管它们通常设置为相同的值。

  • CURRENT_TIMESTAMP returns 当前用户会话时区的当前时间。数据类型为 TIMESTAMP WITH TIME ZONE

  • LOCALTIMESTAMP 也 returns 当前用户会话时区的当前时间,但数据类型是 TIMESTAMP,而不是 TIMESTAMP WITH TIME ZONE

另一个注意事项,当你有 TIMESTAMP WITH LOCAL TIME ZONE 时你不能像这样格式化输出 SELECT TO_CHAR(t, 'DD/MM/YYYY HH24:MI:SS ZTR') FROM shot 因为根据定义 TIMESTAMP WITH LOCAL TIME ZONEalways 显示在当前用户会话时区和 TZR(即时区区域名称)没有任何意义。好吧,您可以将其视为 Oracle 错误,但在某种程度上它是有道理的。