我有两个日期,格式为 Time Stamp Without Time Zone。
我想比较它们并得到它们之间月份的数值:
select age(NOW(), '2012-03-24 14:44:55.454041+03')
给予:
4 years 9 mons 2 days 21:00:27.165482
这里的技巧是我需要将此结果转换为一个月值。
所以:
为了将 YEARS
转换为 Months
:
select EXTRACT(YEAR FROM age) * 12 + EXTRACT(MONTH FROM age)
FROM age(NOW(), '2012-06-24 14:44:55.454041+03') AS t(age)
我得到 57
,即 4*12+9
。
我的问题是我不知道如何转换日期。
在上面的示例中,我需要将 '2 days'
转换为以月为单位的值。
“2 天”
不是 0
个月!
在 30 天的月份中,15 天是 0.5 个月。
我该怎么做?
最终结果应该是 57.something
最佳答案
您可以通过以下方式进行粗略估计:
select (extract(epoch from timestamptz '2012-06-24 14:44:55.454041+03')
- extract(epoch from timestamptz '2017-03-27 00:00:00+03'))
/ extract(epoch from interval '30.44 days') rough_estimation
(您可以使用 extract(epoch from interval '1 month')
来进行更粗略的估计)。
您的原始公式的问题在于它旨在给出两个日期之间的完整月份差异。如果您也想计算天数,则会出现一个有趣的问题:在您的示例中,结果应该是 57 个月
和 2 天 21:00:27.165482
。但是 2 days 21:00:27.165482
部分应该在几月份计算呢?一个平均长度的月(30.44 天
)?如果您想精确一点,请注意,在您的示例中,差异实际上只有 56 个月
,加上 2012-06 中的近
(有 7 天
30
天)和 27 天
2017-03
(有 31
天).您应该问自己的问题:是否真的值得一个高级公式来考虑两个范围结束的每个月的天数?
编辑:为了完整起见,这里有一个函数,可以考虑两个范围结束:
create or replace function abs_month_diff(timestamptz, timestamptz)
returns numeric
language sql
stable
as $func$
select extract(year from age)::numeric * 12 + extract(month from age)::numeric
+ (extract(epoch from (lt + interval '1 month' - l))::numeric / extract(epoch from (lt + interval '1 month' - lt))::numeric)
+ (extract(epoch from (g - gt))::numeric / extract(epoch from (gt + interval '1 month' - gt))::numeric)
- case when gt <= l or lt = l then 1 else 0 end
from least($1, $2) l,
greatest($1, $2) g,
date_trunc('month', l) lt,
date_trunc('month', g) gt,
age(gt, l)
$func$;
(注意:如果您使用 timestamp
而不是 timestamptz
,则此函数是 immutable
而不是 stable
。就像 date_trunc
函数一样。)
所以:
select age('2017-03-27 00:00:00+03', '2012-06-24 14:44:55.454041+03'),
abs_month_diff('2017-03-27 00:00:00+03', '2012-06-24 14:44:55.454041+03');
将产生:
age | abs_month_diff
---------------------------------------+-------------------------
4 years 9 mons 2 days 09:15:04.545959 | 57.05138456751051843959
http://rextester.com/QLABV31257(已过时)
编辑:修正函数以在差异小于一个月时产生准确的结果。
参见 f.ex:
set time zone 'utc';
select abs_month_diff('2017-02-27 00:00:00+03', '2017-02-24 00:00:00+03'), 3.0 / 28,
abs_month_diff('2017-03-27 00:00:00+03', '2017-03-24 00:00:00+03'), 3.0 / 31,
abs_month_diff('2017-04-27 00:00:00+03', '2017-04-24 00:00:00+03'), 3.0 / 30,
abs_month_diff('2017-02-27 00:00:00+00', '2017-03-27 00:00:00+00'), 2.0 / 28 + 26.0 / 31;
http://rextester.com/TIYQC5325(已过时)
编辑 2:此函数基于以下公式,计算一个月的长度:
select (mon + interval '1 month' - mon)
from date_trunc('month', now()) mon
这甚至会考虑夏令时的变化。 F.ex.在我的国家/地区,昨天(2017-03-26
)发生了 DST 更改,所以今天(2017-03-27
)以上查询报告:30天 23:00:00
。
编辑 3:再次更正函数(感谢 @Jonathan 注意到边缘情况的边缘情况)。
关于sql - 如何在 PostgreSQL 中获取两个日期之间的月份数值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43041943/