'1 year' = '360 days' ????

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Ricardo Perez Lopez

    '1 year' = '360 days' ????

    Hello everyone:

    I'm a PostgreSQL newbie, working now with dates, times, timestamps and
    intervals.

    I have three questions about the above:

    FIRST:
    --------

    I have observed that, for PostgreSQL, one year is actually 360 days:

    SELECT '1 year'::timestam p = '360 days'::timestam p;

    ?column?
    -------------
    t


    Glubs! I believed that 1 year is 365 days, or 366 if leap. Is it normal?


    SECOND:
    -----------

    When I want to check how many time is between two dates, I have two options
    (which shows two different results):

    SELECT '30-09-04'::timestamp - '30-09-03'::timestamp,
    age('30-09-04'::timestamp, '30-09-03'::timestamp) ;

    ?column? | age
    -------------------------------
    @ 366 days | @ 1 year


    The results are different. If we compare the two results:

    SELECT ('30-09-04'::timestamp - '30-09-03'::timestamp) =
    age('30-09-04'::timestamp, '30-09-03'::timestamp) ;


    ?column?
    --------------
    f


    Obviously, it returns False, because I told in the first question, 1 year is
    360 days for PostgreSQL.

    The question is: is it normal? Which of the two methods is the correct? To
    substract timestamps? Or to use the age function?


    THIRD:
    --------

    As I told in the second question, when I do:

    SELECT '30-09-04'::timestamp - '30-09-03'::timestamp;

    the result is:

    ?column?
    --------------
    @ 366 days

    The question is: is there any way to "normalize" the result, such that the
    result was:

    @ 1 year 1 day

    ?

    I think it's better (and more correct) "@ 1 year 1 day" rather than "@ 366
    days". Is there any way to achieve that?

    Thanks to all.

    Ricardo.

    _______________ _______________ _______________ _______________ _____
    Horóscopo, tarot, numerología... Escucha lo que te dicen los astros.



    ---------------------------(end of broadcast)---------------------------
    TIP 1: subscribe and unsubscribe commands go to majordomo@postg resql.org

  • Bruno Wolff III

    #2
    Re: '1 year' = '360 days' ????

    On Fri, Oct 22, 2004 at 13:37:19 +0200,
    Ricardo Perez Lopez <ricpelo@hotmai l.com> wrote:[color=blue]
    > Hello everyone:
    >
    > I'm a PostgreSQL newbie, working now with dates, times, timestamps and
    > intervals.
    >
    > I have three questions about the above:
    >
    > FIRST:
    > --------
    >
    > I have observed that, for PostgreSQL, one year is actually 360 days:[/color]

    No it isn't. The interval is stored as months and seconds. When
    adding intervals to timestamps, adding months and adding seconds are
    handled differently. Under some circumstances the months part gets
    converted to seconds, and in that event a month is taken to be as
    long as 30 days.
    [color=blue]
    > SELECT '1 year'::timestam p = '360 days'::timestam p;
    >
    > ?column?
    > -------------
    > t
    >
    >
    > Glubs! I believed that 1 year is 365 days, or 366 if leap. Is it normal?
    >
    >
    > SECOND:
    > -----------
    >
    > When I want to check how many time is between two dates, I have two options
    > (which shows two different results):
    >
    > SELECT '30-09-04'::timestamp - '30-09-03'::timestamp,
    > age('30-09-04'::timestamp, '30-09-03'::timestamp) ;
    >
    > ?column? | age
    > -------------------------------
    > @ 366 days | @ 1 year
    >
    >
    > The results are different. If we compare the two results:
    >
    > SELECT ('30-09-04'::timestamp - '30-09-03'::timestamp) =
    > age('30-09-04'::timestamp, '30-09-03'::timestamp) ;
    >
    >
    > ?column?
    > --------------
    > f
    >
    >
    > Obviously, it returns False, because I told in the first question, 1 year
    > is 360 days for PostgreSQL.[/color]

    That isn't really why. When you use age you get an interval with a mix of month
    and seconds parts. If you subtract two timestamps then you get an interval
    with just a seconds part.
    [color=blue]
    >
    > The question is: is it normal? Which of the two methods is the correct? To
    > substract timestamps? Or to use the age function?
    >
    >
    > THIRD:
    > --------
    >
    > As I told in the second question, when I do:
    >
    > SELECT '30-09-04'::timestamp - '30-09-03'::timestamp;
    >
    > the result is:
    >
    > ?column?
    > --------------
    > @ 366 days
    >
    > The question is: is there any way to "normalize" the result, such that the
    > result was:
    >
    > @ 1 year 1 day[/color]

    Use age. If you do that, that is what the interval will look like internally.
    I don't think there is an easy way to output the value of an interval
    so that it looks like that. But if you use it in operations it should
    do what you want. (Though you need to consider whether you want the
    day added before or after you add the 12 months.)
    [color=blue]
    >
    > ?
    >
    > I think it's better (and more correct) "@ 1 year 1 day" rather than "@ 366
    > days". Is there any way to achieve that?
    >
    > Thanks to all.
    >
    > Ricardo.
    >
    > _______________ _______________ _______________ _______________ _____
    > Horóscopo, tarot, numerología... Escucha lo que te dicen los astros.
    > http://astrocentro.msn.es/
    >
    >
    > ---------------------------(end of broadcast)---------------------------
    > TIP 1: subscribe and unsubscribe commands go to majordomo@postg resql.org[/color]

    ---------------------------(end of broadcast)---------------------------
    TIP 3: if posting/reading through Usenet, please send an appropriate
    subscribe-nomail command to majordomo@postg resql.org so that your
    message can get through to the mailing list cleanly

    Comment

    • Tom Lane

      #3
      Re: '1 year' = '360 days' ????

      "Ricardo Perez Lopez" <ricpelo@hotmai l.com> writes:[color=blue]
      > I have observed that, for PostgreSQL, one year is actually 360 days:[/color]
      [color=blue]
      > SELECT '1 year'::timestam p = '360 days'::timestam p;[/color]
      [color=blue]
      > ?column?
      > -------------
      > t[/color]

      Nonsense.

      regression=# SELECT '1 year'::timestam p = '360 days'::timestam p;
      ERROR: invalid input syntax for type timestamp: "1 year"

      How about telling us what you *really* did, instead of posting faked
      examples?

      There are some contexts in which an interval (not a timestamp) of 1
      month will be taken as equivalent to 30 days, for lack of any better
      idea, but it's not the case that Postgres doesn't know the difference.

      regards, tom lane

      ---------------------------(end of broadcast)---------------------------
      TIP 5: Have you checked our extensive FAQ?



      Comment

      • Doug McNaught

        #4
        Re: '1 year' = '360 days' ????

        Tom Lane <tgl@sss.pgh.pa .us> writes:
        [color=blue]
        > "Ricardo Perez Lopez" <ricpelo@hotmai l.com> writes:[color=green]
        >> I have observed that, for PostgreSQL, one year is actually 360 days:[/color]
        >[color=green]
        >> SELECT '1 year'::timestam p = '360 days'::timestam p;[/color]
        >[color=green]
        >> ?column?
        >> -------------
        >> t[/color]
        >
        > Nonsense.
        >
        > regression=# SELECT '1 year'::timestam p = '360 days'::timestam p;
        > ERROR: invalid input syntax for type timestamp: "1 year"
        >
        > How about telling us what you *really* did, instead of posting faked
        > examples?[/color]

        FWIW:

        template1=# select '1 year'::interval = '360 days'::interval ;
        ?column?
        ----------
        t
        (1 row)

        template1=# select '1 year'::interval = '365 days'::interval ;
        ?column?
        ----------
        f
        (1 row)

        template1=# select version();
        version
        ---------------------------------------------------------------------
        PostgreSQL 7.4.5 on i686-pc-linux-gnu, compiled by GCC egcs-2.91.66
        (1 row)

        -Doug

        ---------------------------(end of broadcast)---------------------------
        TIP 3: if posting/reading through Usenet, please send an appropriate
        subscribe-nomail command to majordomo@postg resql.org so that your
        message can get through to the mailing list cleanly

        Comment

        • Tom Lane

          #5
          Re: '1 year' = '360 days' ????

          Doug McNaught <doug@mcnaught. org> writes:[color=blue]
          > template1=# select '1 year'::interval = '360 days'::interval ;
          > ?column?
          > ----------
          > t
          > (1 row)[/color]

          Yeah, if you look at interval_cmp_in ternal() it's fairly obvious why.
          I think that this definition is probably bogus, and that only intervals
          that match exactly (equal months parts *and* equal seconds parts) should
          be considered "equal". However the most obvious way to redefine it
          (compare the months, and only if equal compare the seconds) would lead
          to rather nonintuitive behaviors such as "'1 year' > '1000 days'".
          Anybody have any thoughts about a better way to map the multicomponent
          reality into a one-dimensional sorting order?

          (Note also that as Bruno was just mentioning, we really ought to have
          months/days/seconds components, not just months/seconds; which makes the
          comparison issue even more interesting.)

          regards, tom lane

          ---------------------------(end of broadcast)---------------------------
          TIP 2: you can get off all lists at once with the unregister command
          (send "unregister YourEmailAddres sHere" to majordomo@postg resql.org)

          Comment

          • Bruno Wolff III

            #6
            Re: '1 year' = '360 days' ????

            On Sat, Oct 23, 2004 at 21:38:15 -0400,
            Tom Lane <tgl@sss.pgh.pa .us> wrote:[color=blue]
            > Doug McNaught <doug@mcnaught. org> writes:[color=green]
            > > template1=# select '1 year'::interval = '360 days'::interval ;
            > > ?column?
            > > ----------
            > > t
            > > (1 row)[/color]
            >
            > Yeah, if you look at interval_cmp_in ternal() it's fairly obvious why.
            > I think that this definition is probably bogus, and that only intervals
            > that match exactly (equal months parts *and* equal seconds parts) should
            > be considered "equal". However the most obvious way to redefine it
            > (compare the months, and only if equal compare the seconds) would lead
            > to rather nonintuitive behaviors such as "'1 year' > '1000 days'".
            > Anybody have any thoughts about a better way to map the multicomponent
            > reality into a one-dimensional sorting order?[/color]

            You could return NULL for cases where the number of months in the
            first interval is less than the second, but the number of seconds in
            the second interval is greater than the first.
            You could even tighten things down more by using that months have to
            be at least 28 days, but not more than 31 days (neglecting daylight
            savings time).
            If you want to be able to use a btree index, you need a total ordering, so
            in that case I think you have to have things work pretty much the way they do
            now, including the way the equality operator works.

            ---------------------------(end of broadcast)---------------------------
            TIP 1: subscribe and unsubscribe commands go to majordomo@postg resql.org

            Comment

            • Tom Lane

              #7
              Re: '1 year' = '360 days' ????

              Bruno Wolff III <bruno@wolff.to > writes:[color=blue]
              > Tom Lane <tgl@sss.pgh.pa .us> wrote:[color=green]
              >> Anybody have any thoughts about a better way to map the multicomponent
              >> reality into a one-dimensional sorting order?[/color][/color]
              [color=blue]
              > You could return NULL for cases where the number of months in the
              > first interval is less than the second, but the number of seconds in
              > the second interval is greater than the first.[/color]

              No, you can't, at least not if you want to have btree indexes on
              interval columns. The comparison operators can never return NULL
              for nonnull inputs.
              [color=blue]
              > If you want to be able to use a btree index, you need a total ordering, so
              > in that case I think you have to have things work pretty much the way they do
              > now, including the way the equality operator works.[/color]

              We don't have to have this particular sorting decision, we just have
              to have *some* unique sorting order. In particular, if we want to say
              that two interval values are not equal, we have to be able to say which
              one is less. For instance, "compare the months first and only if equal
              compare the seconds" would work fine from the point of view of btree.
              It's just that that leads to a sort order that users will probably not
              like very much.

              regards, tom lane

              ---------------------------(end of broadcast)---------------------------
              TIP 5: Have you checked our extensive FAQ?



              Comment

              • Bruno Wolff III

                #8
                Re: '1 year' = '360 days' ????

                On Sat, Oct 23, 2004 at 23:36:05 -0400,
                Tom Lane <tgl@sss.pgh.pa .us> wrote:[color=blue]
                >
                > We don't have to have this particular sorting decision, we just have
                > to have *some* unique sorting order. In particular, if we want to say
                > that two interval values are not equal, we have to be able to say which
                > one is less. For instance, "compare the months first and only if equal
                > compare the seconds" would work fine from the point of view of btree.
                > It's just that that leads to a sort order that users will probably not
                > like very much.[/color]

                One way to do comparisons is to use a mapping f(m,s) => R and compare
                (m1,s1) and (m2,s2) by comparing f(m1,s1) and f(m2,s2) and break ties
                by comparing say m1 and m2. This will work as long as f(m,s1) = f(m,s2)
                implies s1 = s2. It will probably be desirable to use a subset of these
                mappings where f(m,s) = g(m) + h(s). In fact the current system uses
                this with g(m) = 30*24*60*60*m and h(s) = s (but without the tiebreak
                that compares m values). Because of the way intervals work, I think
                you want to use an ordering generated like that you want to use
                something of the form f(m,s) = C1*m + C2*s. I also think that treating
                a month as 30 days and having round numbers is better than using
                something like 1/12 a solar year in seconds. So I think the best plan
                is to do things as they are now, except for adding a tie breaker just
                using months or seconds for when both intervals give the same number of
                seconds when treating months as 30 days, but have a different number of
                months.

                ---------------------------(end of broadcast)---------------------------
                TIP 9: the planner will ignore your desire to choose an index scan if your
                joining column's datatypes do not match

                Comment

                • Bruno Wolff III

                  #9
                  Re: '1 year' = '360 days' ????

                  On Sat, Oct 23, 2004 at 23:15:57 -0500,
                  Bruno Wolff III <bruno@wolff.to > wrote:[color=blue]
                  > by comparing say m1 and m2. This will work as long as f(m,s1) = f(m,s2)
                  > implies s1 = s2. It will probably be desirable to use a subset of these
                  > mappings where f(m,s) = g(m) + h(s). In fact the current system uses
                  > this with g(m) = 30*24*60*60*m and h(s) = s (but without the tiebreak
                  > that compares m values). Because of the way intervals work, I think
                  > you want to use an ordering generated like that you want to use
                  > something of the form f(m,s) = C1*m + C2*s. I also think that treating
                  > a month as 30 days and having round numbers is better than using
                  > something like 1/12 a solar year in seconds. So I think the best plan
                  > is to do things as they are now, except for adding a tie breaker just
                  > using months or seconds for when both intervals give the same number of
                  > seconds when treating months as 30 days, but have a different number of
                  > months.[/color]

                  Some more comments on this. I was thinking about it a bit more and using
                  1/12 of the number of seconds in a solar year doesn't seem that bad
                  for comparisons. That way 366 days > 1 year > 365 days. However, if you
                  go that route, I think you would also want to change EXTRACT so that
                  when you extract the EPOCH you use the same function as for comparison.
                  One value I found for a solar year is 365 days, 5 hours, 48 minutes, 45.51
                  seconds.

                  ---------------------------(end of broadcast)---------------------------
                  TIP 4: Don't 'kill -9' the postmaster

                  Comment

                  • Bruno Wolff III

                    #10
                    Re: '1 year' = '360 days' ????

                    On Sat, Oct 23, 2004 at 23:51:20 -0500,
                    Bruno Wolff III <bruno@wolff.to > wrote:[color=blue]
                    > One value I found for a solar year is 365 days, 5 hours, 48 minutes, 45.51
                    > seconds.[/color]

                    Wikipedia gives 365.242189670 days (86400 seconds) as the length of the
                    mean solar year in 2000. To give you some idea of how constant that values is,
                    Wikipedia claims that 2000 years ago the mean solar year was about 10 seconds
                    longer.
                    Using the above value I get there is an average of 2629743 seconds in a month.

                    And yet another option is to note that in the Gregorian calendar there are
                    400*365+97 days or 400*12 months in 400 years, which gives 2629746 seconds
                    per month on average.

                    ---------------------------(end of broadcast)---------------------------
                    TIP 6: Have you searched our list archives?



                    Comment

                    • Pierre-Frédéric Caillaud

                      #11
                      Re: '1 year' = '360 days' ????



                      problem is that '1 months':: interval does not have the same value if you
                      add it to a date or another :

                      => SELECT '2004-02-01'::timestamp+ '1 month'::interva l,
                      '2004-03-01'::timestamp+ '1 month'::interva l;
                      ?column? | ?column?
                      ---------------------+---------------------
                      2004-03-01 00:00:00 | 2004-04-01 00:00:00

                      SELECT '2004-03-01'::timestamp-'2004-02-01'::timestamp,
                      '2004-04-01'::timestamp-'2004-03-01'::timestamp;
                      ?column? | ?column?
                      ----------+----------
                      29 days | 31 days

                      That's because a month is an undefined number of days (also some years
                      are 366 days). In that case '1 months':: interval is either 29 or 31 days
                      but it could be 28 in february 2003 or 30 in april !

                      Thus if we have a date d and two intervals i1 and i2 :

                      The comparison (d+i1) < (d+i2) depends on the value of d (and the
                      timezone).
                      For instance if i1 is '1 month' and i2 is '30 days', we have :

                      SELECT '2004-02-01'::timestamp+ '1 month'::interva l,
                      '2004-02-01'::timestamp+ '30 days'::interval ;
                      ?column? | ?column?
                      ---------------------+---------------------
                      2004-03-01 00:00:00 | 2004-03-02 00:00:00

                      Thus (d+i1) < (d+i2)


                      SELECT '2004-04-01'::timestamp+ '1 month'::interva l,
                      '2004-04-01'::timestamp+ '30 days'::interval ;
                      ?column? | ?column?
                      ---------------------+---------------------
                      2004-05-01 00:00:00 | 2004-05-01 00:00:00

                      Thus (d+i1) = (d+i2)

                      SELECT '2004-03-01'::timestamp+ '1 month'::interva l,
                      '2004-03-01'::timestamp+ '30 days'::interval ;
                      ?column? | ?column?
                      ---------------------+---------------------
                      2004-04-01 00:00:00 | 2004-03-31 00:00:00

                      Thus (d+i1) > (d+i2)

                      And that's normal ! Intervals having months are extremely useful to
                      express the idea of 'same day, next month' that you can't do with just an
                      interval expressed in seconds. However, beware :

                      SELECT '2004-01-31'::timestamp+ '1 month'::interva l;
                      ?column?
                      ---------------------
                      2004-02-29 00:00:00
                      (1 ligne)

                      SELECT '2004-01-30'::timestamp+ '1 month'::interva l;
                      ?column?
                      ---------------------
                      2004-02-29 00:00:00
                      (1 ligne)

                      SELECT '2004-01-29'::timestamp+ '1 month'::interva l;
                      ?column?
                      ---------------------
                      2004-02-29 00:00:00
                      (1 ligne)

                      SELECT '2004-01-28'::timestamp+ '1 month'::interva l;
                      ?column?
                      ---------------------
                      2004-02-28 00:00:00


                      31 january + 1 month = 29 february (it clips at the end of the month,
                      which is IMHO GOOD).

                      How can we sort intervals meaningfully in these conditions ? Can we ? In
                      fact the value of an interval depends on the application, and intervals
                      with months are in another 'world' than intervals with only seconds...
                      same thing for years.

                      [color=blue]
                      >
                      > ---------------------------(end of broadcast)---------------------------
                      > TIP 6: Have you searched our list archives?
                      >
                      > http://archives.postgresql.org
                      >[/color]



                      ---------------------------(end of broadcast)---------------------------
                      TIP 6: Have you searched our list archives?



                      Comment

                      • Michael Glaesemann

                        #12
                        Re: '1 year' = '360 days' ????


                        On Oct 24, 2004, at 4:13 PM, Pierre-Frédéric Caillaud wrote:
                        [color=blue]
                        > How can we sort intervals meaningfully in these conditions ? Can we ?
                        > In fact the value of an interval depends on the application, and
                        > intervals with months are in another 'world' than intervals with only
                        > seconds... same thing for years.[/color]

                        Added to this, I've been wondering whether '1 day'::interval is also
                        problematic wrt daylight savings time or changing time zones. The whole
                        thing seems pretty hairy to me.

                        Michael Glaesemann
                        grzm myrealbox com


                        ---------------------------(end of broadcast)---------------------------
                        TIP 9: the planner will ignore your desire to choose an index scan if your
                        joining column's datatypes do not match

                        Comment

                        • Tom Lane

                          #13
                          Re: '1 year' = '360 days' ????

                          Michael Glaesemann <grzm@myrealbox .com> writes:[color=blue]
                          > Added to this, I've been wondering whether '1 day'::interval is also
                          > problematic wrt daylight savings time or changing time zones.[/color]

                          This is exactly the point I alluded to earlier: intervals need to have
                          three components (months, days, seconds) not just two. That's been on
                          the to-do list for quite awhile. All the other units we support for
                          intervals bear a fixed relationship to one or another of these, so
                          three is sufficient.

                          Question to think about: should we allow fractional months or days in
                          the stored representation? There are some places where the existing
                          restriction that the months field is an integer requires awkward
                          compromises. On the other hand, it's not real clear what a fractional
                          month actually means, and similarly a fractional day is hard to assign
                          meaning to without positing that 1 day == 24 hours.

                          regards, tom lane

                          ---------------------------(end of broadcast)---------------------------
                          TIP 4: Don't 'kill -9' the postmaster

                          Comment

                          • Bruno Wolff III

                            #14
                            Re: '1 year' = '360 days' ????

                            On Sun, Oct 24, 2004 at 11:29:13 -0400,
                            Tom Lane <tgl@sss.pgh.pa .us> wrote:[color=blue]
                            >
                            > Question to think about: should we allow fractional months or days in
                            > the stored representation? There are some places where the existing
                            > restriction that the months field is an integer requires awkward
                            > compromises. On the other hand, it's not real clear what a fractional
                            > month actually means, and similarly a fractional day is hard to assign
                            > meaning to without positing that 1 day == 24 hours.[/color]

                            There are reasonable addition and subtraction operation definitions
                            on two intervals. There might be some application where you want to
                            keep track of fractional months or days. What I am not sure of is
                            would you really have a reason to add fractional months or days
                            to a timestamp. There are a couple reasonable definitions you might
                            make for this definition, but I don't really see a good reason to
                            want this. ne thing to note, when adding intervals you can add the
                            fractions normally. When adding to a date you can get the actual length
                            of the day or month the fractional part adds to, if you wanted to use
                            that information. (Though the resulting day or month may not be the
                            one you added the fractional month to.)

                            I think starting with a type where months and days were integers would be
                            OK, since you could generalize it to handle fractional months and days
                            later and not break applications.

                            Another thing to think about when designing this type, is that when
                            adding timestamps and intervals it makes a difference in which order
                            you add the months, days and seconds.

                            ---------------------------(end of broadcast)---------------------------
                            TIP 3: if posting/reading through Usenet, please send an appropriate
                            subscribe-nomail command to majordomo@postg resql.org so that your
                            message can get through to the mailing list cleanly

                            Comment

                            • Tom Lane

                              #15
                              Re: '1 year' = '360 days' ????

                              Bruno Wolff III <bruno@wolff.to > writes:[color=blue]
                              > Wikipedia gives 365.242189670 days (86400 seconds) as the length of
                              > the mean solar year in 2000. To give you some idea of how constant
                              > that values is, Wikipedia claims that 2000 years ago the mean solar
                              > year was about 10 seconds longer. Using the above value I get there
                              > is an average of 2629743 seconds in a month.[/color]
                              [color=blue]
                              > And yet another option is to note that in the Gregorian calendar there are
                              > 400*365+97 days or 400*12 months in 400 years, which gives 2629746 seconds
                              > per month on average.[/color]

                              I like the latter approach, mainly because it gives a defensible
                              rationale for using a particular exact value. With the solar-year
                              approach there's no strong reason why you should use 2000 (or any other
                              particular year) as the reference; and any value you did use would be
                              subject to both roundoff and observational error. With the Gregorian
                              calendar as reference, 2629746 seconds is the *exact* answer, and it's
                              correct because the Pope says so ;-).

                              (Or, for the Protestants among us, it's correct because the SQL standard
                              specifies use of the Gregorian calendar.)

                              regards, tom lane

                              ---------------------------(end of broadcast)---------------------------
                              TIP 4: Don't 'kill -9' the postmaster

                              Comment

                              Working...