我想知道是否有其他人遇到过这个或知道有关它的信息。
今天是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
答案 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_days
和justify_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