简体   繁体   English

Postgres to_date() function 返回错误的年份

[英]Postgres to_date() function returns wrong year

I used a query: select to_date(substring('0303653597' from 0 for 7),'DDMMYY')我使用了一个查询: select to_date(substring('0303653597' from 0 for 7),'DDMMYY')

Expected output: 1965-03-03预期 output:1965-03-03
Actual output: 2065-03-03实际 output:2065-03-03

When I give the string as 030370 or above it behaves correctly.当我将字符串设置为 030370 或更高时,它的行为正确。
Whats wrong with the predefined function?预定义的 function 有什么问题?
Can we use any other function to achieve the same?我们可以使用任何其他 function 来实现相同的目标吗?

According to the documentation :根据文档

In to_timestamp and to_date, if the year format specification is less than four digits, eg, YYY, and the supplied year is less than four digits, the year will be adjusted to be nearest to the year 2020, eg, 95 becomes 1995.在 to_timestamp 和 to_date 中,如果年份格式规范小于四位,例如 YYY,并且提供的年份小于四位,则年份将调整为最接近 2020 年,例如,95 变为 1995。

in your case 2065 is closer to 2020 than 1965 and thus it defaults to 2065.在您的情况下,2065 比 1965 更接近 2020,因此它默认为 2065。

I believe you won't get a better answer than the one from @whites11, but you can try to fix it by parsing the strings and adding the century yourself:我相信你不会得到比@whites11 更好的答案,但你可以尝试通过解析字符串并自己添加世纪来修复它:

WITH j (dt) AS (
  VALUES ('0303653597'),('0303701111'),('0510511111'),('0510051111')
)
SELECT
  CASE 
   WHEN substring(dt from 5 for 2)::int > '49' THEN
     to_date(substring(dt from 1 for 4) || '19' || substring(dt from 5 for 2), 'DDMMYYYY')
  ELSE 
     to_date(substring(dt from 1 for 4) || '20' || substring(dt from 5 for 2), 'DDMMYYYY')
  END
FROM j;

  to_date   
------------
 1965-03-03
 1970-03-03
 1951-10-05
 2005-10-05

Play with the case condition and see if it fits your needs.使用案例条件,看看它是否符合您的需求。

Demo: db<>fiddle演示: db<>fiddle

A solution for this problem heavy relies on the fact that you can guarantee your dates are starting after a certain year for which the two numbers representation doesn't overlap with the years passed in 2000 century so far.这个问题的解决方案依赖于这样一个事实,即您可以保证您的日期是在某个年份之后开始的,这两个数字表示与 2000 世纪迄今为止所过去的年份不重叠。

Eg if the earliest datapoint is in 1930 you'll know that anything with YY less than 30 needs to be considered 2000+ and anything >30 needs to be considered 1900-1999 .例如,如果最早的数据点是在 1930 年,您就会知道YY小于30的任何东西都需要被视为2000+而任何>30的东西都需要被视为1900-1999 If you have entries also for years like 1919 the above problem is not solvable because any date with YY=[00-21] can't be uniquely associated.如果您也有类似1919的条目,则上述问题无法解决,因为YY=[00-21]的任何日期都无法唯一关联。

However, if you can state that your dates can't be bigger than today's date then a possible solution is to check if the extracted date is bigger than today, if so, add a '19` prefix to the year, like in the example below但是,如果您可以 state 您的日期不能大于今天的日期,那么可能的解决方案是检查提取的日期是否大于今天,如果是,请在年份中添加“19”前缀,如示例中以下

with dt as (
  select '0303653597' dt_str
  union all
  select '1705213597' dt_str
  union all
  select '1805213597' dt_str
)
select
to_date(
substring(dt_str from 0 for 5) || 
case when
  to_date(substring(dt_str from 0 for 7),'DDMMYY' ) <= current_date
  then '20' 
  else '19' 
end
|| substring(dt_str from 5 for 2)
,'DDMMYY')
from dt;

For the 3 dates ( 03/03/65 , 17/05/21 and 18/05/21 ) as of today ( 17/05/21 ) the output will correctly be对于截至今天( 17/05/21 )的 3 个日期( 03/03/65 /03/65、17/05/ 17/05/2118/05/21 ),output 将正确

  to_date   
------------
 1965-03-03
 2021-05-17
 1921-05-18
(3 rows)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM