88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.54 2000/10/29 13:17:33 petere Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.55 2000/11/06 15:57:00 thomas Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -199,7 +199,11 @@ static datetkn datetktbl[] = {
199199{"pst" ,TZ ,NEG (48 )},/* Pacific Standard Time */
200200{"sadt" ,DTZ ,63 },/* S. Australian Dayl. Time */
201201{"sast" ,TZ ,57 },/* South Australian Std Time */
202+ #if USE_AUSTRALIAN_RULES
203+ {"sat" ,TZ ,57 },
204+ #else
202205{"sat" ,DOW ,6 },
206+ #endif
203207{"saturday" ,DOW ,6 },
204208{"sep" ,MONTH ,9 },
205209{"sept" ,MONTH ,9 },
@@ -218,8 +222,7 @@ static datetkn datetktbl[] = {
218222{"tue" ,DOW ,2 },
219223{"tues" ,DOW ,2 },
220224{"tuesday" ,DOW ,2 },
221- {"undefined" ,RESERV ,DTK_INVALID },/* "undefined" pre-v6.1 invalid
222- * time */
225+ {"undefined" ,RESERV ,DTK_INVALID },/* pre-v6.1 invalid time */
223226{"ut" ,TZ ,0 },
224227{"utc" ,TZ ,0 },
225228{"wadt" ,DTZ ,48 },/* West Australian DST */
@@ -235,10 +238,10 @@ static datetkn datetktbl[] = {
235238{"ydt" ,DTZ ,NEG (48 )},/* Yukon Daylight Time */
236239{YESTERDAY ,RESERV ,DTK_YESTERDAY },/* yesterday midnight */
237240{"yst" ,TZ ,NEG (54 )},/* Yukon Standard Time */
241+ {"z" ,RESERV ,DTK_ZULU },/* 00:00:00 */
238242{"zp4" ,TZ ,NEG (24 )},/* GMT +4 hours. */
239243{"zp5" ,TZ ,NEG (30 )},/* GMT +5 hours. */
240244{"zp6" ,TZ ,NEG (36 )},/* GMT +6 hours. */
241- {"z" ,RESERV ,DTK_ZULU },/* 00:00:00 */
242245{ZULU ,RESERV ,DTK_ZULU },/* 00:00:00 */
243246};
244247
@@ -466,25 +469,6 @@ ParseDateTime(char *timestr, char *lowstr,
466469 */
467470if ((* cp == '-' )|| (* cp == '/' )|| (* cp == '.' ))
468471{
469- #if 0
470-
471- /*
472- * special case of Posix timezone "GMT-0800" Note that
473- * other sign (e.g. "GMT+0800" is recognized as two
474- * separate fields and handled later. XXX There is no room
475- * for a delimiter between the "GMT" and the "-0800", so
476- * we are going to just swallow the "GMT". But this leads
477- * to other troubles with the definition of signs, so we
478- * have to flip - thomas 2000-02-06
479- */
480- if ((* cp == '-' )&& isdigit (* (cp + 1 ))
481- && (strncmp (field [nf ],"gmt" ,3 )== 0 ))
482- {
483- * cp = '+' ;
484- continue ;
485- }
486- #endif
487-
488472ftype [nf ]= DTK_DATE ;
489473while (isdigit ((int )* cp )|| (* cp == '-' )|| (* cp == '/' )|| (* cp == '.' ))
490474* lp ++ = tolower (* cp ++ );
@@ -1667,8 +1651,7 @@ DecodeDateDelta(char **field, int *ftype, int nf, int *dtype, struct tm * tm, do
16671651tmask ,
16681652type ;
16691653int i ;
1670- int flen ,
1671- val ;
1654+ int val ;
16721655double fval ;
16731656double sec ;
16741657
@@ -1695,14 +1678,40 @@ DecodeDateDelta(char **field, int *ftype, int nf, int *dtype, struct tm * tm, do
16951678break ;
16961679
16971680case DTK_TZ :
1698-
16991681/*
17001682 * Timezone is a token with a leading sign character and
1701- * otherwise the same as a non-signednumeric field
1683+ * otherwise the same as a non-signedtime field
17021684 */
1685+ Assert ((* field [i ]== '-' )|| (* field [i ]== '+' ));
1686+ /* A single signed number ends up here, but will be rejected by DecodeTime().
1687+ * So, work this out to drop through to DTK_NUMBER, which *can* tolerate this.
1688+ */
1689+ cp = field [i ]+ 1 ;
1690+ while ((* cp != '\0' )&& (* cp != ':' ))
1691+ cp ++ ;
1692+ if ((* cp == ':' )
1693+ && (DecodeTime ((field [i ]+ 1 ),fmask ,& tmask ,tm ,fsec )== 0 )) {
1694+ if (* field [i ]== '-' ) {
1695+ /* flip the sign on all fields */
1696+ tm -> tm_hour = - tm -> tm_hour ;
1697+ tm -> tm_min = - tm -> tm_min ;
1698+ tm -> tm_sec = - tm -> tm_sec ;
1699+ * fsec = - (* fsec );
1700+ }
1701+
1702+ /* Set the next type to be a day, if units are not specified.
1703+ * This handles the case of '1 +02:03' since we are reading right to left.
1704+ */
1705+ type = DTK_DAY ;
1706+ tmask = DTK_M (TZ );
1707+ break ;
1708+ }
1709+ /* DROP THROUGH */
1710+
17031711case DTK_DATE :
17041712case DTK_NUMBER :
17051713val = strtol (field [i ],& cp ,10 );
1714+
17061715if (* cp == '.' )
17071716{
17081717fval = strtod (cp ,& cp );
@@ -1717,7 +1726,6 @@ DecodeDateDelta(char **field, int *ftype, int nf, int *dtype, struct tm * tm, do
17171726else
17181727return -1 ;
17191728
1720- flen = strlen (field [i ]);
17211729tmask = 0 ;/* DTK_M(type); */
17221730
17231731switch (type )
@@ -2193,98 +2201,126 @@ EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str)
21932201int is_nonzero = FALSE;
21942202char * cp = str ;
21952203
2204+ /* The sign of year and month are guaranteed to match,
2205+ * since they are stored internally as "month".
2206+ * But we'll need to check for is_before and is_nonzero
2207+ * when determining the signs of hour/minute/seconds fields.
2208+ */
21962209switch (style )
21972210{
21982211/* compatible with ISO date formats */
21992212case USE_ISO_DATES :
2200- break ;
2201-
2202- default :
2203- strcpy (cp ,"@ " );
2204- cp += strlen (cp );
2205- break ;
2206- }
2207-
2208- if (tm -> tm_year != 0 )
2209- {
2210- is_before |= (tm -> tm_year < 0 );
2211- sprintf (cp ,"%d year%s" ,
2212- abs (tm -> tm_year ), ((abs (tm -> tm_year )!= 1 ) ?"s" :"" ));
2213- cp += strlen (cp );
2214- is_nonzero = TRUE;
2215- }
2216-
2217- if (tm -> tm_mon != 0 )
2218- {
2219- is_before |= (tm -> tm_mon < 0 );
2220- sprintf (cp ,"%s%d mon%s" , (is_nonzero ?" " :"" ),
2221- abs (tm -> tm_mon ), ((abs (tm -> tm_mon )!= 1 ) ?"s" :"" ));
2222- cp += strlen (cp );
2223- is_nonzero = TRUE;
2224- }
2225-
2226- switch (style )
2227- {
2228- /* compatible with ISO date formats */
2229- case USE_ISO_DATES :
2230- if (tm -> tm_mday != 0 )
2213+ if (tm -> tm_year != 0 )
22312214{
2232- is_before |= ( tm -> tm_mday < 0 );
2233- sprintf ( cp , "%s%d" , ( is_nonzero ?" " :"" ), abs ( tm -> tm_mday ));
2215+ sprintf ( cp , "%d year%s" ,
2216+ tm -> tm_year , (( tm -> tm_year != 1 ) ?"s " :"" ));
22342217cp += strlen (cp );
22352218is_nonzero = TRUE;
22362219}
2237- is_before |= ((tm -> tm_hour < 0 )|| (tm -> tm_min < 0 ));
2238- sprintf (cp ,"%s%02d:%02d" , (is_nonzero ?" " :"" ),
2239- abs (tm -> tm_hour ),abs (tm -> tm_min ));
2240- cp += strlen (cp );
2241- /* Mark as "non-zero" since the fields are now filled in */
2242- is_nonzero = TRUE;
22432220
2244- /* fractional seconds? */
2245- if (fsec != 0 )
2221+ if (tm -> tm_mon != 0 )
22462222{
2247- fsec += tm -> tm_sec ;
2248- is_before |= (fsec < 0 );
2249- sprintf (cp ,":%05.2f" ,fabs (fsec ));
2223+ sprintf (cp ,"%s%d mon%s" , (is_nonzero ?" " :"" ),
2224+ tm -> tm_mon , ((tm -> tm_mon != 1 ) ?"s" :"" ));
22502225cp += strlen (cp );
22512226is_nonzero = TRUE;
2227+ }
22522228
2253- /* otherwise, integer seconds only? */
2229+ if (tm -> tm_mday != 0 )
2230+ {
2231+ sprintf (cp ,"%s%d" , (is_nonzero ?" " :"" ),tm -> tm_mday );
2232+ cp += strlen (cp );
2233+ is_nonzero = TRUE;
22542234}
2255- else if (tm -> tm_sec != 0 )
22562235{
2257- is_before |= (tm -> tm_sec < 0 );
2258- sprintf (cp ,":%02d" ,abs (tm -> tm_sec ));
2236+ int minus = ((tm -> tm_hour < 0 )|| (tm -> tm_min < 0 )
2237+ || (tm -> tm_sec < 0 )|| (fsec < 0 ));
2238+
2239+ sprintf (cp ,"%s%s%02d:%02d" , (is_nonzero ?" " :"" ),
2240+ (minus ?"-" :"+" ),
2241+ abs (tm -> tm_hour ),abs (tm -> tm_min ));
22592242cp += strlen (cp );
2243+ /* Mark as "non-zero" since the fields are now filled in */
22602244is_nonzero = TRUE;
2245+
2246+ /* fractional seconds? */
2247+ if (fsec != 0 )
2248+ {
2249+ fsec += tm -> tm_sec ;
2250+ sprintf (cp ,":%05.2f" ,fabs (fsec ));
2251+ cp += strlen (cp );
2252+ is_nonzero = TRUE;
2253+
2254+ /* otherwise, integer seconds only? */
2255+ }
2256+ else if (tm -> tm_sec != 0 )
2257+ {
2258+ sprintf (cp ,":%02d" ,abs (tm -> tm_sec ));
2259+ cp += strlen (cp );
2260+ is_nonzero = TRUE;
2261+ }
22612262}
22622263break ;
22632264
22642265case USE_POSTGRES_DATES :
22652266default :
2267+ strcpy (cp ,"@ " );
2268+ cp += strlen (cp );
2269+
2270+ if (tm -> tm_year != 0 )
2271+ {
2272+ is_before = (tm -> tm_year < 0 );
2273+ if (is_before )
2274+ tm -> tm_year = - tm -> tm_year ;
2275+ sprintf (cp ,"%d year%s" ,
2276+ tm -> tm_year , ((tm -> tm_year != 1 ) ?"s" :"" ));
2277+ cp += strlen (cp );
2278+ is_nonzero = TRUE;
2279+ }
2280+
2281+ if (tm -> tm_mon != 0 )
2282+ {
2283+ if (!is_nonzero )
2284+ is_before = (tm -> tm_mon < 0 );
2285+ if (is_before )
2286+ tm -> tm_mon = - tm -> tm_mon ;
2287+ sprintf (cp ,"%s%d mon%s" , (is_nonzero ?" " :"" ),
2288+ tm -> tm_mon , ((tm -> tm_mon != 1 ) ?"s" :"" ));
2289+ cp += strlen (cp );
2290+ is_nonzero = TRUE;
2291+ }
2292+
22662293if (tm -> tm_mday != 0 )
22672294{
2268- is_before |= (tm -> tm_mday < 0 );
2295+ if (!is_nonzero )
2296+ is_before = (tm -> tm_mday < 0 );
2297+ if (is_before )
2298+ tm -> tm_mday = - tm -> tm_mday ;
22692299sprintf (cp ,"%s%d day%s" , (is_nonzero ?" " :"" ),
2270- abs ( tm -> tm_mday ) , ((abs ( tm -> tm_mday ) != 1 ) ?"s" :"" ));
2300+ tm -> tm_mday , ((tm -> tm_mday != 1 ) ?"s" :"" ));
22712301cp += strlen (cp );
22722302is_nonzero = TRUE;
22732303}
22742304if (tm -> tm_hour != 0 )
22752305{
2276- is_before |= (tm -> tm_hour < 0 );
2306+ if (!is_nonzero )
2307+ is_before = (tm -> tm_hour < 0 );
2308+ if (is_before )
2309+ tm -> tm_hour = - tm -> tm_hour ;
22772310sprintf (cp ,"%s%d hour%s" , (is_nonzero ?" " :"" ),
2278- abs ( tm -> tm_hour ) , ((abs ( tm -> tm_hour ) != 1 ) ?"s" :"" ));
2311+ tm -> tm_hour , ((tm -> tm_hour != 1 ) ?"s" :"" ));
22792312cp += strlen (cp );
22802313is_nonzero = TRUE;
22812314}
22822315
22832316if (tm -> tm_min != 0 )
22842317{
2285- is_before |= (tm -> tm_min < 0 );
2318+ if (!is_nonzero )
2319+ is_before = (tm -> tm_min < 0 );
2320+ if (is_before )
2321+ tm -> tm_min = - tm -> tm_min ;
22862322sprintf (cp ,"%s%d min%s" , (is_nonzero ?" " :"" ),
2287- abs ( tm -> tm_min ) , ((abs ( tm -> tm_min ) != 1 ) ?"s" :"" ));
2323+ tm -> tm_min , ((tm -> tm_min != 1 ) ?"s" :"" ));
22882324cp += strlen (cp );
22892325is_nonzero = TRUE;
22902326}
@@ -2293,26 +2329,32 @@ EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str)
22932329if (fsec != 0 )
22942330{
22952331fsec += tm -> tm_sec ;
2296- is_before |= (fsec < 0 );
2297- sprintf (cp ,"%s%.2f secs" , (is_nonzero ?" " :"" ),fabs (fsec ));
2332+ if (!is_nonzero )
2333+ is_before = (fsec < 0 );
2334+ if (is_before )
2335+ fsec = - fsec ;
2336+ sprintf (cp ,"%s%.2f secs" , (is_nonzero ?" " :"" ),fsec );
22982337cp += strlen (cp );
22992338is_nonzero = TRUE;
23002339
23012340/* otherwise, integer seconds only? */
23022341}
23032342else if (tm -> tm_sec != 0 )
23042343{
2305- is_before |= (tm -> tm_sec < 0 );
2344+ if (!is_nonzero )
2345+ is_before = (tm -> tm_sec < 0 );
2346+ if (is_before )
2347+ tm -> tm_sec = - tm -> tm_sec ;
23062348sprintf (cp ,"%s%d sec%s" , (is_nonzero ?" " :"" ),
2307- abs ( tm -> tm_sec ) , ((abs ( tm -> tm_sec ) != 1 ) ?"s" :"" ));
2349+ tm -> tm_sec , ((tm -> tm_sec != 1 ) ?"s" :"" ));
23082350cp += strlen (cp );
23092351is_nonzero = TRUE;
23102352}
23112353break ;
23122354}
23132355
23142356/* identically zero? then put in a unitless zero... */
2315- if (!is_nonzero )
2357+ if (!is_nonzero )
23162358{
23172359strcat (cp ,"0" );
23182360cp += strlen (cp );