Re: Understanding years part of Interval

From: Erik Wienhold <ewie(at)ewie(dot)name>
To: "pgsql-general(at)postgresql(dot)org" <pgsql-general(at)postgresql(dot)org>
Subject: Re: Understanding years part of Interval
Date: 2023-02-06 19:29:58
Message-ID: 371463617.216036.1675711798455@office.mailbox.org
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general pgsql-hackers

> On 06/02/2023 18:33 CET Marcos Pegoraro <marcos(at)f10(dot)com(dot)br> wrote:
>
> Em seg., 6 de fev. de 2023 às 10:59, Erik Wienhold <ewie(at)ewie(dot)name> escreveu:
> > > On 06/02/2023 12:20 CET Marcos Pegoraro <marcos(at)f10(dot)com(dot)br> wrote:
> > >
> > > I was just playing with some random timestamps for a week, for a month,
> > > for a year ...
> > >
> > > select distinct current_date+((random()::numeric)||'month')::interval from generate_series(1,100) order by 1;
> > > It´s with distinct clause because if you change that 'month' for a 'year'
> > > it´ll return only 12 rows, instead of 100. So, why years part of interval
> > > works differently than any other ?
> > >
> > > select '1.01 week'::interval; --> 0 years 0 mons 7 days 1 hours 40 mins 48.00 secs
> > > select '1.01 month'::interval; --> 0 years 1 mons 0 days 7 hours 12 mins 0.00 secs
> > > select '1.01 year'::interval; --> 1 years 0 mons 0 days 0 hours 0 mins 0.00 secs
> >
> > Explained in https://www.postgresql.org/docs/15/datatype-datetime.html#DATATYPE-INTERVAL-INPUT:
> >
> > Field values can have fractional parts: for example, '1.5 weeks' or
> > '01:02:03.45'. However, because interval internally stores only
> > three integer units (months, days, microseconds), fractional units
> > must be spilled to smaller units. Fractional parts of units greater
> > than months are rounded to be an integer number of months, e.g.
> > '1.5 years' becomes '1 year 6 mons'. Fractional parts of weeks and
> > days are computed to be an integer number of days and microseconds,
> > assuming 30 days per month and 24 hours per day, e.g., '1.75 months'
> > becomes 1 mon 22 days 12:00:00. Only seconds will ever be shown as
> > fractional on output.
> >
> > Internally interval values are stored as months, days, and
> > microseconds. 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.
> >
> I´ve sent this message initially to general and Erik told me it's documented,
> so it's better to hackers help me if this has an explaining why it's done that way.
>
> select '1 year'::interval = '1.05 year'::interval -->true ?
> I cannot agree that this select returns true.

The years are converted to months and the fractional month is rounded half up:

1.05 year = 12.6 month
=> 1 year 0.6 month
=> 1 year 1 month (after rounding)

Compare that to 12.5 months to see when the rounding occurs:

12.5 month / 12 month
=> 1.0416... years

Plug 1.0416 and 1.0417 into the interval to observe the rounding:

=# select '1.0416 year'::interval, '1.0417 year'::interval;
interval | interval
----------+--------------
1 year | 1 year 1 mon

--
Erik

In response to

Browse pgsql-general by date

  From Date Subject
Next Message Phillip Diffley 2023-02-07 02:48:51 Language options for GIN index support functions
Previous Message Peter J. Holzer 2023-02-06 19:22:22 Re: Sequence vs UUID

Browse pgsql-hackers by date

  From Date Subject
Next Message Andres Freund 2023-02-06 19:33:28 Re: [PATCH] Compression dictionaries for JSONB
Previous Message Andres Freund 2023-02-06 19:24:01 Re: Pluggable toaster