OSDN Git Service

Fix transposed arguments for typmod for one INTERVAL production.
authorThomas G. Lockhart <lockhart@fourpalms.org>
Sat, 20 Oct 2001 01:02:22 +0000 (01:02 +0000)
committerThomas G. Lockhart <lockhart@fourpalms.org>
Sat, 20 Oct 2001 01:02:22 +0000 (01:02 +0000)
Mask both typmod subfields for INTERVAL to avoid setting the high bit,
 per dire warning from Tom Lane.
Clear tmask for DTK_ISO_TIME case to avoid time zone troubles.
 Symptom reported by Tom Lane.
Clean up checking for valid time zone info in output routine.
 This should now work for both SQL99 and Unix-style time zones.
Put in explicit check for INTERVAL() typmod rounding to avoid accumulating
 cruft in the lower bits. Not sure that this helps, but we'll need to do
 something. The symptom is visible with a query like
 select interval(2) '10000 days 01:02:03.040506';
Regression tests are patched to repair the Tom Lane symptom, and all pass.

src/backend/parser/gram.y
src/backend/utils/adt/datetime.c
src/backend/utils/adt/nabstime.c
src/backend/utils/adt/timestamp.c
src/test/regress/expected/horology.out
src/test/regress/expected/timestamptz.out

index 59db3b1..4f5f5d6 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.264 2001/10/18 23:16:09 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.265 2001/10/20 01:02:14 thomas Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -887,13 +887,18 @@ zone_value:  Sconst
                | ConstInterval Sconst opt_interval
                        {
                                A_Const *n = (A_Const *) makeStringConst($2, $1);
-                               n->typename->typmod = (($3 << 16) | 0xFFFF);
+                               if ($3 != -1)
+                                       n->typename->typmod = (($3 << 16) | 0xFFFF);
                                $$ = (Node *)n;
                        }
                | ConstInterval '(' Iconst ')' Sconst opt_interval
                        {
                                A_Const *n = (A_Const *) makeStringConst($5, $1);
-                               n->typename->typmod = (($3 << 16) | $6);
+                               if ($6 != -1)
+                                       n->typename->typmod = (($6 << 16) | $3);
+                               else
+                                       n->typename->typmod = ((0x7FFF << 16) | $3);
+
                                $$ = (Node *)n;
                        }
                | FCONST
@@ -4044,12 +4049,13 @@ SimpleTypename:  ConstTypename
                | ConstInterval opt_interval
                                {
                                        $$ = $1;
-                                       $$->typmod = (($2 << 16) | 0xFFFF);
+                                       if ($2 != -1)
+                                               $$->typmod = ((($2 & 0x7FFF) << 16) | 0xFFFF);
                                }
                | ConstInterval '(' Iconst ')' opt_interval
                                {
                                        $$ = $1;
-                                       $$->typmod = (($5 << 16) | $3);
+                                       $$->typmod = ((($5 & 0x7FFF) << 16) | $3);
                                }
                ;
 
@@ -5625,7 +5631,9 @@ AexprConst:  Iconst
                                        n->typename = $1;
                                        n->val.type = T_String;
                                        n->val.val.str = $2;
-                                       n->typename->typmod = (($3 << 16) | 0xFFFF);
+                                       /* precision is not specified, but fields may be... */
+                                       if ($3 != -1)
+                                               n->typename->typmod = ((($3 & 0x7FFF) << 16) | 0xFFFF);
                                        $$ = (Node *)n;
                                }
                | ConstInterval '(' Iconst ')' Sconst opt_interval
@@ -5634,7 +5642,9 @@ AexprConst:  Iconst
                                        n->typename = $1;
                                        n->val.type = T_String;
                                        n->val.val.str = $5;
-                                       n->typename->typmod = (($6 << 16) | $3);
+                                       /* precision specified, and fields may be... */
+                                       n->typename->typmod = ((($6 & 0x7FFF) << 16) | $3);
+
                                        $$ = (Node *)n;
                                }
                | ParamNo
index 2752319..6d6fbd6 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.73 2001/10/18 17:30:15 thomas Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.74 2001/10/20 01:02:18 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -385,17 +385,22 @@ j2day(int date)
 }      /* j2day() */
 
 
+/* TrimTrailingZeros()
+ * ... resulting from printing numbers with full precision.
+ */
 void
 TrimTrailingZeros(char *str)
 {
        int len = strlen(str);
 
+#if 0
        /* chop off trailing one to cope with interval rounding */
        if (strcmp((str + len - 4), "0001") == 0)
        {
                len -= 4;
                *(str + len) = '\0';
        }
+#endif
 
        /* chop off trailing zeros... */
        while ((*(str + len - 1) == '0')
@@ -905,11 +910,12 @@ DecodeDateTime(char **field, int *ftype, int nf,
                                                break;
 
                                        case UNITS:
-                                               ptype = val;
                                                tmask = 0;
+                                               ptype = val;
                                                break;
 
                                        case DTK_ISO_TIME:
+                                               tmask = 0;
                                                if ((i < 1) || (i >= (nf-1))
                                                        || (ftype[i-1] != DTK_DATE)
                                                        || (ftype[i+1] != DTK_TIME))
@@ -2267,10 +2273,10 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha
                                }
 
                                /* tzp == NULL indicates that we don't want *any* time zone info in the output string.
-                                * *tzn != NULL indicates that we *have* time zone info available.
+                                * *tzn != NULL indicates that we have alpha time zone info available.
                                 * tm_isdst != -1 indicates that we have a valid time zone translation.
                                 */
-                               if ((tzp != NULL) && (*tzn != NULL) && (tm->tm_isdst >= 0))
+                               if ((tzp != NULL) && (tm->tm_isdst >= 0))
                                {
                                        hour = -(*tzp / 3600);
                                        min = ((abs(*tzp) / 60) % 60);
@@ -2315,14 +2321,18 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha
                                        sprintf((str + strlen(str)), ":%02.0f", sec);
                                }
 
-                               if ((*tzn != NULL) && (tm->tm_isdst >= 0))
-                                       sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
-
-                               else if (tzp != NULL)
+                               if ((tzp != NULL) && (tm->tm_isdst >= 0))
                                {
-                                       hour = -(*tzp / 3600);
-                                       min = ((abs(*tzp) / 60) % 60);
-                                       sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
+                                       if (*tzn != NULL)
+                                       {
+                                               sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
+                                       }
+                                       else
+                                       {
+                                               hour = -(*tzp / 3600);
+                                               min = ((abs(*tzp) / 60) % 60);
+                                               sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
+                                       }
                                }
                        }
                        else
@@ -2353,14 +2363,18 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha
                                        sprintf((str + strlen(str)), ":%02.0f", sec);
                                }
 
-                               if ((*tzn != NULL) && (tm->tm_isdst >= 0))
-                                       sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
-
-                               else if (tzp != NULL)
+                               if ((tzp != NULL) && (tm->tm_isdst >= 0))
                                {
-                                       hour = -(*tzp / 3600);
-                                       min = ((abs(*tzp) / 60) % 60);
-                                       sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
+                                       if (*tzn != NULL)
+                                       {
+                                               sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
+                                       }
+                                       else
+                                       {
+                                               hour = -(*tzp / 3600);
+                                               min = ((abs(*tzp) / 60) % 60);
+                                               sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
+                                       }
                                }
                        }
                        else
@@ -2403,14 +2417,23 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha
 
                                sprintf((str + strlen(str)), " %04d", tm->tm_year);
 
-                               if ((tzp != NULL) && (*tzn != NULL) && (tm->tm_isdst >= 0))
-                                       sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
-
-                               else if (HasCTZSet && (tzp != NULL))
+                               if ((tzp != NULL) && (tm->tm_isdst >= 0))
                                {
-                                       hour = -(*tzp / 3600);
-                                       min = ((abs(*tzp) / 60) % 60);
-                                       sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
+                                       if (*tzn != NULL)
+                                       {
+                                               sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
+                                       }
+                                       else
+                                       {
+                                               /* We have a time zone, but no string version.
+                                                * Use the numeric form, but be sure to include a leading space
+                                                * to avoid formatting something which would be rejected by the
+                                                * date/time parser later. - thomas 2001-10-19
+                                                */
+                                               hour = -(*tzp / 3600);
+                                               min = ((abs(*tzp) / 60) % 60);
+                                               sprintf((str + strlen(str)), ((min != 0) ? " %+03d:%02d" : " %+03d"), hour, min);
+                                       }
                                }
                        }
                        else
index 55642a1..29608aa 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.89 2001/10/18 19:52:03 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.90 2001/10/20 01:02:18 thomas Exp $
  *
  * NOTES
  *
@@ -256,7 +256,7 @@ GetCurrentAbsoluteTimeUsec(int *usec)
        };
 
        return (AbsoluteTime) now;
-}      /* GetCurrentAbsoluteTime() */
+}      /* GetCurrentAbsoluteTimeUsec() */
 
 
 void
@@ -344,7 +344,7 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char **tzn)
                {
                        *tzp = CTimeZone;
                        tm->tm_gmtoff = CTimeZone;
-                       tm->tm_isdst = -1;
+                       tm->tm_isdst = 0;
                        tm->tm_zone = NULL;
                        if (tzn != NULL)
                                *tzn = NULL;
@@ -366,6 +366,10 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char **tzn)
                        }
                }
        }
+       else
+       {
+               tm->tm_isdst = -1;
+       }
 #elif defined(HAVE_INT_TIMEZONE)
        if (tzp != NULL)
        {
@@ -376,7 +380,7 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char **tzn)
                if (HasCTZSet)
                {
                        *tzp = CTimeZone;
-                       tm->tm_isdst = -1;
+                       tm->tm_isdst = 0;
                        if (tzn != NULL)
                                *tzn = NULL;
                }
@@ -397,6 +401,10 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char **tzn)
                        }
                }
        }
+       else
+       {
+               tm->tm_isdst = -1;
+       }
 #endif
 #else                                                  /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
        if (tzp != NULL)
@@ -426,6 +434,10 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char **tzn)
                        }
                }
        }
+       else
+       {
+               tm->tm_isdst = -1;
+       }
 #endif
 
        return;
index efe4a50..f39e85b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.57 2001/10/18 19:54:59 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.58 2001/10/20 01:02:18 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -374,14 +374,14 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
 {
        if (typmod != -1)
        {
-               int range = ((typmod >> 16) & 0xFFFF);
+               int range = ((typmod >> 16) & 0x7FFF);
                int precision = (typmod & 0xFFFF);
 
-               if (range == 0xFFFF)
+               if (range == 0x7FFF)
                {
                        /* Do nothing... */
                }
-               if (range == MASK(YEAR))
+               else if (range == MASK(YEAR))
                {
                        interval->month = ((interval->month / 12) * 12);
                        interval->time = 0;
@@ -483,7 +483,18 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
                                IntervalScale = pow(10.0, IntervalTypmod);
                        }
 
-                       interval->time = (rint(interval->time * IntervalScale) / IntervalScale);
+                       /* Hmm. For the time field, we can get to a large value
+                        * since we store everything related to an absolute interval
+                        * (e.g. years worth of days) in this one field. So we have
+                        * precision problems doing rint() on this field if the field
+                        * is too large. This resulted in an annoying "...0001" appended
+                        * to the printed result on my Linux box.
+                        * I hate doing an expensive math operation like log10()
+                        * to avoid this, but what else can we do??
+                        * - thomas 2001-10-19
+                        */
+                       if ((log10(interval->time) + IntervalTypmod) <= 13)
+                               interval->time = (rint(interval->time * IntervalScale) / IntervalScale);
                }
        }
 
@@ -671,14 +682,15 @@ timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, double *fsec, char **tzn)
                else
                {
                        *tzp = 0;
-                       tm->tm_isdst = 0;
+                       /* Mark this as *no* time zone available */
+                       tm->tm_isdst = -1;
                        if (tzn != NULL)
                                *tzn = NULL;
                }
        }
        else
        {
-               tm->tm_isdst = 0;
+               tm->tm_isdst = -1;
                if (tzn != NULL)
                        *tzn = NULL;
        }
index c0dec19..f911fc3 100644 (file)
@@ -359,7 +359,7 @@ SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMPTZ_TBL;
     | Tue Feb 10 17:32:01 1998 PST
     | Tue Feb 10 17:32:01 1998 PST
     | Wed Jun 10 17:32:01 1998 PDT
-    | Sun Sep 22 11:19:20 2002 PDT
+    | Sun Sep 22 18:19:20 2002 PDT
     | Thu Mar 15 08:14:01 2001 PST
     | Thu Mar 15 04:14:02 2001 PST
     | Thu Mar 15 02:14:03 2001 PST
@@ -428,7 +428,7 @@ SELECT '' AS "64", d1 - interval '1 year' AS one_year FROM TIMESTAMPTZ_TBL;
     | Sat Feb 10 17:32:01 1996 PST
     | Sat Feb 10 17:32:01 1996 PST
     | Mon Jun 10 17:32:01 1996 PDT
-    | Fri Sep 22 11:19:20 2000 PDT
+    | Fri Sep 22 18:19:20 2000 PDT
     | Mon Mar 15 08:14:01 1999 PST
     | Mon Mar 15 04:14:02 1999 PST
     | Mon Mar 15 02:14:03 1999 PST
index dd7ef75..70325aa 100644 (file)
@@ -152,7 +152,7 @@ SELECT '' AS "64", d1 FROM TIMESTAMPTZ_TBL;
     | Mon Feb 10 17:32:01 1997 PST
     | Mon Feb 10 17:32:01 1997 PST
     | Tue Jun 10 17:32:01 1997 PDT
-    | Sat Sep 22 11:19:20 2001 PDT
+    | Sat Sep 22 18:19:20 2001 PDT
     | Wed Mar 15 08:14:01 2000 PST
     | Wed Mar 15 04:14:02 2000 PST
     | Wed Mar 15 02:14:03 2000 PST
@@ -220,7 +220,7 @@ SELECT '' AS "48", d1 FROM TIMESTAMPTZ_TBL
     | Mon Feb 10 17:32:01 1997 PST
     | Mon Feb 10 17:32:01 1997 PST
     | Tue Jun 10 17:32:01 1997 PDT
-    | Sat Sep 22 11:19:20 2001 PDT
+    | Sat Sep 22 18:19:20 2001 PDT
     | Wed Mar 15 08:14:01 2000 PST
     | Wed Mar 15 04:14:02 2000 PST
     | Wed Mar 15 02:14:03 2000 PST
@@ -304,7 +304,7 @@ SELECT '' AS "63", d1 FROM TIMESTAMPTZ_TBL
     | Mon Feb 10 17:32:01 1997 PST
     | Mon Feb 10 17:32:01 1997 PST
     | Tue Jun 10 17:32:01 1997 PDT
-    | Sat Sep 22 11:19:20 2001 PDT
+    | Sat Sep 22 18:19:20 2001 PDT
     | Wed Mar 15 08:14:01 2000 PST
     | Wed Mar 15 04:14:02 2000 PST
     | Wed Mar 15 02:14:03 2000 PST
@@ -394,7 +394,7 @@ SELECT '' AS "49", d1 FROM TIMESTAMPTZ_TBL
     | Mon Feb 10 17:32:01 1997 PST
     | Mon Feb 10 17:32:01 1997 PST
     | Tue Jun 10 17:32:01 1997 PDT
-    | Sat Sep 22 11:19:20 2001 PDT
+    | Sat Sep 22 18:19:20 2001 PDT
     | Wed Mar 15 08:14:01 2000 PST
     | Wed Mar 15 04:14:02 2000 PST
     | Wed Mar 15 02:14:03 2000 PST
@@ -449,7 +449,7 @@ SELECT '' AS "54", d1 - timestamp with time zone '1997-01-02' AS diff
     | @ 39 days 17 hours 32 mins 1 sec
     | @ 39 days 17 hours 32 mins 1 sec
     | @ 159 days 16 hours 32 mins 1 sec
-    | @ 1724 days 10 hours 19 mins 20 secs
+    | @ 1724 days 17 hours 19 mins 20 secs
     | @ 1168 days 8 hours 14 mins 1 sec
     | @ 1168 days 4 hours 14 mins 2 secs
     | @ 1168 days 2 hours 14 mins 3 secs
@@ -511,7 +511,7 @@ SELECT '' AS "54", d1 - timestamp with time zone '1997-01-02' AS diff
     | @ 39 days 17 hours 32 mins 1 sec
     | @ 39 days 17 hours 32 mins 1 sec
     | @ 159 days 16 hours 32 mins 1 sec
-    | @ 1724 days 10 hours 19 mins 20 secs
+    | @ 1724 days 17 hours 19 mins 20 secs
     | @ 1168 days 8 hours 14 mins 1 sec
     | @ 1168 days 4 hours 14 mins 2 secs
     | @ 1168 days 2 hours 14 mins 3 secs
@@ -574,7 +574,7 @@ SELECT '' AS "54", d1 as timestamptz,
     | Mon Feb 10 17:32:01 1997 PST    | 1997 |     2 |  10 |   17 |     32 |      1
     | Mon Feb 10 17:32:01 1997 PST    | 1997 |     2 |  10 |   17 |     32 |      1
     | Tue Jun 10 17:32:01 1997 PDT    | 1997 |     6 |  10 |   17 |     32 |      1
-    | Sat Sep 22 11:19:20 2001 PDT    | 2001 |     9 |  22 |   11 |     19 |     20
+    | Sat Sep 22 18:19:20 2001 PDT    | 2001 |     9 |  22 |   18 |     19 |     20
     | Wed Mar 15 08:14:01 2000 PST    | 2000 |     3 |  15 |    8 |     14 |      1
     | Wed Mar 15 04:14:02 2000 PST    | 2000 |     3 |  15 |    4 |     14 |      2
     | Wed Mar 15 02:14:03 2000 PST    | 2000 |     3 |  15 |    2 |     14 |      3
@@ -636,7 +636,7 @@ SELECT '' AS "54", d1 as timestamptz,
     | Mon Feb 10 17:32:01 1997 PST    |       1 |    0 |      0
     | Mon Feb 10 17:32:01 1997 PST    |       1 |    0 |      0
     | Tue Jun 10 17:32:01 1997 PDT    |       2 |    0 |      0
-    | Sat Sep 22 11:19:20 2001 PDT    |       3 |    0 |      0
+    | Sat Sep 22 18:19:20 2001 PDT    |       3 |    0 |      0
     | Wed Mar 15 08:14:01 2000 PST    |       1 |    0 |      0
     | Wed Mar 15 04:14:02 2000 PST    |       1 |    0 |      0
     | Wed Mar 15 02:14:03 2000 PST    |       1 |    0 |      0
@@ -982,7 +982,7 @@ SELECT '' AS to_char_5, to_char(d1, 'HH HH12 HH24 MI SS SSSS')
            | 05 05 17 32 01 63121
            | 05 05 17 32 01 63121
            | 05 05 17 32 01 63121
-           | 11 11 11 19 20 40760
+           | 06 06 18 19 20 65960
            | 08 08 08 14 01 29641
            | 04 04 04 14 02 15242
            | 02 02 02 14 03 8043
@@ -1052,7 +1052,7 @@ SELECT '' AS to_char_6, to_char(d1, '"HH:MI:SS is" HH:MI:SS "\\"text between quo
            | HH:MI:SS is 05:32:01 "text between quote marks"
            | HH:MI:SS is 05:32:01 "text between quote marks"
            | HH:MI:SS is 05:32:01 "text between quote marks"
-           | HH:MI:SS is 11:19:20 "text between quote marks"
+           | HH:MI:SS is 06:19:20 "text between quote marks"
            | HH:MI:SS is 08:14:01 "text between quote marks"
            | HH:MI:SS is 04:14:02 "text between quote marks"
            | HH:MI:SS is 02:14:03 "text between quote marks"
@@ -1123,7 +1123,7 @@ SELECT '' AS to_char_7, to_char(d1, 'HH24--text--MI--text--SS')
            | 17--text--32--text--01
            | 17--text--32--text--01
            | 17--text--32--text--01
-           | 11--text--19--text--20
+           | 18--text--19--text--20
            | 08--text--14--text--01
            | 04--text--14--text--02
            | 02--text--14--text--03
@@ -1264,7 +1264,7 @@ SELECT '' AS to_char_9, to_char(d1, 'YYYY A.D. YYYY a.d. YYYY bc HH:MI:SS P.M. H
            | 1997 A.D. 1997 a.d. 1997 ad 05:32:01 P.M. 05:32:01 p.m. 05:32:01 pm
            | 1997 A.D. 1997 a.d. 1997 ad 05:32:01 P.M. 05:32:01 p.m. 05:32:01 pm
            | 1997 A.D. 1997 a.d. 1997 ad 05:32:01 P.M. 05:32:01 p.m. 05:32:01 pm
-           | 2001 A.D. 2001 a.d. 2001 ad 11:19:20 A.M. 11:19:20 a.m. 11:19:20 am
+           | 2001 A.D. 2001 a.d. 2001 ad 06:19:20 P.M. 06:19:20 p.m. 06:19:20 pm
            | 2000 A.D. 2000 a.d. 2000 ad 08:14:01 A.M. 08:14:01 a.m. 08:14:01 am
            | 2000 A.D. 2000 a.d. 2000 ad 04:14:02 A.M. 04:14:02 a.m. 04:14:02 am
            | 2000 A.D. 2000 a.d. 2000 ad 02:14:03 A.M. 02:14:03 a.m. 02:14:03 am