Как узнать количество дней в месяце? - PullRequest
20 голосов
/ 03 августа 2011

Я пытаюсь получить следующее в Postgres:

select day_in_month(2);

Ожидаемый результат:

28

Есть ли в Postgres какой-либо встроенный способ сделать это?

Ответы [ 6 ]

34 голосов
/ 03 августа 2011
SELECT  
    DATE_PART('days', 
        DATE_TRUNC('month', NOW()) 
        + '1 MONTH'::INTERVAL 
        - '1 DAY'::INTERVAL
    )

Заменить NOW() любой другой датой.

3 голосов
/ 08 июня 2018

Использование умного «трюка» для извлечения части day из последней даты месяца, как , продемонстрированное Quassnoi .Но это может быть немного проще / быстрее:

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

Обоснование

extract - это стандартный SQL, поэтому может быть предпочтительнее, но внутренне разрешает ту же функцию, что и date_part(). Руководство:

Функция date_part смоделирована на традиционном Ingres, эквивалентном стандартной функции SQL 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 также принимаются.В любом случае, снова руководство :

Внутренне 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';

Все то же самое.

1 голос
/ 19 февраля 2016

Обратите внимание, что ожидаемый результат для 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
0 голосов
/ 13 декабря 2018

Вы можете написать функцию:

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;
0 голосов
/ 15 сентября 2017
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;
0 голосов
/ 24 июля 2017

Это тоже работает.

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

Или просто:

SELECT your_date + INTERVAL '1 month' - your_date;

Эти два возвращают интервал , а не целое число .

...