postgres' 1年'等于360天'?

时间:2014-11-03 22:34:34

标签: postgresql datediff

我想知道是否有其他人遇到过这个或知道有关它的信息。

今天是2014年11月3日,如果我检查2013年11月5日是否在去年,我会得到不同的答案,具体取决于我如何检查:1年与365天

select now() - '20131105' as diff, 
case when now() - '20131105' <= '1 year' then 'within year' else 'not within year' end as yr_check,
case when now() - '20131105' <= '365 days' then 'within 365 days' else 'not within 365 days' end as day_check

2014-11-03 16:27:38.39669-06;  363 days 16:27:38.39669;  not within year;  within 365 days

看起来在11月9日查询时,没关系

select now() as right_now, now() - '20131109' as diff, 
case when now() - '20131109' <= '1 year' then 'within year' else 'not within year' end as yr_check,
case when now() - '20131109' <= '365 days' then 'within 365 days' else 'not within 365 days' end as day_check

2014-11-03 16:31:12.464469-06;  359 days 16:31:12.464469;  within year;  within 365 days

有人对此有所了解吗?或者有什么关于日期算术的东西很有趣吗?

postgres版本是9.2.4

3 个答案:

答案 0 :(得分:3)

  

或者日期算术是否有点有趣?

这很好笑,但不会让你发笑。

十二个月必须等于一年不是吗?

=> SELECT '12 months'::interval = '1 year'::interval;
 ?column? 
----------
 t

好。说得通。嗯 - 想知道一个月有多长。

=> SELECT '30 days'::interval = '1 month'::interval;
 ?column? 
----------
 t

足够公平。假设他们必须选择一些东西。

嗯 - 但这意味着......

=> SELECT '360 days'::interval = '12 months'::interval;
 ?column? 
----------
 t

这似乎意味着......

=> SELECT '360 days'::interval = '1 year'::interval;
 ?column? 
----------
 t

那不可能是对的!他们需要做的是一个月等于30.41666天。没有,闰年怎么样?嗯 - 这会影响几周吗? AARGH!

基本上,你不能在时间单位之间明智地转换。一分钟内没有60秒,一天24小时,一年52天甚至365天。不幸的是,人类(特别是客户形象的人)喜欢在时间单位之间进行转换,所以我们最终会像这样混乱。

PostgreSQL的系统不再是任何其他系统,实际上比大多数系统更好。

答案 1 :(得分:1)

来自www.postgresql.org/docs/current/static/datatype-datetime.html

  

内部interval值存储为月,日和秒。这样做是因为一个月中的天数变化,如果涉及夏令时调整,则一天可以有23或25小时。月份和日期字段是整数,而秒字段可以存储分数。因为间隔通常是从常量字符串或时间戳减法创建的,所以此存储方法在大多数情况下中运行良好。函数justify_daysjustify_hours可用于调整超出正常范围的日期和小时数。

因为你比较了两个interval,所以在比较之前,PostgreSQL会在内部规范化值(比如justify_interval()):

SELECT INTERVAL '31 days' > INTERVAL '1 mon' -- yields 't'

但是,如果您应用interval减法/加法,那么改变日期&amp;考虑月份长度:

SELECT (timestamptz '2014-11-03 00:00:00 America/New_York' - INTERVAL '1 day') AT TIME ZONE 'America/New_York',
       timestamptz '2014-11-03 00:00:00 America/New_York' - timestamptz '2014-11-02 00:00:00 America/New_York' <= interval '1 day';


-- | timestamp           | boolean |
-- +---------------------+---------+
-- | 2014-11-02 01:00:00 | f       |

因此,如果您需要测试时间戳/日期是否在一个范围内,您应该操纵时间戳/日期(或使用时间戳/日期ranges)&amp;将这些值与<>BETWEEN进行比较。

SELECT timestamp '2014-11-03 00:00:00' - timestamp '2014-10-03 00:00:00' <= interval '1 mon',
       timestamp '2014-11-03 00:00:00' - interval '1 mon' <= timestamp '2014-10-03 00:00:00';

-- | boolean | boolean |
-- +---------+---------+
-- | f       | t       |

答案 2 :(得分:0)

我不确定此检查的真正问题是什么,但它可以通过其他方式解决:

select now() - interval '1 year' <= date '2013-11-05'

我不是Postgres的专家,但它可以是类型比较的东西,因为:

select pg_typeof(now() - date '2013-11-05'),
       pg_typeof(now() - interval '1 year')

产生结果:

interval, timestamp with time zone

因此,您的示例将间隔与间隔进行比较,但对于不同的比例 - 天数与年份,我的解决方案将时间戳与日期进行比较,这似乎有效

更新:

您可以检查interval '1 year'未附加到年份(未添加到日期或时间戳)等于360天:

select interval '1 year' <= interval '359 days',
       interval '1 year' <= interval '360 days'

产生:

f, t

根据我的理解,你不能只比较你不知道它附加年份的随机年份间隔 - 总是比较日期,只使用间隔来创建新的日期对象。

select now() - interval '1 year' <= now() - interval '365 days'

t