今天,我在运行此查询时遇到了 PostgreSQL 9.6 中无法解释的结果:
SELECT age('2018-06-30','2018-05-19') AS one,
age('2018-07-01','2018-05-20') AS two;
两列的预期结果:1 mon 11 days
。但是,仅在 2018-05-19 到 2018-06-30 期间,我得到了我的期望,而在 2018-05-20 到 2018-07-01 期间,我会多得到一天:1星期一 12 天
我不明白为什么会这样,据我了解,2018-05-20 2018-07-01 之间只是 1 mon 11 days
的间隔,Postgres 结果在这里是错误的。
我找不到任何关于 PostgreSQL-age(timestamp,timestamp)
函数究竟如何工作的深入信息。但是,我假设该函数执行类似的操作:从开始日期开始,以月份为单位向前移动,直到到达结束月份。从那里,转到结束日期的那一天。总结月份和日期。
因此,根据我的理解,这就是我的情况下应该发生的事情(抱歉,这里太冗长了,但我觉得这是必要的):
从 2018-05-19 开始。前进一个月。登陆时间为 2018-06-19。向前走 N
天,直到到达 2018-06-30:
1 day: 20
2 days: 21
3 days: 22
4 days: 23
5 days: 24
6 days: 25
7 days: 26
8 days: 27
9 days: 28
10 days: 29
11 days: 30
= 1 month 11 days.
对于2018-05-20和2018-07-01之间的时间应该是差不多的:
从 2018-05-20 开始。前进一个月。登陆时间为 2018-06-20。向前走 N
天,直到到达 2018-07-01:
1 day: 21
2 days: 22
3 days: 23
4 days: 24
5 days: 25
6 days: 26
7 days: 27
8 days: 28
9 days: 29
10 days: 30
11 days: 1
= 1 month 11 days.
这是我的错误还是 PostgreSQL 的错误之一? 是否有替代函数/算法按照我描述/预期的方式工作?
最佳答案
age
是通过src/backend/utils/adt/timestamp.c
中的timestamptz_age
函数计算的。评论说:
/* timestamptz_age()
* Calculate time difference while retaining year/month fields.
* Note that this does not result in an accurate absolute time span
* since year and month are out of context once the arithmetic
* is done.
*/
代码首先将参数转换为struct pg_tm
变量tm1
和tm2
(struct pg_tm
类似于C 库的 struct tm
,但有额外的时区字段),然后计算每个字段的差异 tm
。
在 age('2018-07-01','2018-05-20')
的情况下,该差异的相关字段如下所示:
tm_mday = -19
tm_mon = 2
tm_year = 0
现在调整负字段。对于 tm_mday
,代码如下所示:
while (tm->tm_mday < 0)
{
if (dt1 < dt2)
{
tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
tm->tm_mon--;
}
else
{
tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
tm->tm_mon--;
}
}
由于 dt1 > dt2
,采用了 else
分支,代码将 5 月的天数 (31) 相加并将月份减 1,最终与
tm_mday = 12
tm_mon = 1
tm_year = 0
这就是你得到的结果。
现在乍一看似乎tm2->tm_mon
不是正确选择的月份,最好取左边参数的前一个月:
day_tab[isleap(tm1->tm_year)][(tm1->tm_mon + 10) % 12]
但我不能说这种选择是否在所有情况下都更好,而且无论如何评论都会保护函数,所以我不愿将其称为错误。
您可能想通过黑客邮件列表处理它。
关于sql - PostgreSQL age() 函数 : different/unexpected results when landing in dfferent month,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51167239/