INTERVAL
表示可以添加到或从DATE
、TIMESTAMP
、TIMESTAMPTZ
或TIME
值中减去的时间段。
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
时,月份部分会进一步拆分为年和月,微秒部分会拆分为小时、分钟和微秒。天数部分不会拆分为其他单位。为了演示这一点,以下查询通过将三个基本单位的随机量相加生成一个名为period
的INTERVAL
。然后从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
可以使用 +
和 -
运算符与 TIMESTAMP
、TIMESTAMPTZ
、DATE
和 TIME
进行加减操作。
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
微秒来计算的。
因此,INTERVAL
s 在功能上不同时仍可能相等,并且当它们被添加到日期或时间戳时,INTERVAL
s 的顺序并不总是保持不变。
例如:
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页面以了解操作间隔的函数。