As part of a larger Postgres query, I generate all years between two given timestamps (timestamptz
):
select to_char(generate_series, 'YYYY') from generate_series(
'2022-06-14 11:00:00.000+00'::timestamptz,
'2023-06-14 11:00:00.000+00'::timestamptz,
'1 year' );
Which returns:
'2022'
'2023'
The issue is, if there is less than one year between both timestamps, only the first year is returned. I need a set of all involved years, regardless of the the interval between both timestamps, e.g.:
select to_char(generate_series, 'YYYY') from generate_series(
'2022-06-14 11:00:00.000+00'::timestamptz,
'2023-06-13 11:00:00.000+00'::timestamptz,
'1 year' );
Only returns:
'2022'
But I would like it to return:
'2022'
'2023'
Is there some way to achieve this?
2
Answers
The year of a
timestamptz
(timestamp with time zone]
) value is not strictly determined. It’s still the year 2024 in New York, when I wish "Happy New Year 2025" in Vienna.Only
date
ortimestamp
(timestamp without time zone
) are deterministic in this regard.To avoid corner case issues you must define the time zone for your query in one way or another.
Here is one way:
Here is another:
date_trunc()
allows a 3rd parameter to pass the time zone since Postgres 12 – which only makes sense fortimestamptz
, obviously.Replace with your time zone, or use timestamp values to begin with.
Assuming the second timestamp is guaranteed to be after the first, or you have to do more / define how to deal with it.
Basics:
I’m not sure exactly why you’re doing it this way, but what you can do is the following – if your second date isn’t less than 1 year from your first, then you can use the following (hacky!) code – if you’re taking the dates from somewhere else.
(all of the code below is available on the fiddle here):
This makes use of the PostgreSQL
AGE()
function:Result: