使用 JAVA 在数据库中存储 date/time 信息?
Using JAVA to store date/time info in the DB?
什么是最好的 way/approach 来存储 date/time 信息(以及一般的时间戳)以便可以在不同时区显示的信息?
我的想法是让数据库以指定格式(如 GMT 或 UTC)保存时间。当从数据库读取时,将收集到的任何 date/time/时间戳数据转换为该区域的本地时间戳。
将数据插入数据库时。以下将适用。
- Collect the time from the User Interface as a string
- convert the time to the local date/time representation (where the timezone is included)
- convert the local date/time to GMT (or UTC)
- 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 ZONE
。
TIMESTAMP 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 ZONE
是 always 显示在当前用户会话时区和 TZR
(即时区区域名称)没有任何意义。好吧,您可以将其视为 Oracle 错误,但在某种程度上它是有道理的。
什么是最好的 way/approach 来存储 date/time 信息(以及一般的时间戳)以便可以在不同时区显示的信息?
我的想法是让数据库以指定格式(如 GMT 或 UTC)保存时间。当从数据库读取时,将收集到的任何 date/time/时间戳数据转换为该区域的本地时间戳。
将数据插入数据库时。以下将适用。
- Collect the time from the User Interface as a string
- convert the time to the local date/time representation (where the timezone is included)
- convert the local date/time to GMT (or UTC)
- 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 ZONE
。
TIMESTAMP 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 ZONE
是 always 显示在当前用户会话时区和 TZR
(即时区区域名称)没有任何意义。好吧,您可以将其视为 Oracle 错误,但在某种程度上它是有道理的。