Allow 5+ digit years for non-ISO timestamp/date strings, where appropriate
authorBruce Momjian <bruce@momjian.us>
Wed, 16 Oct 2013 17:22:55 +0000 (13:22 -0400)
committerBruce Momjian <bruce@momjian.us>
Wed, 16 Oct 2013 17:22:55 +0000 (13:22 -0400)
Report from Haribabu Kommi

src/backend/utils/adt/datetime.c
src/test/regress/expected/timestamptz.out
src/test/regress/sql/timestamptz.sql

index f39353f3614ab4bafcf722aa40219b7f76639e5f..48bf3db9b2c896f1690e488741b74bd2d9ca4d67 100644 (file)
@@ -1161,7 +1161,17 @@ DecodeDateTime(char **field, int *ftype, int nf,
                                                if (dterr < 0)
                                                        return dterr;
                                        }
-                                       else if (flen > 4)
+                                       /*
+                                        * Is this a YMD or HMS specification, or a year number?
+                                        * YMD and HMS are required to be six digits or more, so
+                                        * if it is 5 digits, it is a year.  If it is six or more
+                                        * more digits, we assume it is YMD or HMS unless no date
+                                        * and no time values have been specified.  This forces
+                                        * 6+ digit years to be at the end of the string, or to use
+                                        * the ISO date specification.
+                                        */
+                                       else if (flen >= 6 && (!(fmask & DTK_DATE_M) ||
+                                                        !(fmask & DTK_TIME_M)))
                                        {
                                                dterr = DecodeNumberField(flen, field[i], fmask,
                                                                                                  &tmask, tm,
@@ -2647,29 +2657,20 @@ DecodeNumberField(int len, char *str, int fmask,
        /* No decimal point and no complete date yet? */
        else if ((fmask & DTK_DATE_M) != DTK_DATE_M)
        {
-               /* yyyymmdd? */
-               if (len == 8)
-               {
-                       *tmask = DTK_DATE_M;
-
-                       tm->tm_mday = atoi(str + 6);
-                       *(str + 6) = '\0';
-                       tm->tm_mon = atoi(str + 4);
-                       *(str + 4) = '\0';
-                       tm->tm_year = atoi(str + 0);
-
-                       return DTK_DATE;
-               }
-               /* yymmdd? */
-               else if (len == 6)
+               if (len >= 6)
                {
                        *tmask = DTK_DATE_M;
-                       tm->tm_mday = atoi(str + 4);
-                       *(str + 4) = '\0';
-                       tm->tm_mon = atoi(str + 2);
-                       *(str + 2) = '\0';
-                       tm->tm_year = atoi(str + 0);
-                       *is2digits = TRUE;
+                       /*
+                        * Start from end and consider first 2 as Day, next 2 as Month,
+                        * and the rest as Year.
+                        */
+                       tm->tm_mday = atoi(str + (len - 2));
+                       *(str + (len - 2)) = '\0';
+                       tm->tm_mon = atoi(str + (len - 4));
+                       *(str + (len - 4)) = '\0';
+                       tm->tm_year = atoi(str);
+                       if ((len - 4) == 2)
+                               *is2digits = TRUE;
 
                        return DTK_DATE;
                }
@@ -2686,7 +2687,7 @@ DecodeNumberField(int len, char *str, int fmask,
                        *(str + 4) = '\0';
                        tm->tm_min = atoi(str + 2);
                        *(str + 2) = '\0';
-                       tm->tm_hour = atoi(str + 0);
+                       tm->tm_hour = atoi(str);
 
                        return DTK_TIME;
                }
@@ -2697,7 +2698,7 @@ DecodeNumberField(int len, char *str, int fmask,
                        tm->tm_sec = 0;
                        tm->tm_min = atoi(str + 2);
                        *(str + 2) = '\0';
-                       tm->tm_hour = atoi(str + 0);
+                       tm->tm_hour = atoi(str);
 
                        return DTK_TIME;
                }
index 6581b5e6a9758252c74b6bd1e0f7de4cf89162db..9f4f7a495a02cf73ac4208fe2e5cfb0a647e34c8 100644 (file)
@@ -1675,3 +1675,25 @@ SELECT '' AS to_char_11, to_char(d1, 'FMIYYY FMIYY FMIY FMI FMIW FMIDDD FMID')
             | 2001 1 1 1 1 1 1
 (66 rows)
 
+CREATE TABLE TIMESTAMPTZ_TST (a int , b timestamptz);
+-- Test year field value with len > 4
+INSERT INTO TIMESTAMPTZ_TST VALUES(1, 'Sat Mar 12 23:58:48 1000 IST');
+INSERT INTO TIMESTAMPTZ_TST VALUES(2, 'Sat Mar 12 23:58:48 10000 IST');
+INSERT INTO TIMESTAMPTZ_TST VALUES(3, 'Sat Mar 12 23:58:48 100000 IST');
+INSERT INTO TIMESTAMPTZ_TST VALUES(3, '10000 Mar 12 23:58:48 IST');
+INSERT INTO TIMESTAMPTZ_TST VALUES(4, '100000312 23:58:48 IST');
+INSERT INTO TIMESTAMPTZ_TST VALUES(4, '1000000312 23:58:48 IST');
+--Verify data
+SELECT * FROM TIMESTAMPTZ_TST ORDER BY a;
+ a |               b                
+---+--------------------------------
+ 1 | Wed Mar 12 13:58:48 1000 PST
+ 2 | Sun Mar 12 14:58:48 10000 PDT
+ 3 | Sun Mar 12 14:58:48 100000 PDT
+ 3 | Sun Mar 12 14:58:48 10000 PDT
+ 4 | Sun Mar 12 14:58:48 10000 PDT
+ 4 | Sun Mar 12 14:58:48 100000 PDT
+(6 rows)
+
+--Cleanup
+DROP TABLE TIMESTAMPTZ_TST;
index 863b2865cb50c0d371faf1bf6b5c49f908270b9c..4eef62e99afa7c52938b7630204e603d24a4ee7c 100644 (file)
@@ -240,3 +240,17 @@ SELECT '' AS to_char_10, to_char(d1, 'IYYY IYY IY I IW IDDD ID')
 
 SELECT '' AS to_char_11, to_char(d1, 'FMIYYY FMIYY FMIY FMI FMIW FMIDDD FMID')
    FROM TIMESTAMPTZ_TBL;
+
+CREATE TABLE TIMESTAMPTZ_TST (a int , b timestamptz);
+
+-- Test year field value with len > 4
+INSERT INTO TIMESTAMPTZ_TST VALUES(1, 'Sat Mar 12 23:58:48 1000 IST');
+INSERT INTO TIMESTAMPTZ_TST VALUES(2, 'Sat Mar 12 23:58:48 10000 IST');
+INSERT INTO TIMESTAMPTZ_TST VALUES(3, 'Sat Mar 12 23:58:48 100000 IST');
+INSERT INTO TIMESTAMPTZ_TST VALUES(3, '10000 Mar 12 23:58:48 IST');
+INSERT INTO TIMESTAMPTZ_TST VALUES(4, '100000312 23:58:48 IST');
+INSERT INTO TIMESTAMPTZ_TST VALUES(4, '1000000312 23:58:48 IST');
+--Verify data
+SELECT * FROM TIMESTAMPTZ_TST ORDER BY a;
+--Cleanup
+DROP TABLE TIMESTAMPTZ_TST;