⌘+k ctrl+k
1.3 (稳定版)
搜索快捷键 cmd + k | ctrl + k
间隔类型

INTERVAL 表示可用于对 DATETIMESTAMPTIMESTAMPTZTIME 值进行加减的时间段。

名称 描述
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)
;

警告:当与单位关键字一起使用时,小数数值会被截断为整数(除非单位是 SECONDSMILLISECONDS)。

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

为了获得更高的精度,请在字符串中包含单位或使用更精细的单位;例如,INTERVAL '1.5 years'INTERVAL 18 MONTHS

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

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

INTERVAL 通过 datepart 函数分解时, 组件会进一步拆分为年和月,而 微秒 组件会拆分为小时、分钟和微秒。 组件不会拆分为额外的单位。为了证明这一点,以下查询通过对三个基本单位的随机量求和,生成了一个名为 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);

警告:微秒 组件只拆分为小时、分钟和微秒,而不是小时、分钟、 和微秒。

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

所有单位都使用 0-based 索引,除了季度使用 1-based 索引。

例如

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'
;

即使 INTERVAL 没有微秒组件,将 INTERVAL 添加到 DATE 也会返回 TIMESTAMP。结果与将 DATE 转换为 TIMESTAMP(这会将时间组件设置为 00:00:00)后再添加 INTERVAL 的结果相同。

相反,两个 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 相减不会创建 INTERVAL,而是返回给定日期之间的天数作为整数值。

警告:提取两个 TIMESTAMP 之间 INTERVAL 差异的某个组件,不等同于使用 datediff 函数计算的对应单位下两个 TIMESTAMP 之间的分区边界数量。

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 微秒。

因此,即使 INTERVAL 在功能上不同,它们也可能比较相等;并且当 INTERVAL 被添加到日期或时间戳时,其顺序并不总是保留。

例如

  • 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

函数

有关可与 INTERVAL 一起使用的日期部分的列表,请参阅日期部分函数页面

有关对间隔进行操作的函数,请参阅间隔运算符页面