我有一个数据类型为TIMESTAMP
的字段(DD-MON-RR HH.MI.SSXFF AM
是格式)。当我在SQL开发人员中运行select语句时,此字段显示'04-NOV-08 12.00.00.000000000 AM'
作为结果,我认为08
是2008年,但是当我在我的java代码中调试时,此字段显示值'Sun Nov 04 00:00:00 ICT 8
'这意味着年份是8.你能告诉我哪个是正确值吗?
答案 0 :(得分:1)
您的默认NLS_TIMESTAMP_FORMAT(您可以更改as shown here,虽然您不应该真正依赖它)会为您提供两位数的年份代表。
出于显示目的,YY和RR date format models之间没有区别。您的查询显示年份为08
,但这可能代表任何世纪的第8年。
正如@DanBracuk建议你可以通过指定四位数年份格式掩码来查看全年,to_char(value, 'YYYY-MM-DD')
;那给了你0008-11-04
。因此,存储在时间戳中的值实际上是在第8年,而不是2008年,Java正在向您显示正确的值。 (如果您将数据作为日期时间而不是字符串传递,那么您会期望;但是您没有表明这一点。)
由于您可能实际上并不想在表格中使用第8年的数据,因此您会遇到数据问题。您可能能够通过简单地为每个值添加2000年来纠正您的数据,但这假设它们都显示从第一个世纪开始的一年,并且其余日期是正确的。
你还需要弄清楚数据是如何到达那里的,以及它是否仍在用错误的世纪创建。最简单的解释可能是从具有四位数年度NLS设置的会话插入期间提供的两位数年份。这正是您不应该依赖NLS_DATE_FORMAT,NLS_TIMESTAMP_FORMAT等的原因,因为编写代码的人通常无法控制运行它的人的会话。
您可以通过此演示了解2位数年份和4位数字掩码会发生什么。这将插入使用to_date
和to_timestamp
以及RR,RRRR,YY和YYYY格式掩码转换的相同字符串值的数据。
create table t42 (id number, ts timestamp);
insert into t42 (id, ts) values (1, to_date('04-NOV-08', 'DD-MON-RR'));
insert into t42 (id, ts) values (2, to_timestamp('04-NOV-08', 'DD-MON-RR'));
insert into t42 (id, ts) values (3, to_date('04-NOV-08', 'DD-MON-RRRR'));
insert into t42 (id, ts) values (4, to_timestamp('04-NOV-08', 'DD-MON-RRRR'));
insert into t42 (id, ts) values (5, to_date('04-NOV-08', 'DD-MON-YY'));
insert into t42 (id, ts) values (6, to_timestamp('04-NOV-08', 'DD-MON-YY'));
insert into t42 (id, ts) values (7, to_date('04-NOV-08', 'DD-MON-YYYY'));
insert into t42 (id, ts) values (8, to_timestamp('04-NOV-08', 'DD-MON-YYYY'));
select id, ts, to_char(ts, 'YYYY-MM-DD') as full_year from t42;
ID TS FULL_YEAR
---------- ---------------------------- ----------
1 04-NOV-08 00.00.00.000000000 2008-11-04
2 04-NOV-08 00.00.00.000000000 2008-11-04
3 04-NOV-08 00.00.00.000000000 2008-11-04
4 04-NOV-08 00.00.00.000000000 2008-11-04
5 04-NOV-08 00.00.00.000000000 2008-11-04
6 04-NOV-08 00.00.00.000000000 2008-11-04
7 04-NOV-08 00.00.00.000000000 0008-11-04
8 04-NOV-08 00.00.00.000000000 0008-11-04
使用我的默认时间戳模型的字符串表示显示所有值都相同,所有年份都显示为08
,如您所见。但是,使用YYYY格式掩码插入的值 - 正确地 - 被解释为0008而不是2008。
您还可以看到完全依赖于NLS设置的内容:
alter session set nls_timestamp_format = 'DD-MON-YY HH24:MI:SS.FF3';
insert into t42 (id, ts) values (9, '04-NOV-08');
alter session set nls_timestamp_format = 'DD-MON-YYYY HH24:MI:SS.FF3';
insert into t42 (id, ts) values (10, '04-NOV-08');
select id, ts, to_char(ts, 'YYYY-MM-DD') as full_year from t42 where id > 8;
ID TS FULL_YEAR
---------- ------------------------ ----------
9 04-NOV-2008 00:00:00.000 2008-11-04
10 04-NOV-0008 00:00:00.000 0008-11-04
运行了相同的代码,但最终得到了两个非常不同的值。
除了即席查询之外,或许,不要依赖NLS设置。您不应该对其他用户的会话设置做任何假设。如果您有要转换为日期或时间戳的字符串值,请始终显式调用to_date
或to_timestamp
并指定正确的格式掩码。如果可能,您应该在字符串值中使用4位数年份。您也可以使用日期/时间戳文字,具体取决于字符串的呈现方式。