⌘+k ctrl+k
1.4 (LTS)
搜索快捷键 cmd + k | ctrl + k
Interval 类型

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

名称 描述
INTERVAL 时间段

可以通过提供数值和单位来构建 INTERVAL。非 months(月)、days(天)或 microseconds(微秒)的单位会被转换为这三个基础单位中较小单位的等效值。

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

之所以需要三个独立的基础单位,是因为一个月不对应固定的天数(二月比三月天数少),而一天也不对应固定的微秒数(由于夏令时,一天可能是 25 小时或 23 小时)。这种组件拆分方式使得 INTERVAL 类适合于在日期上添加或减去特定的时间单位。例如,我们可以使用以下 SQL 查询生成一个包含每月第一天的表:

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

INTERVAL 通过 datepart 函数解构时,months 组件会被进一步拆分为年和月,microseconds 组件会被拆分为小时、分钟和微秒。days 组件不会被拆分为其他单位。为了演示这一点,以下查询通过对这三个基础单位的随机量求和来生成一个名为 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);

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

下表描述了 datepart 如何根据三个基础单位,在公式中提取这些部分。

部分 公式
年份 #months // 12
month #months % 12
day #days
hour #microseconds // (60 * 60 * 1_000_000)
minute (#microseconds // (60 * 1_000_000)) % 60
microsecond #microseconds % (60 * 1_000_000)

此外,datepart 还可用于从 INTERVAL 中提取世纪、年代、季度、秒和毫秒。但是,在重新组合原始 INTERVAL 时不需要这些部分。事实上,如果前面的查询额外提取了这些部分中的任何一个,那么提取出的部分之和通常会大于原始的 period

部分 公式
century datepart('year', interval) // 100
decade datepart('year', interval) // 10
quarter datepart('month', interval) // 3 + 1
second datepart('microsecond', interval) // 1_000_000
millisecond datepart('microsecond', interval) // 1_000

所有单位均使用从 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'
;

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

相反,从另一个 TIMESTAMPTIMESTAMPTZ 中减去一个 TIMESTAMPTIMESTAMPTZ 会创建一个 INTERVAL,描述两个时间戳之间的差异,且仅包含 daysmicroseconds 组件。例如:

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 差值的一部分,并不等同于计算由 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 一起使用的日期部分列表。

请参阅 间隔运算符页面,获取可对间隔进行操作的函数。

© 2025 DuckDB 基金会,阿姆斯特丹,荷兰
行为准则 商标使用指南