Oracle中YY和RR表示年份的区别

Posted bisal的个人杂货铺

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Oracle中YY和RR表示年份的区别相关的知识,希望对你有一定的参考价值。

《》中曾提到,DATE类型的日期表示,一种是用RR表示年份后两位,一种是用YY表示年份后两位,两者有些区别,稍不注意,很可能就是“彩蛋”,出现类似Antd的事件。


如果在TO_DATE函数中使用YY格式符,那么只会返回和当前年相同的前两位年份数字。如果使用RR格式符,那就可以根据指定的两位年份数字,还有当前年的后两位数字,返回不同的值,听起来像绕口令,我们对RR和YY,分别进行介绍。


首先,看DD-MON-RR,以下是官方文档的描述:

The RR Datetime Format Element
    The RR datetime format element is similar to the YY datetime format element, but it provides additional flexibility for storing date values in other centuries. The RR datetime format element lets you store 20th century dates in the 21st century by specifying only the last two digits of the year. 


RR日期格式符和YY日期格式符很相似,但是对于不同世纪,他提供了存储日期值额外的扩展性。RR日期格式符可以让你在21世纪通过仅仅指定年份的后两位来存储20世纪的日期,

If you use the TO_DATE function with the YY datetime format element, then the year returned always has the same first 2 digits as the current year. If you use the RR datetime format element instead, then the century of the return value varies according to the specified two-digit year and the last two digits of the current year. 


RR规则,

That is:
    If the specified two-digit year is 00 to 49, then
        If the last two digits of the current year are 00 to 49, then the returned year has the same first two digits as the current year.
        If the last two digits of the current year are 50 to 99, then the first 2 digits of the returned year are 1 greater than the first 2 digits of the current year.
    If the specified two-digit year is 50 to 99, then
        If the last two digits of the current year are 00 to 49, then the first 2 digits of the returned year are 1 less than the first 2 digits of the current year.
        If the last two digits of the current year are 50 to 99, then the returned year has the same first two digits as the current year


翻译下,
1. 如果指定的两位年份数字是00-49,
(1) 如果当前年的后两位数字是00-49,则返回的年份和当前年的前两位数字相同。
(2) 如果当前年的后两位数字是50-99,则返回的年份前两位数字会比当前年的前两位数字大1。

2. 如果指定的两位年份数字是50-99,
(1) 如果当前年份的后两位数字是00-49,则返回的年份前两位数字会比当前年的前两位数字小1。
(2) 如果当前年的后两位数字是50-99,则返回的年份和当前年的前两位数字相同。


举个RR的例子,假设以下查询发生在1950-1999之间:

假设以下查询发生在2000-2049之间:

不管是2000年之前还是之后执行SQL,查询都会返回相同的值。使用RR日期格式符写的SQL,可以根据不同的年份前两位来返回相同的值。


接下来看看YY,提供的两位年份数字,此时对于世纪的判断就会和当前数据库服务器设置的世纪相同,假设现在是2015年,

无法使用YY,表示1950年。


不要以为这两个日期格式,对于应用,没什么影响,碰见过这种坑。有个应用,连接11g的库,逻辑大致是先根据日期和其他条件删除表中对应的历史记录(此处日期条件判断未使用to_date(),其中日期和另外一些条件是个复合主键),然后再插入一条新记录(此处日期字段使用to_date(XX, ‘DDMONYY’))。在测试的时候,测试人员发现一个问题,先手工插入了一条2050年的记录,然后运行应用,发现报主键冲突,再追查是因为原先的记录并未删除,导致新插入的记录主键冲突,看起来很诡异的问题,为何没有删除旧的记录?

原因就在于删除的检索条件中日期使用的是DDMONYY日期格式符,但插入的时候没有用任何日期格式符,此时就会使用数据库的默认日期格式,9i之后,NLS_DATE_FORMAT的默认值就是DD-MON-RR。


描述下整个操作,
1. 测试人员手工插入一条2050年的记录

(2015年,使用TO_DATE(XX, 'DDMONYY'))。
2. 应用首先执行删除操作,此时日期条件没用to_date(),直接用

了’01JAN50’,默认使用的则是DDMONRR格式符,当前是2015年,因此实际删除的条件是1950年的记录。但是,当前表中没有1950年的记录,因此删除记录条数是0。
3. 应用执行插入操作,此时使用的日期条件是’01JAN50’,当前是

2015年,因此实际要插入的是2050年的记录。但由于表中已经存在一条2050年的记录,因此会报主键冲突的错误。

因此,针对日期,最直接的方式就是使用YYYY或RRRR全年份的表示方式,这样不会有误会,如果使用YY或RR两位表示年份,那就要清楚这两者的区别,以及自己的需求,毕竟Oracle也要根据规则来判断两位年份是哪个世纪的,因此需要选择适合的方式,而且当一次交易中有多次增删改日期条件的逻辑,那么前后使用YY或RR要一致,否则就会因前后条件不一致,导致不同的结果,一个小小的日期格式,包含了不同的理解,显现出了Oracle系统设计的精妙,也对使用者提出来一定的要求,只有了解了原理,才能更好地使用。

以上是关于Oracle中YY和RR表示年份的区别的主要内容,如果未能解决你的问题,请参考以下文章

float和int有啥区别?

Oracle中select 1和select *的区别

日期和时间类函数

Oracle中select 1和select *的区别

JS中Date对象getYear()方法和getFullYear()方法区别

oracle中constraint和constraints的区别