【问题标题】:postgres '1 year' equals '360 days'?postgres '1 年' 等于 '360 天'?
【发布时间】:2014-12-30 17:13:18
【问题描述】:

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

今天是 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

【问题讨论】:

  • 将now() 替换为能够重现该问题的时间戳对于那些在您编写该问题的同一天没有看到此问题的人会有所帮助。

标签: postgresql datediff


【解决方案1】:

或者关于日期算术有什么有趣的地方吗?

这很有趣,但不是那种让你发笑的方式。

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

=> 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 天。别等了,闰年呢?嗯 - 这会影响几周吗?啊!

基本上,您无法在时间单位之间进行明智的转换。一分钟没有 60 秒,一天没有 24 小时,一年没有 52 周,甚至没有 365 天。不幸的是,人类(尤其是客户型的人类)喜欢在时间单位之间转换,所以我们最终会陷入这样的混乱。

PostgreSQL 的系统并不比任何其他系统更疯狂,实际上比大多数系统都好。

【讨论】:

    【解决方案2】:

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

    在内部,interval 值存储为月、日和秒。这样做是因为一个月中的天数不同,如果涉及夏令时调整,一天可以有 23 或 25 小时。月和日字段是整数,而秒字段可以存储分数。因为间隔通常是由常量字符串或时间戳减法创建的,所以这种存储方法在大多数情况中效果很好。函数justify_days 和justify_hours 可用于调整超出正常范围的日期和时间。

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

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

    但是,如果您应用 interval 减法/加法,请考虑不同的日期和月份长度:

    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)并将这些值与&lt;、&gt; 或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       |
    

    【讨论】:

      【解决方案3】:

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

      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
      

      【讨论】:

      • 似乎相当随意,尽管“1 年”让我有 360 天。 5 天以上似乎有很大的不同
      • 据我了解,年份是动态间隔 - 它会根据您添加的年份而改变其含义。如果没有附加日期,也许它有一些价值,比如说 360 天?我不知道,对我来说,检查 1 年后是否比其他日期更早,而不是检查 2 个日期之间的差异是否小于 1 年(是闰年吗?或者可能是在儒略历改革前后) ?)。当您不知道您在谈论的年份时,1 年没有任何意义。
      • 也许 - 尽管我所知道的年份是 360 天,但在我期望的默认日历中它们是 365 或 366(可能与农历等不同)。此外,这不是随机年份,该示例明确从 2014 年 11 月 3 日减去 1 年。
      • @paulf 但是当你从其他时间戳中减去时间戳时,你会得到没有上下文的间隔。与月份相同:3 月 1 日 - 2 月 1 日 = 1 个月,7 月 1 日 - 6 月 1 日 = 1 个月。它们的天数相同吗?理查德更好地挖掘为什么一年等于 ta 360 天。
      猜你喜欢
      • 1970-01-01
      • 2017-01-02
      • 2021-12-28
      • 1970-01-01
      • 1970-01-01
      • 2012-01-17
      • 2017-12-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多