patch for 60 seconds bug - Mailing list pgsql-patches

From Joseph Shraibman
Subject patch for 60 seconds bug
Date
Msg-id 3B7B2DEC.4070700@selectacast.net
Whole thread Raw
Responses Re: patch for 60 seconds bug
List pgsql-patches
This patch fixes the problem of doing:
select '2001-08-15 23:59:59.996'::timestamp;

... and getting a string with 60 in the seconds field.  This only fixes the method
EncodeDateTime(), the fix should be applied to EncodeTimeOnly() as well. (I didn't do it
because I thought that you might want to make this prettier before applying).

I was afraid to modify the fields in the passed in tm object.  Logically since it is only
output by this method even if internally it was changed it would have to go through this
method again to be output anyway, but I didn't want to mess with it.

This should be in the next 7.1.x release so when people dump from 7.1 to upgrade to 7.2
they won't have invalid data.


Interestingly:
  select '2001-08-15 23:59:59.995'::timestamp;
use to output:
  2001-08-15 23:59:59.99-04
on my system before I made this change.  Is this the result of some funkiness in my libc?
  I'm using a redhat 6.2ish system with glibc 2.1.3











*** datetime.c.orig    Wed Aug 15 21:00:05 2001
--- datetime.c    Wed Aug 15 22:05:56 2001
***************
*** 2080,2086 ****
   {
       int
    day,

    hour,
!
        min;
       double        sec;

       if ((tm->tm_mon < 1) || (tm->tm_mon > 12))
--- 2080,2091 ----
   {
       int
    day,

    hour,
!
        min,
!                 tmyear,
!                 tmmon,
!                 tmmday,
!                 tmhour,
!                 tmmin;
       double        sec;

       if ((tm->tm_mon < 1) || (tm->tm_mon > 12))
***************
*** 2088,2093 ****
--- 2093,2126 ----

       sec = (tm->tm_sec + fsec);

+     /* code to round the datetime so outputs with 60 seconds dont happen
+     I don't want to modify the tm values bec. I don't know if there would be side affects
+     so I created seperate variables.
+     I left BC dates alone.
+     */
+     tmyear = tm->tm_year;
+     tmmon =  tm->tm_mon;
+     tmmday = tm->tm_mday;
+     tmhour = tm->tm_hour;
+     tmmin = tm->tm_min;
+     if (sec >= 59.995){
+         sec = 0;
+         if (++tmmin > 59){
+
    tmmin = 0;
+
    if (++tmhour > 23){
+
        tmhour = 0;
+
        if (++tmmday > day_tab[isleap(tmyear)][tmmon - 1]){
+
            tmmday = 1;
+
            if (++tmmon > 12){
+
                tmmon = 1;
+
                tmyear++;/* what about BC? */
+
            }
+
        }
+
    }
+         }
+     };
+
+
       switch (style)
       {
               /* compatible with ISO date formats */
***************
*** 2096,2102 ****
               if (tm->tm_year > 0)
               {

    sprintf(str, "%04d-%02d-%02d %02d:%02d:",
!
                tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);

    sprintf((str + strlen(str)), ((fsec != 0) ? "%05.2f" : "%02.0f"), sec);


    if ((*tzn != NULL) && (tm->tm_isdst >= 0))
--- 2129,2135 ----
               if (tm->tm_year > 0)
               {

    sprintf(str, "%04d-%02d-%02d %02d:%02d:",
!
                tmyear, tmmon, tmmday, tmhour, tmmin);

    sprintf((str + strlen(str)), ((fsec != 0) ? "%05.2f" : "%02.0f"), sec);


    if ((*tzn != NULL) && (tm->tm_isdst >= 0))
***************
*** 2129,2158 ****
               /* compatible with Oracle/Ingres date formats */
           case USE_SQL_DATES:
               if (EuroDates)
!
        sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
               else
!
        sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);

               if (tm->tm_year > 0)
               {

    sprintf((str + 5), "/%04d %02d:%02d:%05.2f",
!
                tm->tm_year, tm->tm_hour, tm->tm_min, sec);


    if ((*tzn != NULL) && (tm->tm_isdst >= 0))

        sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
               }
               else

    sprintf((str + 5), "/%04d %02d:%02d %s",
!
              -(tm->tm_year - 1), tm->tm_hour, tm->tm_min, "BC");
               break;

               /* German variant on European style */
           case USE_GERMAN_DATES:
!
    sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
               if (tm->tm_year > 0)
               {

    sprintf((str + 5), ".%04d %02d:%02d:%05.2f",
!
                tm->tm_year, tm->tm_hour, tm->tm_min, sec);


    if ((*tzn != NULL) && (tm->tm_isdst >= 0))

        sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
--- 2162,2191 ----
               /* compatible with Oracle/Ingres date formats */
           case USE_SQL_DATES:
               if (EuroDates)
!
        sprintf(str, "%02d/%02d", tmmday, tmmon);
               else
!
        sprintf(str, "%02d/%02d", tmmon, tmmday);

               if (tm->tm_year > 0)
               {

    sprintf((str + 5), "/%04d %02d:%02d:%05.2f",
!
                tmyear, tmhour, tmmin, sec);


    if ((*tzn != NULL) && (tm->tm_isdst >= 0))

        sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
               }
               else

    sprintf((str + 5), "/%04d %02d:%02d %s",
!
              -(tm->tm_year - 1), tmhour, tmmin, "BC");
               break;

               /* German variant on European style */
           case USE_GERMAN_DATES:
!
    sprintf(str, "%02d.%02d", tmmday, tmmon);
               if (tm->tm_year > 0)
               {

    sprintf((str + 5), ".%04d %02d:%02d:%05.2f",
!
                tmyear, tmhour, tmmin, sec);


    if ((*tzn != NULL) && (tm->tm_isdst >= 0))

        sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
***************
*** 2165,2193 ****
               /* backward-compatible with traditional Postgres abstime dates */
           case USE_POSTGRES_DATES:
           default:
!
    day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
               tm->tm_wday = j2day(day);

               strncpy(str, days[tm->tm_wday], 3);
               strcpy((str + 3), " ");

               if (EuroDates)
!
        sprintf((str + 4), "%02d %3s", tm->tm_mday, months[tm->tm_mon - 1]);
               else
!
        sprintf((str + 4), "%3s %02d", months[tm->tm_mon - 1], tm->tm_mday);

               if (tm->tm_year > 0)
               {
!
        sprintf((str + 10), " %02d:%02d", tm->tm_hour, tm->tm_min);

    if (fsec != 0)

    {
!
            sprintf((str + 16), ":%05.2f %04d", sec, tm->tm_year);

        if ((*tzn != NULL) && (tm->tm_isdst >= 0))

            sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);

    }

    else

    {
!
            sprintf((str + 16), ":%02.0f %04d", sec, tm->tm_year);

        if ((*tzn != NULL) && (tm->tm_isdst >= 0))

            sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);

    }
--- 2198,2226 ----
               /* backward-compatible with traditional Postgres abstime dates */
           case USE_POSTGRES_DATES:
           default:
!
    day = date2j(tmyear, tmmon, tmmday);
               tm->tm_wday = j2day(day);

               strncpy(str, days[tm->tm_wday], 3);
               strcpy((str + 3), " ");

               if (EuroDates)
!
        sprintf((str + 4), "%02d %3s", tmmday, months[tmmon - 1]);
               else
!
        sprintf((str + 4), "%3s %02d", months[tmmon - 1], tmmday);

               if (tm->tm_year > 0)
               {
!
        sprintf((str + 10), " %02d:%02d", tmhour, tmmin);

    if (fsec != 0)

    {
!
            sprintf((str + 16), ":%05.2f %04d", sec, tmyear);

        if ((*tzn != NULL) && (tm->tm_isdst >= 0))

            sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);

    }

    else

    {
!
            sprintf((str + 16), ":%02.0f %04d", sec, tmyear);

        if ((*tzn != NULL) && (tm->tm_isdst >= 0))

            sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);

    }
--
Joseph Shraibman
jks@selectacast.net
Increase signal to noise ratio.  http://www.targabot.com


pgsql-patches by date:

Previous
From: Vince Vielhaber
Date:
Subject: Re: Re: Proposal for encrypting pg_shadow passwords
Next
From: Tom Lane
Date:
Subject: Re: Re: Proposal for encrypting pg_shadow passwords