]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/datetimes.c
Bring in a patch from Keith Parks to move the use of European dates
[postgresql] / src / backend / utils / adt / datetimes.c
1 /*-------------------------------------------------------------------------
2  *
3  * datetimes.c--
4  *    implements DATE and TIME data types specified in SQL-92 standard
5  *
6  * Copyright (c) 1994-5, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *    $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/datetimes.c,v 1.8 1997/01/26 15:31:12 scrappy Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include <stdio.h>              /* for sprintf() */
15 #include <string.h>
16
17 #include <postgres.h>
18 #include <miscadmin.h>
19 #include <utils/builtins.h>
20 #include <utils/datetime.h>
21
22 static int      day_tab[2][12] = {
23         {31,28,31,30,31,30,31,31,30,31,30,31},
24         {31,29,31,30,31,30,31,31,30,31,30,31}  };
25
26 static int
27 isleap(int year)
28 {
29     return
30         (((year % 4) == 0 && (year % 100) != 0) || (year % 400) == 0);
31 }
32
33 /*****************************************************************************
34  *   Date ADT
35  *****************************************************************************/
36
37 int4
38 date_in(char *datestr)
39 {
40     int d, m, y;
41     int4 result;
42     DateADT *date = (DateADT*)&result;
43
44 #if 0
45 # ifdef USE_SHORT_YEAR
46 #  define CHECK_DATE_LEN(datestr) (strlen(datestr) >= 8)
47 # else
48 #  define CHECK_DATE_LEN(datestr) (strlen(datestr) == 10)
49 # endif /* USE_SHORT_YEAR */
50 #else
51 # define CHECK_DATE_LEN(datestr) 1
52 #endif
53
54     if (EuroDates == 1) { /* Expect european format dates */
55         if (!CHECK_DATE_LEN(datestr) ||
56           sscanf(datestr, "%d%*c%d%*c%d", &d, &m, &y) != 3) {
57             elog(WARN, "date_in: date \"%s\" not of the form dd-mm-yyyy",
58              datestr);
59         }
60     } else {
61         if (!CHECK_DATE_LEN(datestr) ||
62           sscanf(datestr, "%d%*c%d%*c%d", &m, &d, &y) != 3) {
63             elog(WARN, "date_in: date \"%s\" not of the form mm-dd-yyyy",
64               datestr);
65         }
66     }
67     if (y < 0 || y > 32767)
68         elog(WARN, "date_in: year must be limited to values 0 through 32767 in \"%s\"", datestr);
69     if (m < 1 || m > 12)
70         elog(WARN, "date_in: month must be limited to values 1 through 12 in \"%s\"", datestr);
71     if (d < 1 || d > day_tab[isleap(y)][m-1])
72         elog(WARN, "date_in: day must be limited to values 1 through %d in \"%s\"",
73              day_tab[isleap(y)][m-1], datestr);
74
75 #ifdef USE_SHORT_YEAR
76     if (y < 100) 
77         y += 1900; /* hack! */
78 #endif /* USE_SHORT_YEAR */
79  
80     date->day = d;
81     date->month = m;
82     date->year = y;
83     return result;
84 }
85
86 char *
87 date_out(int4 dateVal)
88 {
89     char *datestr = palloc(11);
90     int4 dateStore;
91     DateADT *date;
92
93        /* DateADT is a structure that happens to be four bytes long,
94           trust me on this.... */
95     date = (DateADT*)&dateStore;
96     dateStore = dateVal;
97
98     if (EuroDates == 1) /* Output european format dates */
99         sprintf(datestr, "%02d-%02d-%04d",
100                 (int)date->day, (int)date->month, (int)date->year);
101     else
102         sprintf(datestr, "%02d-%02d-%04d",
103                 (int)date->month, (int)date->day, (int)date->year);
104
105     return datestr;
106 }
107
108
109 int
110 date_eq(int4 dateVal1, int4 dateVal2)
111 {
112     int4 dateStore1 = dateVal1;
113     int4 dateStore2 = dateVal2;
114     DateADT *date1, *date2;
115     
116     date1 = (DateADT*)&dateStore1;
117     date2 = (DateADT*)&dateStore2;
118
119     return (date1->day==date2->day && 
120             date1->month==date2->month &&
121             date1->year==date2->year);
122 }
123
124 int
125 date_ne(int4 dateVal1, int4 dateVal2)
126 {
127     int4 dateStore1 = dateVal1;
128     int4 dateStore2 = dateVal2;
129     DateADT *date1, *date2;
130     
131     date1 = (DateADT*)&dateStore1;
132     date2 = (DateADT*)&dateStore2;
133
134     return (date1->day!=date2->day || date1->month!=date2->month ||
135             date1->year!=date2->year);
136 }
137
138 int
139 date_lt(int4 dateVal1, int4 dateVal2)
140 {
141     int4 dateStore1 = dateVal1;
142     int4 dateStore2 = dateVal2;
143     DateADT *date1, *date2;
144     
145     date1 = (DateADT*)&dateStore1;
146     date2 = (DateADT*)&dateStore2;
147
148     if (date1->year!=date2->year)
149         return (date1->year<date2->year);
150     if (date1->month!=date2->month)
151         return (date1->month<date2->month);
152     return (date1->day<date2->day);
153 }
154
155 int
156 date_le(int4 dateVal1, int4 dateVal2)
157 {
158
159     int4 dateStore1 = dateVal1;
160     int4 dateStore2 = dateVal2;
161     DateADT *date1, *date2;
162     
163     date1 = (DateADT*)&dateStore1;
164     date2 = (DateADT*)&dateStore2;
165
166     if (date1->year!=date2->year)
167         return (date1->year<=date2->year);
168     if (date1->month!=date2->month)
169         return (date1->month<=date2->month);
170     return (date1->day<=date2->day);
171 }
172
173 int
174 date_gt(int4 dateVal1, int4 dateVal2)
175 {
176     int4 dateStore1 = dateVal1;
177     int4 dateStore2 = dateVal2;
178     DateADT *date1, *date2;
179     
180     date1 = (DateADT*)&dateStore1;
181     date2 = (DateADT*)&dateStore2;
182
183
184     if (date1->year!=date2->year)
185         return (date1->year>date2->year);
186     if (date1->month!=date2->month)
187         return (date1->month>date2->month);
188     return (date1->day>date2->day);
189 }
190
191 int
192 date_ge(int4 dateVal1, int4 dateVal2)
193 {
194     int4 dateStore1 = dateVal1;
195     int4 dateStore2 = dateVal2;
196     DateADT *date1, *date2;
197     
198     date1 = (DateADT*)&dateStore1;
199     date2 = (DateADT*)&dateStore2;
200
201     if (date1->year!=date2->year)
202         return (date1->year>=date2->year);
203     if (date1->month!=date2->month)
204         return (date1->month>=date2->month);
205     return (date1->day>=date2->day);
206 }
207
208 int
209 date_cmp(int4 dateVal1, int4 dateVal2)
210 {
211     int4 dateStore1 = dateVal1;
212     int4 dateStore2 = dateVal2;
213     DateADT *date1, *date2;
214     
215     date1 = (DateADT*)&dateStore1;
216     date2 = (DateADT*)&dateStore2;
217
218     if (date1->year!=date2->year)
219         return ((date1->year<date2->year) ? -1 : 1);
220     if (date1->month!=date2->month)
221         return ((date1->month<date2->month) ? -1 : 1);
222     if (date1->day!=date2->day)
223         return ((date1->day<date2->day) ? -1 : 1);
224     return 0;
225 }
226
227 int4
228 date_larger(int4 dateVal1, int4 dateVal2)
229 {
230   return (date_gt (dateVal1, dateVal2) ? dateVal1 : dateVal2);
231 }
232
233 int4
234 date_smaller(int4 dateVal1, int4 dateVal2)
235 {
236   return (date_lt (dateVal1, dateVal2) ? dateVal1 : dateVal2);
237 }
238
239 /* Compute difference between two dates in days.  */
240 int32
241 date_mi(int4 dateVal1, int4 dateVal2)
242 {
243   DateADT *date1, *date2;
244   int32 days = 0;
245   int i;
246
247   date1 = (DateADT *) &dateVal1;
248   date2 = (DateADT *) &dateVal2;
249
250   /* Sum number of days in each full year between date1 and date2.  */
251   for (i = date1->year + 1; i < date2->year; ++i)
252     days += isleap (i) ? 366 : 365;
253
254   /* Add in number of days in each full month from date1 to end of
255      year.  */
256   for (i = date1->month + 1; i <= 12; ++i)
257     days += day_tab[isleap (date1->year)][i - 1];
258
259   /* Add in number of days in each full month from start of year to
260      date2.  */
261   for (i = 1; i < date2->month; ++i)
262     days += day_tab[isleap (date2->year)][i - 1];
263
264   /* Add in number of days left in month for date1.  */
265   days += day_tab[isleap (date1->year)][date1->month - 1] - date1->day;
266
267   /* Add in day of month of date2.  */
268   days += date2->day;
269
270   return (days);
271 }
272
273 /* Add a number of days to a date, giving a new date.
274    Must handle both positive and negative numbers of days.  */
275 int4
276 date_pli(int4 dateVal, int32 days)
277 {
278   DateADT *date1 = (DateADT *) &dateVal;
279   /* Use separate day variable because date1->day is a narrow type.  */
280   int32 day = date1->day + days;
281
282   if (days > 0)
283     {
284       /* Loop as long as day has wrapped around end of month.  */
285       while (day > day_tab[isleap (date1->year)][date1->month - 1])
286         {
287           day -= day_tab[isleap (date1->year)][date1->month - 1];
288           if (++date1->month > 12)
289             {
290               /* Month wrapped around.  */
291               date1->month = 1;
292               ++date1->year;
293             }
294         }
295     }
296   else
297     {
298       /* Loop as long as day has wrapped around beginning of month.  */
299       while (day < 1)
300         {
301           /* Decrement month first, because a negative day number
302              should be held as relative to the previous month's end.  */
303           if (--date1->month < 1)
304             {
305               /* Month wrapped around.  */
306               date1->month = 12;
307               --date1->year;
308             }
309
310           day += day_tab[isleap (date1->year)][date1->month - 1];
311         }
312     }
313   date1->day = day;
314
315   return (dateVal);
316 }
317
318 /* Subtract a number of days from a date, giving a new date.  */
319 int4
320 date_mii(int4 dateVal, int32 days)
321 {
322   return (date_pli (dateVal, -days));
323 }
324
325 /*****************************************************************************
326  *   Time ADT
327  *****************************************************************************/
328
329 char *
330 time_in(char *timestr)
331 {
332     int h, m;
333     float sec;
334     TimeADT *time;
335
336     if (sscanf(timestr, "%d%*c%d%*c%f", &h, &m, &sec) != 3) {
337         sec = 0.0;
338         if (sscanf(timestr, "%d%*c%d", &h, &m) != 2) {
339             elog(WARN, "time_in: time \"%s\" not of the form hh:mm:ss",
340                  timestr);
341         }
342     }
343
344     if (h < 0 || h > 23)
345         elog(WARN, "time_in: hour must be limited to values 0 through 23 in \"%s\"", timestr);
346     if (m < 0 || m > 59)
347         elog(WARN, "time_in: minute must be limited to values 0 through 59 in \"%s\"", timestr);
348     if (sec < 0 || sec >= 60.0)
349         elog(WARN, "time_in: second must be limited to values 0 through 59.999 in \"%s\"", timestr);
350
351     time = (TimeADT*)palloc(sizeof(TimeADT));
352     time->hr = h;
353     time->min = m;
354     time->sec = sec;
355     return (char*)time;
356 }
357
358 char *
359 time_out(TimeADT *time)
360 {
361     char *timestr = palloc(32);
362     int n;
363     float f;
364
365     if (time->sec == 0.0) {
366         sprintf(timestr, "%02d:%02d",
367                 (int)time->hr, (int)time->min);
368     } else {
369         n = (int)time->sec;
370         f = (float)n;
371         if (f == time->sec) {
372             sprintf(timestr, "%02d:%02d:%02d",
373                     (int)time->hr, (int)time->min, n);
374         } else {
375             sprintf(timestr, "%02d:%02d:%09.6f",
376                     (int)time->hr, (int)time->min, time->sec);
377         }
378     }
379
380     return timestr;
381 }
382
383
384 int
385 time_eq(TimeADT *time1, TimeADT *time2)
386 {
387     return (time1->sec==time2->sec && time1->min==time2->min &&
388             time1->hr==time2->hr);
389 }
390
391 int
392 time_ne(TimeADT *time1, TimeADT *time2)
393 {
394     return (time1->sec!=time2->sec || time1->min!=time2->min ||
395             time1->hr!=time2->hr);
396 }
397
398 int
399 time_lt(TimeADT *time1, TimeADT *time2)
400 {
401     if (time1->hr!=time2->hr)
402         return (time1->hr<time2->hr);
403     if (time1->min!=time2->min)
404         return (time1->min<time2->min);
405     return (time1->sec<time2->sec);
406 }
407
408 int
409 time_le(TimeADT *time1, TimeADT *time2)
410 {
411     if (time1->hr!=time2->hr)
412         return (time1->hr<=time2->hr);
413     if (time1->min!=time2->min)
414         return (time1->min<=time2->min);
415     return (time1->sec<=time2->sec);
416 }
417
418 int
419 time_gt(TimeADT *time1, TimeADT *time2)
420 {
421     if (time1->hr!=time2->hr)
422         return (time1->hr>time2->hr);
423     if (time1->min!=time2->min)
424         return (time1->min>time2->min);
425     return (time1->sec>time2->sec);
426 }
427
428 int
429 time_ge(TimeADT *time1, TimeADT *time2)
430 {
431     if (time1->hr!=time2->hr)
432         return (time1->hr>=time2->hr);
433     if (time1->min!=time2->min)
434         return (time1->min>=time2->min);
435     return (time1->sec>=time2->sec);
436 }
437
438 int
439 time_cmp(TimeADT *time1, TimeADT *time2)
440 {
441     if (time1->hr!=time2->hr)
442         return ((time1->hr<time2->hr) ? -1 : 1);
443     if (time1->min!=time2->min)
444         return ((time1->min<time2->min) ? -1 : 1);
445     if (time1->sec!=time2->sec)
446         return ((time1->sec<time2->sec) ? -1 : 1);
447     return 0;
448 }
449
450 int32   /* RelativeTime */
451 int42reltime(int32 timevalue)
452 {
453     return(timevalue);
454 }