8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -199,7 +199,11 @@ static datetkn datetktbl[] = {
199
199
{"pst" ,TZ ,NEG (48 )},/* Pacific Standard Time */
200
200
{"sadt" ,DTZ ,63 },/* S. Australian Dayl. Time */
201
201
{"sast" ,TZ ,57 },/* South Australian Std Time */
202
+ #if USE_AUSTRALIAN_RULES
203
+ {"sat" ,TZ ,57 },
204
+ #else
202
205
{"sat" ,DOW ,6 },
206
+ #endif
203
207
{"saturday" ,DOW ,6 },
204
208
{"sep" ,MONTH ,9 },
205
209
{"sept" ,MONTH ,9 },
@@ -218,8 +222,7 @@ static datetkn datetktbl[] = {
218
222
{"tue" ,DOW ,2 },
219
223
{"tues" ,DOW ,2 },
220
224
{"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 */
223
226
{"ut" ,TZ ,0 },
224
227
{"utc" ,TZ ,0 },
225
228
{"wadt" ,DTZ ,48 },/* West Australian DST */
@@ -235,10 +238,10 @@ static datetkn datetktbl[] = {
235
238
{"ydt" ,DTZ ,NEG (48 )},/* Yukon Daylight Time */
236
239
{YESTERDAY ,RESERV ,DTK_YESTERDAY },/* yesterday midnight */
237
240
{"yst" ,TZ ,NEG (54 )},/* Yukon Standard Time */
241
+ {"z" ,RESERV ,DTK_ZULU },/* 00:00:00 */
238
242
{"zp4" ,TZ ,NEG (24 )},/* GMT +4 hours. */
239
243
{"zp5" ,TZ ,NEG (30 )},/* GMT +5 hours. */
240
244
{"zp6" ,TZ ,NEG (36 )},/* GMT +6 hours. */
241
- {"z" ,RESERV ,DTK_ZULU },/* 00:00:00 */
242
245
{ZULU ,RESERV ,DTK_ZULU },/* 00:00:00 */
243
246
};
244
247
@@ -466,25 +469,6 @@ ParseDateTime(char *timestr, char *lowstr,
466
469
*/
467
470
if ((* cp == '-' )|| (* cp == '/' )|| (* cp == '.' ))
468
471
{
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
-
488
472
ftype [nf ]= DTK_DATE ;
489
473
while (isdigit ((int )* cp )|| (* cp == '-' )|| (* cp == '/' )|| (* cp == '.' ))
490
474
* lp ++ = tolower (* cp ++ );
@@ -1667,8 +1651,7 @@ DecodeDateDelta(char **field, int *ftype, int nf, int *dtype, struct tm * tm, do
1667
1651
tmask ,
1668
1652
type ;
1669
1653
int i ;
1670
- int flen ,
1671
- val ;
1654
+ int val ;
1672
1655
double fval ;
1673
1656
double sec ;
1674
1657
@@ -1695,14 +1678,40 @@ DecodeDateDelta(char **field, int *ftype, int nf, int *dtype, struct tm * tm, do
1695
1678
break ;
1696
1679
1697
1680
case DTK_TZ :
1698
-
1699
1681
/*
1700
1682
* 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
1702
1684
*/
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
+
1703
1711
case DTK_DATE :
1704
1712
case DTK_NUMBER :
1705
1713
val = strtol (field [i ],& cp ,10 );
1714
+
1706
1715
if (* cp == '.' )
1707
1716
{
1708
1717
fval = strtod (cp ,& cp );
@@ -1717,7 +1726,6 @@ DecodeDateDelta(char **field, int *ftype, int nf, int *dtype, struct tm * tm, do
1717
1726
else
1718
1727
return -1 ;
1719
1728
1720
- flen = strlen (field [i ]);
1721
1729
tmask = 0 ;/* DTK_M(type); */
1722
1730
1723
1731
switch (type )
@@ -2193,98 +2201,126 @@ EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str)
2193
2201
int is_nonzero = FALSE;
2194
2202
char * cp = str ;
2195
2203
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
+ */
2196
2209
switch (style )
2197
2210
{
2198
2211
/* compatible with ISO date formats */
2199
2212
case 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 )
2231
2214
{
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 " :"" ));
2234
2217
cp += strlen (cp );
2235
2218
is_nonzero = TRUE;
2236
2219
}
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;
2243
2220
2244
- /* fractional seconds? */
2245
- if (fsec != 0 )
2221
+ if (tm -> tm_mon != 0 )
2246
2222
{
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" :"" ));
2250
2225
cp += strlen (cp );
2251
2226
is_nonzero = TRUE;
2227
+ }
2252
2228
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;
2254
2234
}
2255
- else if (tm -> tm_sec != 0 )
2256
2235
{
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 ));
2259
2242
cp += strlen (cp );
2243
+ /* Mark as "non-zero" since the fields are now filled in */
2260
2244
is_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
+ }
2261
2262
}
2262
2263
break ;
2263
2264
2264
2265
case USE_POSTGRES_DATES :
2265
2266
default :
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
+
2266
2293
if (tm -> tm_mday != 0 )
2267
2294
{
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 ;
2269
2299
sprintf (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" :"" ));
2271
2301
cp += strlen (cp );
2272
2302
is_nonzero = TRUE;
2273
2303
}
2274
2304
if (tm -> tm_hour != 0 )
2275
2305
{
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 ;
2277
2310
sprintf (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" :"" ));
2279
2312
cp += strlen (cp );
2280
2313
is_nonzero = TRUE;
2281
2314
}
2282
2315
2283
2316
if (tm -> tm_min != 0 )
2284
2317
{
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 ;
2286
2322
sprintf (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" :"" ));
2288
2324
cp += strlen (cp );
2289
2325
is_nonzero = TRUE;
2290
2326
}
@@ -2293,26 +2329,32 @@ EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str)
2293
2329
if (fsec != 0 )
2294
2330
{
2295
2331
fsec += 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 );
2298
2337
cp += strlen (cp );
2299
2338
is_nonzero = TRUE;
2300
2339
2301
2340
/* otherwise, integer seconds only? */
2302
2341
}
2303
2342
else if (tm -> tm_sec != 0 )
2304
2343
{
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 ;
2306
2348
sprintf (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" :"" ));
2308
2350
cp += strlen (cp );
2309
2351
is_nonzero = TRUE;
2310
2352
}
2311
2353
break ;
2312
2354
}
2313
2355
2314
2356
/* identically zero? then put in a unitless zero... */
2315
- if (!is_nonzero )
2357
+ if (!is_nonzero )
2316
2358
{
2317
2359
strcat (cp ,"0" );
2318
2360
cp += strlen (cp );