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
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