我正在尝试在 Postgres 中获取以下内容:
select day_in_month(2);
预期输出:
28
Postgres 中有没有内置的方法可以做到这一点?
SELECT
DATE_PART('days',
DATE_TRUNC('month', NOW())
+ '1 MONTH'::INTERVAL
- '1 DAY'::INTERVAL
)
用任何其他日期替换
NOW()
。
使用智能“技巧”从该月的最后一个日期中提取day部分,如Quassnoi所示。但它可以更简单/更快一点:
SELECT extract(days FROM date_trunc('month', now()) + interval '1 month - 1 day');
extract
是标准 SQL,因此可能更可取,但它在内部解析为与 date_part()
相同的函数。 说明书:
函数以传统的 Ingres 为模型,相当于 SQL 标准函数date_part
:extract
但我们只需要添加 a single
interval
。 Postgres 允许同时使用多个时间单位。 说明书:
也接受值可以使用以下详细语法编写:interval
[@]
quantity unit
[
quantity unit
...] [
direction
]
其中
是一个数字(可能带符号);quantity
是unit
,microsecond
、millisecond
、second
、minute
、hour
、day
、week
、month
、year
、decade
、century
,或这些单位的缩写或复数;millennium
ISO 8601 或标准 SQL 格式。不管怎样,再次手册:
在内部,
值存储为月、日和秒。 这样做是因为一个月中的天数不同,并且一天 如果夏令时调整为 23 或 25 小时 涉及。月份和日期字段是整数,而秒字段是 字段可以存储分数。interval
(输出/显示取决于IntervalStyle
上面的示例使用默认 Postgres 格式:
interval '1 month - 1 day'
。这些也是有效的(虽然可读性较差):
interval '1 mon - 1 d' -- unambiguous abbreviations of time units are allowed
IS0 8601 格式:
interval '0-1 -1 0:0'
标准 SQL 格式:
interval 'P1M-1D';
都一样。
请注意,由于闰年,day_in_month(2) 的预期输出可能为 29。您可能想传递日期而不是整数。
另外,请注意夏令时:删除时区,否则某些月份的计算可能会错误(CET / CEST 中的下一个示例):
SELECT DATE_TRUNC('month', '2016-03-12'::timestamptz) + '1 MONTH'::INTERVAL
- DATE_TRUNC('month', '2016-03-12'::timestamptz) ;
------------------
30 days 23:00:00
SELECT DATE_TRUNC('month', '2016-03-12'::timestamp) + '1 MONTH'::INTERVAL
- DATE_TRUNC('month', '2016-03-12'::timestamp) ;
----------
31 days
这也有效。
WITH date_ AS (SELECT your_date AS d)
SELECT d + INTERVAL '1 month' - d FROM date_;
或者只是:
SELECT your_date + INTERVAL '1 month' - your_date;
这两个返回间隔,而不是整数。
SELECT
(
timestamp '2024-01-01' + INTERVAL '1 month'
) - timestamp '2024-01-01' AS days
-- 31 days
两个时间戳相减总是会产生一个以天为单位的间隔。我们不会仅仅得到几个月或几年的答案,因为这些时间段的长度是可变的。
SELECT cnt_dayofmonth(2016, 2); -- 29
create or replace function cnt_dayofmonth(_year int, _month int)
returns int2 as
$BODY$
-- ZU 2017.09.15, returns the count of days in mounth, inputs are year and month
declare
datetime_start date := ('01.01.'||_year::char(4))::date;
datetime_month date := ('01.'||_month||'.'||_year)::date;
cnt int2;
begin
select extract(day from (select (datetime_month + INTERVAL '1 month -1 day'))) into cnt;
return cnt;
end;
$BODY$
language plpgsql;
你可以写一个函数:
CREATE OR REPLACE FUNCTION get_total_days_in_month(timestamp)
RETURNS decimal
IMMUTABLE
AS $$
select cast(datediff(day, date_trunc('mon', $1), last_day($1) + 1) as decimal)
$$ LANGUAGE sql;