⌘+k ctrl+k
1.1.3 (stable)
Search Shortcut cmd + k | ctrl + k
Interval Type

INTERVAL表示可以添加到或从DATETIMESTAMPTIMESTAMPTZTIME值中减去的时间段。

Name Description
INTERVAL 时间段

可以通过提供数量和单位来构建一个INTERVAL。 不是微秒的单位将被转换为这三个基本单位中较小的等效数量。

SELECT
    INTERVAL 1 YEAR, -- single unit using YEAR keyword; stored as 12 months
    INTERVAL (random() * 10) YEAR, -- parentheses necessary for variable amounts;
                                   -- stored as integer number of months
    INTERVAL '1 month 1 day', -- string type necessary for multiple units; stored as (1 month, 1 day)
    '16 months'::INTERVAL, -- string cast supported; stored as 16 months
    '48:00:00'::INTERVAL, -- HH::MM::SS string supported; stored as (48 * 60 * 60 * 1e6 microseconds)
;

警告 十进制值可以在字符串中使用,但会被四舍五入为整数。

SELECT INTERVAL '1.5' YEARS;
-- Returns 12 months; equivalent to `to_years(CAST(trunc(1.5) AS INTEGER))`

为了更精确,请使用更细粒度的单位;例如,使用18 MONTHS而不是'1.5' YEARS

需要三个基本单位,因为一个月不对应固定的天数(二月比三月少几天),一天也不对应固定的微秒数。 这种划分为组件的方式使得INTERVAL类适合用于向日期添加或减去特定的时间单位。例如,我们可以使用以下SQL查询生成一个包含每个月第一天的表格:

SELECT DATE '2000-01-01' + INTERVAL (i) MONTH
FROM range(12) t(i);

当通过datepart函数解构INTERVAL时,月份部分会进一步拆分为年和月,微秒部分会拆分为小时、分钟和微秒。天数部分不会拆分为其他单位。为了演示这一点,以下查询通过将三个基本单位的随机量相加生成一个名为periodINTERVAL。然后从period中提取上述六个部分,将它们重新相加,并确认结果始终等于原始的period

SELECT
    period = list_reduce(
        [INTERVAL (datepart(part, period) || part) FOR part IN
             ['year', 'month', 'day', 'hour', 'minute', 'microsecond']
        ],
        (i1, i2) -> i1 + i2
    ) -- always true
FROM (
    VALUES (
        INTERVAL (random() * 123_456_789_123) MICROSECONDS
        + INTERVAL (random() * 12_345) DAYS
        + INTERVAL (random() * 12_345) MONTHS
    )
) _(period);

警告 微秒 组件仅被分割为小时、分钟和微秒,而不是小时、分钟、和微秒。

此外,可以通过datepart函数提取INTERVAL中的世纪、十年、季度、秒和毫秒的数量,这些数量会被向下舍入到最接近的整数。然而,这些组件并不是重新组装原始INTERVAL所必需的。实际上,如果之前的查询还提取了十年或秒,那么提取部分的总和通常会大于原始的period,因为这会分别对月份和微秒组件进行重复计数。

所有单位使用基于0的索引,除了季度,季度使用基于1的索引。

例如:

SELECT
    datepart('decade', INTERVAL 12 YEARS), -- returns 1
    datepart('year', INTERVAL 12 YEARS), -- returns 12
    datepart('second', INTERVAL 1_234 MILLISECONDS), -- returns 1
    datepart('microsecond', INTERVAL 1_234 MILLISECONDS), -- returns 1_234_000

时间戳、日期和间隔的算术运算

INTERVAL 可以使用 +- 运算符与 TIMESTAMPTIMESTAMPTZDATETIME 进行加减操作。

SELECT
    DATE '2000-01-01' + INTERVAL 1 YEAR,
    TIMESTAMP '2000-01-01 01:33:30' - INTERVAL '1 month 13 hours',
    TIME '02:00:00' - INTERVAL '3 days 23 hours', -- wraps; equals TIME '03:00:00'
;

相反,减去两个TIMESTAMP或两个TIMESTAMPTZ会创建一个INTERVAL,描述时间戳之间的差异,仅包含天和微秒部分。例如:

SELECT
    TIMESTAMP '2000-02-06 12:00:00' - TIMESTAMP '2000-01-01 11:00:00', -- 36 days 1 hour
    TIMESTAMP '2000-02-01' + (TIMESTAMP '2000-02-01' - TIMESTAMP '2000-01-01'), -- '2000-03-03', NOT '2000-03-01'
;

从一个DATE减去另一个DATE不会创建一个INTERVAL,而是返回给定日期之间的天数作为整数值。

警告 提取两个TIMESTAMP之间的INTERVAL差异的组件并不等同于计算两个TIMESTAMP之间对应单位的分区边界数量,如datediff函数所计算的那样:

SELECT
    datediff('day', TIMESTAMP '2020-01-01 01:00:00', TIMESTAMP '2020-01-02 00:00:00'), -- 1
    datepart('day', TIMESTAMP '2020-01-02 00:00:00' - TIMESTAMP '2020-01-01 01:00:00'), -- 0
;

相等性和比较

仅用于相等性和排序比较时,INTERVAL中的总微秒数是通过将天数基本单位转换为24 * 60 * 60 * 1e6微秒,并将月数基本单位转换为30天,即30 * 24 * 60 * 60 * 1e6微秒来计算的。

因此,INTERVALs 在功能上不同时仍可能相等,并且当它们被添加到日期或时间戳时,INTERVALs 的顺序并不总是保持不变。

例如:

  • INTERVAL 30 DAYS = INTERVAL 1 MONTH
  • 但是 DATE '2020-01-01' + INTERVAL 30 DAYS != DATE '2020-01-01' + INTERVAL 1 MONTH

  • INTERVAL '30 days 12 hours' > INTERVAL 1 MONTH
  • 但是 DATE '2020-01-01' + INTERVAL '30 days 12 hours' < DATE '2020-01-01' + INTERVAL 1 MONTH.

Functions

请参阅日期部分函数页面以获取可与INTERVAL一起使用的可用日期部分列表。

请参阅Interval Operators页面以了解操作间隔的函数。