ISO-8601 in Postgres: How to insert only year in type date? (incomplete date-time values)

后端 未结 1 923
刺人心
刺人心 2021-01-25 00:01

The Postgres database claims it supports the ISO-8601 standard. In ISO-8601 a date format \"yyyy\", i.e. consisting of only the year, is fine and acceptable. But I can\'t find a

1条回答
  •  盖世英雄少女心
    2021-01-25 00:40

    To get the year of a date data type:

    select extract(year from '2014-01-01'::date) as the_year;
     the_year 
    ----------
         2014
    

    If you only need the year then use a smallint with a check constraint

    create table t (
        the_year smallint check(
            the_year between 0 and extract(year from current_date)
        )
    );
    
    insert into t (the_year) values (2030);
    ERROR:  new row for relation "t" violates check constraint "t_the_year_check"
    DETAIL:  Failing row contains (2030).
    
    insert into t (the_year) values (2014);
    INSERT 0 1
    

    But if you will store the whole date then it makes no sense to separate into 3 columns.

    Note that the semantics of the column are up to the application. If a column is of the date type but the application only considers the year then that column means the year.

    Check the Date/Time Functions and Operators


    One solution to the partial date problem pointed by @a_horse in the comments is to create a column indicating the precision of that date

    create table t (
        the_date date,
        the_date_precision varchar(5)
    );
    
    insert into t (the_date, the_date_precision) values
    (current_date, 'year'),
    (current_date, 'month'),
    (current_date, 'day')
    ;
    
    select
        case the_date_precision
            when 'year' then to_char(the_date, 'YYYY')
            when 'month' then to_char(the_date, 'YYYY-MM')
            else to_char(the_date, 'YYYY-MM-DD')
        end as the_date
    from t
    ;
      the_date  
    ------------
     2014
     2014-02
     2014-02-06
    

    The above is the KISS aproach but I think the next implementation is more elegant

    create table t (
        the_date date,
        the_date_precision smallint
    );
    
    insert into t (the_date, the_date_precision) values
    (current_date, 1),
    (current_date, 2),
    (current_date, 3)
    ;
    
    select
        array_to_string(
            (
                string_to_array(to_char(the_date, 'YYYY-MM-DD'), '-')
            )[1:the_date_precision]
            , '-'
        ) as the_date
    from t
    ;
      the_date  
    ------------
     2014
     2014-02
     2014-02-06
    

    That select expression could be turned into a function to be easier to reproduce. Or just a view

    create view view_t as 
    select *,
        array_to_string(
            (
                string_to_array(to_char(the_date, 'YYYY-MM-DD'), '-')
            )[1:the_date_precision]
            , '-'
        ) as the_date_output
    from t
    ;
    select * from view_t;
      the_date  | the_date_precision | the_date_output 
    ------------+--------------------+-----------------
     2014-02-06 |                  1 | 2014
     2014-02-06 |                  2 | 2014-02
     2014-02-06 |                  3 | 2014-02-06
    

    0 讨论(0)
提交回复
热议问题