30

我试图在 Postgres 中获得以下内容:

select day_in_month(2);

预期输出:

28

Postgres 中是否有任何内置方法可以做到这一点?

4

6 回答 6

47
SELECT  
    DATE_PART('days', 
        DATE_TRUNC('month', NOW()) 
        + '1 MONTH'::INTERVAL 
        - '1 DAY'::INTERVAL
    )

替换NOW()为任何其他日期。

于 2011-08-03T13:29:30.457 回答
10

如Quassnoi 所示,使用智能“技巧”从该月的最后一个日期中提取日期部分。但它可以更简单/更快:

SELECT extract(days FROM date_trunc('month', now()) + interval '1 month - 1 day');

基本原理

extract是标准 SQL,因此可能更可取,但它在内部解析为与date_part(). 手册:

date_part函数以等效于 SQL 标准函数的传统 Ingres 为模型extract

但我们只需要添加一个 interval. Postgres 一次允许多个时间单位。手册:

interval可以使用以下详细语法编写值:

[@] quantity unit[quantity unit...] [direction]

哪里quantity是一个数字(可能是签名的);unitmicrosecond, millisecond, second, minute, hour, day, week, month, year, decade, century, millennium, 或这些单位的缩写或复数;

也接受ISO 8601 或标准 SQL 格式。无论哪种方式,手册再次

内部interval值存储为月、日和秒。这样做是因为一个月中的天数不同,如果涉及夏令时调整,一天可以有 23 或 25 小时。月和日字段是整数,而秒字段可以存储分数。

(输出/显示取决于 的设置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';

都一样。

于 2018-06-08T18:59:37.540 回答
2

请注意,由于闰年,day_in_month(2) 的预期输出可能为 29。您可能想要传递日期而不是 int。

另外,请注意夏令时:删除时区,否则某些月份计算可能是错误的(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
于 2016-02-19T09:59:08.297 回答
0

这也有效。

WITH date_ AS (SELECT your_date AS d)
SELECT d + INTERVAL '1 month' - d FROM date_;

要不就:

SELECT your_date + INTERVAL '1 month' - your_date;

这两个返回区间,不是整数

于 2017-07-24T10:28:47.347 回答
-2
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;
于 2017-09-15T10:19:13.003 回答
-2

你可以写一个函数:

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;
于 2018-12-13T10:48:11.640 回答