开发者

How to get the number of days in a month?

I am trying to get the following in Postgres:

select day_in_month(2);

Expected output:

28

Is there any built-in way i开发者_如何学Cn Postgres to do that?


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

Substitute NOW() with any other date.


Using the smart "trick" to extract the day part from the last date of the month, as demonstrated by Quassnoi. But it can be a bit simpler / faster:

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

Rationale

extract is standard SQL, so maybe preferable, but it resolves to the same function internally as date_part(). The manual:

The date_part function is modeled on the traditional Ingres equivalent to the SQL-standard function extract:

But we only need to add a single interval. Postgres allows multiple time units at once. The manual:

interval values can be written using the following verbose syntax:

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

where quantity is a number (possibly signed); unit is microsecond, millisecond, second, minute, hour, day, week, month, year, decade, century, millennium, or abbreviations or plurals of these units;

ISO 8601 or standard SQL format are also accepted. Either way, the manual again:

Internally interval values are stored as months, days, and seconds. This is done because the number of days in a month varies, and a day can have 23 or 25 hours if a daylight savings time adjustment is involved. The months and days fields are integers while the seconds field can store fractions.

(Output / display depends on the setting of IntervalStyle.)

The above example uses default Postgres format: interval '1 month - 1 day'. These are also valid (while less readable):

interval '1 mon - 1 d' -- unambiguous abbreviations of time units are allowed

IS0 8601 format:

interval '0-1 -1 0:0'

Standard SQL format:

interval 'P1M-1D';

All the same.


Note that expected output for day_in_month(2) can be 29 because of leap years. You might want to pass a date instead of an int.

Also, beware of daylight saving : remove the timezone or else some monthes calculations could be wrong (next example in 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


This works as well.

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

Or just:

SELECT your_date + INTERVAL '1 month' - your_date;

These two return interval, not integer.


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;


You can write a function:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜