How to get the number of days in a month?

后端 未结 6 2029
梦毁少年i
梦毁少年i 2020-12-30 23:25

I am trying to get the following in Postgres:

select day_in_month(2);

Expected output:

28

Is there any bu

相关标签:
6条回答
  • 2020-12-30 23:39

    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 讨论(0)
  • 2020-12-30 23:40

    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.

    0 讨论(0)
  • 2020-12-30 23:40

    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
    
    0 讨论(0)
  • 2020-12-30 23:41

    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.

    0 讨论(0)
  • 2020-12-30 23:46
    SELECT  
        DATE_PART('days', 
            DATE_TRUNC('month', NOW()) 
            + '1 MONTH'::INTERVAL 
            - '1 DAY'::INTERVAL
        )
    

    Substitute NOW() with any other date.

    0 讨论(0)
  • 2020-12-30 23:50
    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 讨论(0)
提交回复
热议问题