1 #ifndef MODULE_DATE_CALC
2 #define MODULE_DATE_CALC
3 /*****************************************************************************/
4 /*  MODULE NAME:  DateCalc.c                            MODULE TYPE:  (lib)  */
5 /*****************************************************************************/
6 /*          Gregorian calendar date calculations in compliance with          */
7 /*          ISO/R 2015-1971, DIN 1355 and (to some extent) ISO 8601.         */
8 /*****************************************************************************/
9 /*  MODULE IMPORTS:                                                          */
10 /*****************************************************************************/
11 #include <stdio.h>                                  /*  MODULE TYPE:  (sys)  */
12 #include <stdlib.h>                                 /*  MODULE TYPE:  (sys)  */
13 #include <string.h>                                 /*  MODULE TYPE:  (sys)  */
14 #include <time.h>                                   /*  MODULE TYPE:  (sys)  */
15 #include "ToolBox.h"                                /*  MODULE TYPE:  (dat)  */
16 /*****************************************************************************/
17 /*  MODULE INTERFACE:                                                        */
18 /*****************************************************************************/
19 
20 /* Make the VMS linker happy: */
21 
22 #ifdef VMS
23 #define DateCalc_Day_of_Week_Abbreviation_ DateCalc_DoW_Abbrev_
24 #define DateCalc_nth_weekday_of_month_year DateCalc_nth_weekday
25 #endif
26 
27 boolean
28 DateCalc_leap_year                     (Z_int   year);
29 
30 boolean
31 DateCalc_check_date                    (Z_int   year,
32                                         Z_int   month,
33                                         Z_int   day);
34 
35 boolean
36 DateCalc_check_time                    (Z_int   hour,
37                                         Z_int   min,
38                                         Z_int   sec);
39 
40 boolean
41 DateCalc_check_business_date           (Z_int   year,
42                                         Z_int   week,
43                                         Z_int   dow);
44 
45 Z_int
46 DateCalc_Day_of_Year                   (Z_int   year,
47                                         Z_int   month,
48                                         Z_int   day);
49 
50 Z_long
51 DateCalc_Date_to_Days                  (Z_int   year,
52                                         Z_int   month,
53                                         Z_int   day);
54 
55 Z_int
56 DateCalc_Day_of_Week                   (Z_int   year,
57                                         Z_int   month,
58                                         Z_int   day);
59 
60 Z_int
61 DateCalc_Weeks_in_Year                 (Z_int   year);
62 
63 Z_int
64 DateCalc_Week_Number                   (Z_int   year,
65                                         Z_int   month,
66                                         Z_int   day);
67 
68 boolean
69 DateCalc_week_of_year                  (Z_int  *week,       /*   O   */
70                                         Z_int  *year,       /*  I/O  */
71                                         Z_int   month,      /*   I   */
72                                         Z_int   day);       /*   I   */
73 
74 boolean
75 DateCalc_monday_of_week                (Z_int   week,       /*   I   */
76                                         Z_int  *year,       /*  I/O  */
77                                         Z_int  *month,      /*   O   */
78                                         Z_int  *day);       /*   O   */
79 
80 boolean
81 DateCalc_nth_weekday_of_month_year     (Z_int  *year,       /*  I/O  */
82                                         Z_int  *month,      /*  I/O  */
83                                         Z_int  *day,        /*   O   */
84                                         Z_int   dow,        /*   I   */
85                                         Z_int   n);         /*   I   */
86 
87 boolean
88 DateCalc_standard_to_business          (Z_int  *year,       /*  I/O  */
89                                         Z_int  *week,       /*   O   */
90                                         Z_int  *dow,        /*   O   */
91                                         Z_int   month,      /*   I   */
92                                         Z_int   day);       /*   I   */
93 
94 boolean
95 DateCalc_business_to_standard          (Z_int  *year,       /*  I/O  */
96                                         Z_int  *month,      /*   O   */
97                                         Z_int  *day,        /*   O   */
98                                         Z_int   week,       /*   I   */
99                                         Z_int   dow);       /*   I   */
100 
101 Z_long
102 DateCalc_Delta_Days                    (Z_int   year1,
103                                         Z_int   month1,
104                                         Z_int   day1,
105                                         Z_int   year2,
106                                         Z_int   month2,
107                                         Z_int   day2);
108 
109 boolean /* PRIVATE */
110 DateCalc_delta_hms                     (Z_long *Dd,         /*  I/O  */
111                                         Z_int  *Dh,         /*   O   */
112                                         Z_int  *Dm,         /*   O   */
113                                         Z_int  *Ds,         /*   O   */
114                                         Z_int   hour1,      /*   I   */
115                                         Z_int   min1,       /*   I   */
116                                         Z_int   sec1,       /*   I   */
117                                         Z_int   hour2,      /*   I   */
118                                         Z_int   min2,       /*   I   */
119                                         Z_int   sec2);      /*   I   */
120 
121 boolean
122 DateCalc_delta_dhms                    (Z_long *Dd,         /*   O   */
123                                         Z_int  *Dh,         /*   O   */
124                                         Z_int  *Dm,         /*   O   */
125                                         Z_int  *Ds,         /*   O   */
126                                         Z_int   year1,      /*   I   */
127                                         Z_int   month1,     /*   I   */
128                                         Z_int   day1,       /*   I   */
129                                         Z_int   hour1,      /*   I   */
130                                         Z_int   min1,       /*   I   */
131                                         Z_int   sec1,       /*   I   */
132                                         Z_int   year2,      /*   I   */
133                                         Z_int   month2,     /*   I   */
134                                         Z_int   day2,       /*   I   */
135                                         Z_int   hour2,      /*   I   */
136                                         Z_int   min2,       /*   I   */
137                                         Z_int   sec2);      /*   I   */
138 
139 boolean
140 DateCalc_delta_ymd                     (Z_int  *year1,      /*  I/O  */
141                                         Z_int  *month1,     /*  I/O  */
142                                         Z_int  *day1,       /*  I/O  */
143                                         Z_int   year2,      /*   I   */
144                                         Z_int   month2,     /*   I   */
145                                         Z_int   day2);      /*   I   */
146 
147 boolean
148 DateCalc_delta_ymdhms                  (Z_int  *D_y,        /*   O   */
149                                         Z_int  *D_m,        /*   O   */
150                                         Z_int  *D_d,        /*   O   */
151                                         Z_int  *Dh,         /*   O   */
152                                         Z_int  *Dm,         /*   O   */
153                                         Z_int  *Ds,         /*   O   */
154                                         Z_int   year1,      /*   I   */
155                                         Z_int   month1,     /*   I   */
156                                         Z_int   day1,       /*   I   */
157                                         Z_int   hour1,      /*   I   */
158                                         Z_int   min1,       /*   I   */
159                                         Z_int   sec1,       /*   I   */
160                                         Z_int   year2,      /*   I   */
161                                         Z_int   month2,     /*   I   */
162                                         Z_int   day2,       /*   I   */
163                                         Z_int   hour2,      /*   I   */
164                                         Z_int   min2,       /*   I   */
165                                         Z_int   sec2);      /*   I   */
166 
167 boolean
168 DateCalc_norm_delta_ymd                (Z_int  *year1,      /*  I/O  */
169                                         Z_int  *month1,     /*  I/O  */
170                                         Z_int  *day1,       /*  I/O  */
171                                         Z_int   year2,      /*   I   */
172                                         Z_int   month2,     /*   I   */
173                                         Z_int   day2);      /*   I   */
174 
175 boolean
176 DateCalc_norm_delta_ymdhms             (Z_int  *D_y,        /*   O   */
177                                         Z_int  *D_m,        /*   O   */
178                                         Z_int  *D_d,        /*   O   */
179                                         Z_int  *Dhh,        /*   O   */
180                                         Z_int  *Dmm,        /*   O   */
181                                         Z_int  *Dss,        /*   O   */
182                                         Z_int   year1,      /*   I   */
183                                         Z_int   month1,     /*   I   */
184                                         Z_int   day1,       /*   I   */
185                                         Z_int   hour1,      /*   I   */
186                                         Z_int   min1,       /*   I   */
187                                         Z_int   sec1,       /*   I   */
188                                         Z_int   year2,      /*   I   */
189                                         Z_int   month2,     /*   I   */
190                                         Z_int   day2,       /*   I   */
191                                         Z_int   hour2,      /*   I   */
192                                         Z_int   min2,       /*   I   */
193                                         Z_int   sec2);      /*   I   */
194 
195 void
196 DateCalc_Normalize_DHMS                (Z_long *Dd,         /*  I/O  */
197                                         Z_long *Dh,         /*  I/O  */
198                                         Z_long *Dm,         /*  I/O  */
199                                         Z_long *Ds);        /*  I/O  */
200 
201 boolean
202 DateCalc_add_delta_days                (Z_int  *year,       /*  I/O  */
203                                         Z_int  *month,      /*  I/O  */
204                                         Z_int  *day,        /*  I/O  */
205                                         Z_long  Dd);        /*   I   */
206 
207 boolean
208 DateCalc_add_delta_dhms                (Z_int  *year,       /*  I/O  */
209                                         Z_int  *month,      /*  I/O  */
210                                         Z_int  *day,        /*  I/O  */
211                                         Z_int  *hour,       /*  I/O  */
212                                         Z_int  *min,        /*  I/O  */
213                                         Z_int  *sec,        /*  I/O  */
214                                         Z_long  Dd,         /*   I   */
215                                         Z_long  Dh,         /*   I   */
216                                         Z_long  Dm,         /*   I   */
217                                         Z_long  Ds);        /*   I   */
218 
219 boolean /* PRIVATE */
220 DateCalc_add_year_month                (Z_int  *year,       /*  I/O  */
221                                         Z_int  *month,      /*  I/O  */
222                                         Z_long  Dy,         /*   I   */
223                                         Z_long  Dm);        /*   I   */
224 
225 boolean
226 DateCalc_add_delta_ym                  (Z_int  *year,       /*  I/O  */
227                                         Z_int  *month,      /*  I/O  */
228                                         Z_int  *day,        /*  I/O  */
229                                         Z_long  Dy,         /*   I   */
230                                         Z_long  Dm);        /*   I   */
231 
232 boolean
233 DateCalc_add_delta_ymd                 (Z_int  *year,       /*  I/O  */
234                                         Z_int  *month,      /*  I/O  */
235                                         Z_int  *day,        /*  I/O  */
236                                         Z_long  Dy,         /*   I   */
237                                         Z_long  Dm,         /*   I   */
238                                         Z_long  Dd);        /*   I   */
239 
240 boolean
241 DateCalc_add_delta_ymdhms              (Z_int  *year,       /*  I/O  */
242                                         Z_int  *month,      /*  I/O  */
243                                         Z_int  *day,        /*  I/O  */
244                                         Z_int  *hour,       /*  I/O  */
245                                         Z_int  *min,        /*  I/O  */
246                                         Z_int  *sec,        /*  I/O  */
247                                         Z_long  D_y,        /*   I   */
248                                         Z_long  D_m,        /*   I   */
249                                         Z_long  D_d,        /*   I   */
250                                         Z_long  Dh,         /*   I   */
251                                         Z_long  Dm,         /*   I   */
252                                         Z_long  Ds);        /*   I   */
253 
254 boolean
255 DateCalc_add_norm_delta_ymd            (Z_int  *year,       /*  I/O  */
256                                         Z_int  *month,      /*  I/O  */
257                                         Z_int  *day,        /*  I/O  */
258                                         Z_long  Dy,         /*   I   */
259                                         Z_long  Dm,         /*   I   */
260                                         Z_long  Dd);        /*   I   */
261 
262 boolean
263 DateCalc_add_norm_delta_ymdhms         (Z_int  *year,       /*  I/O  */
264                                         Z_int  *month,      /*  I/O  */
265                                         Z_int  *day,        /*  I/O  */
266                                         Z_int  *hour,       /*  I/O  */
267                                         Z_int  *min,        /*  I/O  */
268                                         Z_int  *sec,        /*  I/O  */
269                                         Z_long  D_y,        /*   I   */
270                                         Z_long  D_m,        /*   I   */
271                                         Z_long  D_d,        /*   I   */
272                                         Z_long  Dh,         /*   I   */
273                                         Z_long  Dm,         /*   I   */
274                                         Z_long  Ds);        /*   I   */
275 
276 boolean
277 DateCalc_system_clock                  (Z_int  *year,       /*   O   */
278                                         Z_int  *month,      /*   O   */
279                                         Z_int  *day,        /*   O   */
280                                         Z_int  *hour,       /*   O   */
281                                         Z_int  *min,        /*   O   */
282                                         Z_int  *sec,        /*   O   */
283                                         Z_int  *doy,        /*   O   */
284                                         Z_int  *dow,        /*   O   */
285                                         Z_int  *dst,        /*   O   */
286                                         boolean gmt);       /*   I   */
287 
288 boolean
289 DateCalc_gmtime                        (Z_int  *year,       /*   O   */
290                                         Z_int  *month,      /*   O   */
291                                         Z_int  *day,        /*   O   */
292                                         Z_int  *hour,       /*   O   */
293                                         Z_int  *min,        /*   O   */
294                                         Z_int  *sec,        /*   O   */
295                                         Z_int  *doy,        /*   O   */
296                                         Z_int  *dow,        /*   O   */
297                                         Z_int  *dst,        /*   O   */
298                                         time_t  seconds);   /*   I   */
299 
300 boolean
301 DateCalc_localtime                     (Z_int  *year,       /*   O   */
302                                         Z_int  *month,      /*   O   */
303                                         Z_int  *day,        /*   O   */
304                                         Z_int  *hour,       /*   O   */
305                                         Z_int  *min,        /*   O   */
306                                         Z_int  *sec,        /*   O   */
307                                         Z_int  *doy,        /*   O   */
308                                         Z_int  *dow,        /*   O   */
309                                         Z_int  *dst,        /*   O   */
310                                         time_t  seconds);   /*   I   */
311 
312 boolean
313 DateCalc_mktime                        (time_t *seconds,    /*   O   */
314                                         Z_int   year,       /*   I   */
315                                         Z_int   month,      /*   I   */
316                                         Z_int   day,        /*   I   */
317                                         Z_int   hour,       /*   I   */
318                                         Z_int   min,        /*   I   */
319                                         Z_int   sec,        /*   I   */
320                                         Z_int   doy,        /*   I   */
321                                         Z_int   dow,        /*   I   */
322                                         Z_int   dst);       /*   I   */
323 
324 boolean
325 DateCalc_timezone                      (Z_int  *year,       /*   O   */
326                                         Z_int  *month,      /*   O   */
327                                         Z_int  *day,        /*   O   */
328                                         Z_int  *hour,       /*   O   */
329                                         Z_int  *min,        /*   O   */
330                                         Z_int  *sec,        /*   O   */
331                                         Z_int  *dst,        /*   O   */
332                                         time_t when);       /*   I   */
333 
334 boolean
335 DateCalc_date2time                     (time_t *seconds,    /*   O   */
336                                         Z_int   year,       /*   I   */
337                                         Z_int   month,      /*   I   */
338                                         Z_int   day,        /*   I   */
339                                         Z_int   hour,       /*   I   */
340                                         Z_int   min,        /*   I   */
341                                         Z_int   sec);       /*   I   */
342 
343 boolean
344 DateCalc_time2date                     (Z_int  *year,       /*   O   */
345                                         Z_int  *month,      /*   O   */
346                                         Z_int  *day,        /*   O   */
347                                         Z_int  *hour,       /*   O   */
348                                         Z_int  *min,        /*   O   */
349                                         Z_int  *sec,        /*   O   */
350                                         time_t  seconds);   /*   I   */
351 
352 boolean
353 DateCalc_easter_sunday                 (Z_int  *year,       /*  I/O  */
354                                         Z_int  *month,      /*   O   */
355                                         Z_int  *day);       /*   O   */
356 
357 Z_int
358 DateCalc_Decode_Month                  (charptr buffer,
359                                         Z_int   length,
360                                         Z_int   lang);
361 
362 Z_int
363 DateCalc_Decode_Day_of_Week            (charptr buffer,
364                                         Z_int   length,
365                                         Z_int   lang);
366 
367 Z_int
368 DateCalc_Decode_Language               (charptr buffer,
369                                         Z_int   length);
370 
371 boolean
372 DateCalc_decode_date_eu                (charptr buffer,     /*   I   */
373                                         Z_int  *year,       /*   O   */
374                                         Z_int  *month,      /*   O   */
375                                         Z_int  *day,        /*   O   */
376                                         Z_int   lang);      /*   I   */
377 
378 boolean
379 DateCalc_decode_date_us                (charptr buffer,     /*   I   */
380                                         Z_int  *year,       /*   O   */
381                                         Z_int  *month,      /*   O   */
382                                         Z_int  *day,        /*   O   */
383                                         Z_int   lang);      /*   I   */
384 
385 Z_int
386 DateCalc_Fixed_Window                  (Z_int   year);
387 
388 Z_int
389 DateCalc_Moving_Window                 (Z_int   year);
390 
391 Z_int
392 DateCalc_Compress                      (Z_int   year,
393                                         Z_int   month,
394                                         Z_int   day);
395 
396 boolean
397 DateCalc_uncompress                    (Z_int   date,       /*   I   */
398                                         Z_int  *century,    /*   O   */
399                                         Z_int  *year,       /*   O   */
400                                         Z_int  *month,      /*   O   */
401                                         Z_int  *day);       /*   O   */
402 
403 boolean
404 DateCalc_check_compressed              (Z_int   date);
405 
406 charptr
407 DateCalc_Compressed_to_Text            (Z_int   date,
408                                         Z_int   lang);
409 
410 charptr
411 DateCalc_Date_to_Text                  (Z_int   year,
412                                         Z_int   month,
413                                         Z_int   day,
414                                         Z_int   lang);
415 
416 charptr
417 DateCalc_Date_to_Text_Long             (Z_int   year,
418                                         Z_int   month,
419                                         Z_int   day,
420                                         Z_int   lang);
421 
422 charptr                                                     /*   O   */
423 DateCalc_English_Ordinal               (charptr result,     /*   O   */
424                                         Z_int   number);    /*   I   */
425 
426 charptr
427 DateCalc_Calendar                      (Z_int   year,
428                                         Z_int   month,
429                                         boolean orthodox,
430                                         Z_int   lang);
431 
432 void
433 DateCalc_Dispose                       (charptr string);
434 
435 N_char
436 DateCalc_ISO_LC                        (N_char c);
437 
438 N_char
439 DateCalc_ISO_UC                        (N_char c);
440 
441 charptr
442 DateCalc_Version                       (void);
443 
444 /*****************************************************************************/
445 /*  MODULE RESOURCES:                                                        */
446 /*****************************************************************************/
447 
448 #define  DateCalc_YEAR_OF_EPOCH        70    /* year of reference (epoch)    */
449 #define  DateCalc_CENTURY_OF_EPOCH   1900    /* century of reference (epoch) */
450 #define  DateCalc_EPOCH (DateCalc_CENTURY_OF_EPOCH + DateCalc_YEAR_OF_EPOCH)
451 
452 const Z_int DateCalc_Days_in_Year_[2][14] =
453 {
454     { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
455     { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
456 };
457 
458 const Z_int DateCalc_Days_in_Month_[2][13] =
459 {
460     { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
461     { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
462 };
463 
464 #define DateCalc_LANGUAGES 14
465 
466 Z_int DateCalc_Language = 1; /* Default = 1 (English) */
467 
468 const N_char DateCalc_Month_to_Text_[DateCalc_LANGUAGES+1][13][32] =
469 {
470     {
471         "???", "???", "???", "???", "???", "???", "???",
472         "???", "???", "???", "???", "???", "???"
473     },
474     {
475         "???", "January", "February", "March", "April", "May", "June",
476         "July", "August", "September", "October", "November", "December"
477     },
478     {
479         "???", "janvier", "f�vrier", "mars", "avril", "mai", "juin",
480         "juillet", "ao�t", "septembre", "octobre", "novembre", "d�cembre"
481     },
482     {
483         "???", "Januar", "Februar", "M�rz", "April", "Mai", "Juni",
484         "Juli", "August", "September", "Oktober", "November", "Dezember"
485     },
486     {
487         "???", "enero", "febrero", "marzo", "abril", "mayo", "junio",
488         "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"
489     },
490     {
491         "???", "janeiro", "fevereiro", "mar�o", "abril", "maio", "junho",
492         "julho", "agosto", "setembro", "outubro", "novembro", "dezembro"
493     },
494     {
495         "???", "januari", "februari", "maart", "april", "mei", "juni",
496         "juli", "augustus", "september", "oktober", "november", "december"
497     },
498     {
499         "???", "Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno",
500         "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"
501     },
502     {
503         "???", "januar", "februar", "mars", "april", "mai", "juni",
504         "juli", "august", "september", "oktober", "november", "desember"
505     },
506     {
507         "???", "januari", "februari", "mars", "april", "maj", "juni",
508         "juli", "augusti", "september", "oktober", "november", "december"
509     },
510     {
511         "???", "januar", "februar", "marts", "april", "maj", "juni",
512         "juli", "august", "september", "oktober", "november", "december"
513     },
514     {
515         "???", "tammikuu", "helmikuu", "maaliskuu", "huhtikuu",
516         "toukokuu", "kes�kuu", "hein�kuu", "elokuu",
517         "syyskuu", "lokakuu", "marraskuu", "joulukuu"
518     },
519     {
520         "???", "Janu�r", "Febru�r", "M�rcius", "�prilis", "M�jus", "J�nius",
521         "J�lius", "Augusztus", "Szeptember", "Okt�ber", "November", "December"
522     },
523     {
524         "???", "Styczen", "Luty", "Marzec", "Kwiecien", "Maj", "Czerwiec",    /* ISO-Latin-1 approximation */
525         "Lipiec", "Sierpien", "Wrzesien", "Pazdziernik", "Listopad", "Grudzien"
526     },
527     {
528         "???", "Ianuarie", "Februarie", "Martie", "Aprilie", "Mai", "Iunie",
529         "Iulie", "August", "Septembrie", "Octombrie", "Noiembrie", "Decembrie"
530     }
531 };
532 
533 const N_char DateCalc_Day_of_Week_to_Text_[DateCalc_LANGUAGES+1][8][32] =
534 {
535     {
536         "???", "???", "???", "???",
537         "???", "???", "???", "???"
538     },
539     {
540         "???", "Monday", "Tuesday", "Wednesday",
541         "Thursday", "Friday", "Saturday", "Sunday"
542     },
543     {
544         "???", "Lundi", "Mardi", "Mercredi",
545         "Jeudi", "Vendredi", "Samedi", "Dimanche"
546     },
547     {
548         "???", "Montag", "Dienstag", "Mittwoch",
549         "Donnerstag", "Freitag", "Samstag", "Sonntag"
550     },
551     {
552         "???", "Lunes", "Martes", "Mi�rcoles",
553         "Jueves", "Viernes", "S�bado", "Domingo"
554     },
555     {
556         "???", "Segunda-feira", "Ter�a-feira", "Quarta-feira",
557         "Quinta-feira", "Sexta-feira", "S�bado", "Domingo"
558     },
559     {
560         "???", "Maandag", "Dinsdag", "Woensdag",
561         "Donderdag", "Vrijdag", "Zaterdag", "Zondag"
562     },
563     {
564         "???", "Luned�", "Marted�", "Mercoled�",
565         "Gioved�", "Venerd�", "Sabato", "Domenica"
566     },
567     {
568         "???", "mandag", "tirsdag", "onsdag",
569         "torsdag", "fredag", "l�rdag", "s�ndag"
570     },
571     {
572         "???", "m�ndag", "tisdag", "onsdag",
573         "torsdag", "fredag", "l�rdag", "s�ndag"
574     },
575     {
576         "???", "mandag", "tirsdag", "onsdag",
577         "torsdag", "fredag", "l�rdag", "s�ndag"
578     },
579     {
580         "???", "maanantai", "tiistai", "keskiviikko",
581         "torstai", "perjantai", "lauantai", "sunnuntai"
582     },
583     {
584         "???", "h�tf�", "kedd", "szerda",
585         "cs�t�rt�k", "p�ntek", "szombat", "vas�rnap"
586     },
587     {
588         "???", "poniedzialek", "wtorek", "sroda",    /* ISO-Latin-1 approximation */
589         "czwartek", "piatek", "sobota", "niedziela"
590     },
591     {
592         "???", "Luni", "Marti", "Miercuri",
593         "Joi", "Vineri", "Sambata", "Duminica"
594     }
595 };
596 
597 const N_char DateCalc_Day_of_Week_Abbreviation_[DateCalc_LANGUAGES+1][8][4] =
598 
599     /* Fill the fields below _only_ if special abbreviations are needed! */
600     /* Note that the first field serves as a flag and must be non-empty! */
601 {
602     {
603         "", "", "", "", "", "", "", ""    /*  0 */
604     },
605     {
606         "", "", "", "", "", "", "", ""    /*  1 */
607     },
608     {
609         "", "", "", "", "", "", "", ""    /*  2 */
610     },
611     {
612         "", "", "", "", "", "", "", ""    /*  3 */
613     },
614     {
615         "", "", "", "", "", "", "", ""    /*  4 */
616     },
617     {
618         "", "", "", "", "", "", "", ""    /*  5 */
619 /*      "???", "2�", "3�", "4�", "5�", "6�", "S�b", "Dom"    /*  5 */
620     },
621     {
622         "", "", "", "", "", "", "", ""    /*  6 */
623     },
624     {
625         "", "", "", "", "", "", "", ""    /*  7 */
626     },
627     {
628         "", "", "", "", "", "", "", ""    /*  8 */
629     },
630     {
631         "", "", "", "", "", "", "", ""    /*  9 */
632     },
633     {
634         "", "", "", "", "", "", "", ""    /* 10 */
635     },
636     {
637         "", "", "", "", "", "", "", ""    /* 11 */
638     },
639     {
640         "", "", "", "", "", "", "", ""    /* 12 */
641     },
642     {
643         "???", "Pn", "Wt", "Sr", "Cz", "Pt", "So", "Ni"    /* 13 */ /* ISO-Latin-1 approximation */
644     },
645     {
646         "", "", "", "", "", "", "", ""    /* 14 */
647     }
648 };
649 
650 const N_char DateCalc_English_Ordinals_[4][4] =
651 {
652     "th",
653     "st",
654     "nd",
655     "rd"
656 };
657 
658 const N_char DateCalc_Date_Long_Format_[DateCalc_LANGUAGES+1][64] =
659 {
660     "%s, %d %s %d",                     /*  0  Default     */
661     "%s, %s %s %d",                     /*  1  English     */
662     "%s %d %s %d",                      /*  2  Fran�ais    */
663     "%s, den %d. %s %d",                /*  3  Deutsch     */
664     "%s, %d de %s de %d",               /*  4  Espa�ol     */
665     "%s, dia %d de %s de %d",           /*  5  Portugu�s   */
666     "%s, %d %s %d",                     /*  6  Nederlands  */
667     "%s, %d %s %d",                     /*  7  Italiano    */
668     "%s, %d. %s %d",                    /*  8  Norsk       */
669     "%s, %d %s %d",                     /*  9  Svenska     */
670     "%s, %d. %s %d",                    /* 10  Dansk       */
671     "%s, %d. %sta %d",                  /* 11  suomi       */
672     "%d. %s %d., %s",                   /* 12  Magyar      */
673     "%s, %d %s %d",                     /* 13  polski      */
674     "%s %d %s %d"                       /* 14  Romaneste   */
675 };
676 
677 const N_char DateCalc_Language_to_Text_[DateCalc_LANGUAGES+1][32] =
678 {
679     "???", "English", "Fran�ais", "Deutsch", "Espa�ol",
680     "Portugu�s", "Nederlands", "Italiano", "Norsk", "Svenska",
681     "Dansk", "suomi", "Magyar", "polski", "Romaneste"
682 };
683 
684 /*****************************************************************************/
685 /*  MODULE IMPLEMENTATION:                                                   */
686 /*****************************************************************************/
687 
DateCalc_is_digit(N_char c)688 static boolean DateCalc_is_digit(N_char c)
689 {
690     N_int i = (N_int) c;
691 
692     if ((i >= 0x30) and (i <= 0x39)) return(true);
693     return(false);
694 }
695 
DateCalc_is_alnum(N_char c)696 static boolean DateCalc_is_alnum(N_char c)
697 {
698     N_int i = (N_int) c;
699 
700     if (((i >= 0x30) and (i <= 0x39)) or
701         ((i >= 0x41) and (i <= 0x5A)) or
702         ((i >= 0x61) and (i <= 0x7A)) or
703         ((i >= 0xC0) and (i <= 0xD6)) or
704         ((i >= 0xD8) and (i <= 0xF6)) or
705         ((i >= 0xF8) and (i <= 0xFF)))
706             return(true);
707     return(false);
708 }
709 
DateCalc_ISO_LC(N_char c)710 N_char DateCalc_ISO_LC(N_char c)
711 {
712     N_int i = (N_int) c;
713 
714     if (((i >= 0x41) and (i <= 0x5A)) or
715         ((i >= 0xC0) and (i <= 0xD6)) or
716         ((i >= 0xD8) and (c <= 0xDE))) i += 0x20;
717     return((N_char) i);
718 }
719 
DateCalc_ISO_UC(N_char c)720 N_char DateCalc_ISO_UC(N_char c)
721 {
722     N_int i = (N_int) c;
723 
724     if (((i >= 0x61) and (i <= 0x7A)) or
725         ((i >= 0xE0) and (i <= 0xF6)) or
726         ((i >= 0xF8) and (c <= 0xFE))) i -= 0x20;
727     return((N_char) i);
728 }
729 
DateCalc_Year_to_Days(Z_int year)730 static Z_long DateCalc_Year_to_Days(Z_int year)
731 {
732     Z_long days;
733 
734     days = year * 365L;
735     days += year >>= 2;
736     days -= year /= 25;
737     days += year >>  2;
738     return(days);
739 }
740 
DateCalc_scan9(charptr str,Z_int len,Z_int idx,boolean neg)741 static boolean DateCalc_scan9(charptr str, Z_int len, Z_int idx, boolean neg)
742 {   /* Mnemonic: COBOL "PIC 9" */
743     if ((str != NULL) and (idx >= 0) and (idx < len))
744         return( DateCalc_is_digit(str[idx]) XOR neg );
745     return(false);
746 }
747 
DateCalc_scanx(charptr str,Z_int len,Z_int idx,boolean neg)748 static boolean DateCalc_scanx(charptr str, Z_int len, Z_int idx, boolean neg)
749 {   /* Mnemonic: COBOL "PIC X" */
750     if ((str != NULL) and (idx >= 0) and (idx < len))
751         return( DateCalc_is_alnum(str[idx]) XOR neg );
752     return(false);
753 }
754 
DateCalc_Str2Int(charptr string,Z_int length)755 static Z_int DateCalc_Str2Int(charptr string, Z_int length)
756 {
757     Z_int number = 0;
758 
759     while (length-- > 0)
760     {
761         if (number) number *= 10;
762         number += (Z_int) (*string++ - '0');
763     }
764     return(number);
765 }
766 
DateCalc_Center(charptr * target,charptr source,Z_int width)767 static void DateCalc_Center(charptr *target, charptr source, Z_int width)
768 {
769     Z_int length;
770     Z_int blank;
771 
772     length = strlen((char *)source);
773     if (length > width) length = width;
774     blank = width - length;
775     blank >>= 1;
776     while (blank-- > 0) *(*target)++ = ' ';
777     while (length-- > 0) *(*target)++ = *source++;
778     *(*target)++ = '\n';
779     *(*target)   = '\0';
780 }
781 
DateCalc_Blank(charptr * target,Z_int count)782 static void DateCalc_Blank(charptr *target, Z_int count)
783 {
784     while (count-- > 0) *(*target)++ = ' ';
785     *(*target) = '\0';
786 }
787 
DateCalc_Newline(charptr * target,Z_int count)788 static void DateCalc_Newline(charptr *target, Z_int count)
789 {
790     while (count-- > 0) *(*target)++ = '\n';
791     *(*target) = '\0';
792 }
793 
DateCalc_Normalize_Time(Z_long * Dd,Z_long * Dh,Z_long * Dm,Z_long * Ds)794 static void DateCalc_Normalize_Time(Z_long *Dd, Z_long *Dh, Z_long *Dm, Z_long *Ds)
795 {
796     Z_long quot;
797 
798     quot = (Z_long) (*Ds / 60L);
799     *Ds -= quot * 60L;
800     *Dm += quot;
801     quot = (Z_long) (*Dm / 60L);
802     *Dm -= quot * 60L;
803     *Dh += quot;
804     quot = (Z_long) (*Dh / 24L);
805     *Dh -= quot * 24L;
806     *Dd += quot;
807 }
808 
DateCalc_Normalize_Ranges(Z_long * Dd,Z_long * Dh,Z_long * Dm,Z_long * Ds)809 static void DateCalc_Normalize_Ranges(Z_long *Dd, Z_long *Dh, Z_long *Dm, Z_long *Ds)
810 {
811     Z_long quot;
812 
813     /* Prevent overflow errors on systems */
814     /* with short "long"s (e.g. 32 bits): */
815 
816     quot = (Z_long) (*Dh / 24L);
817     *Dh -= quot * 24L;
818     *Dd += quot;
819     quot = (Z_long) (*Dm / 60L);
820     *Dm -= quot * 60L;
821     *Dh += quot;
822     DateCalc_Normalize_Time(Dd,Dh,Dm,Ds);
823 }
824 
DateCalc_Normalize_Signs(Z_long * Dd,Z_long * Dh,Z_long * Dm,Z_long * Ds)825 static void DateCalc_Normalize_Signs(Z_long *Dd, Z_long *Dh, Z_long *Dm, Z_long *Ds)
826 {
827     Z_long quot;
828 
829     quot = (Z_long) (*Ds / 86400L);
830     *Ds -= quot * 86400L;
831     *Dd += quot;
832     if (*Dd != 0L)
833     {
834         if (*Dd > 0L)
835         {
836             if (*Ds < 0L)
837             {
838                 *Ds += 86400L;
839                 (*Dd)--;
840             }
841         }
842         else
843         {
844             if (*Ds > 0L)
845             {
846                 *Ds -= 86400L;
847                 (*Dd)++;
848             }
849         }
850     }
851     *Dh = 0L;
852     *Dm = 0L;
853     if (*Ds != 0L) DateCalc_Normalize_Time(Dd,Dh,Dm,Ds);
854 }
855 
DateCalc_Normalize_DHMS(Z_long * Dd,Z_long * Dh,Z_long * Dm,Z_long * Ds)856 void DateCalc_Normalize_DHMS(Z_long *Dd, Z_long *Dh, Z_long *Dm, Z_long *Ds)
857 {
858     DateCalc_Normalize_Ranges(Dd,Dh,Dm,Ds);
859     *Ds += ((*Dh * 60L) + *Dm) * 60L;
860     DateCalc_Normalize_Signs(Dd,Dh,Dm,Ds);
861 }
862 
863 /*****************************************************************************/
864 
DateCalc_leap_year(Z_int year)865 boolean DateCalc_leap_year(Z_int year)
866 {
867     Z_int yy;
868 
869     return( ((year AND 0x03) == 0) and
870             ( (((yy = (Z_int) (year / 100)) * 100) != year) or
871                 ((yy AND 0x03) == 0) ) );
872 }
873 
DateCalc_check_date(Z_int year,Z_int month,Z_int day)874 boolean DateCalc_check_date(Z_int year, Z_int month, Z_int day)
875 {
876     if ((year >= 1) and
877         (month >= 1) and (month <= 12) and
878         (day >= 1) and
879         (day <= DateCalc_Days_in_Month_[DateCalc_leap_year(year)][month]))
880             return(true);
881     return(false);
882 }
883 
DateCalc_check_time(Z_int hour,Z_int min,Z_int sec)884 boolean DateCalc_check_time(Z_int hour, Z_int min, Z_int sec)
885 {
886     if ((hour >= 0) and (min >= 0) and (sec >= 0) and
887         (hour < 24) and (min < 60) and (sec < 60))
888             return(true);
889     return(false);
890 }
891 
DateCalc_check_business_date(Z_int year,Z_int week,Z_int dow)892 boolean DateCalc_check_business_date(Z_int year, Z_int week, Z_int dow)
893 {
894     if ((year >= 1) and
895         (week >= 1) and (week <= DateCalc_Weeks_in_Year(year)) and
896         (dow >= 1) and (dow <= 7))
897             return(true);
898     return(false);
899 }
900 
DateCalc_Day_of_Year(Z_int year,Z_int month,Z_int day)901 Z_int DateCalc_Day_of_Year(Z_int year, Z_int month, Z_int day)
902 {
903     boolean leap;
904 
905     if ((year >= 1) and
906         (month >= 1) and (month <= 12) and
907         (day >= 1) and
908         (day <= DateCalc_Days_in_Month_[leap=DateCalc_leap_year(year)][month]))
909             return( DateCalc_Days_in_Year_[leap][month] + day );
910     return(0);
911 }
912 
DateCalc_Date_to_Days(Z_int year,Z_int month,Z_int day)913 Z_long DateCalc_Date_to_Days(Z_int year, Z_int month, Z_int day)
914 {
915     boolean leap;
916 
917     if ((year >= 1) and
918         (month >= 1) and (month <= 12) and
919         (day >= 1) and
920         (day <= DateCalc_Days_in_Month_[leap=DateCalc_leap_year(year)][month]))
921             return( DateCalc_Year_to_Days(--year) +
922                     DateCalc_Days_in_Year_[leap][month] + day );
923     return(0L);
924 }
925 
DateCalc_Day_of_Week(Z_int year,Z_int month,Z_int day)926 Z_int DateCalc_Day_of_Week(Z_int year, Z_int month, Z_int day)
927 {
928     Z_long days;
929 
930     days = DateCalc_Date_to_Days(year,month,day);
931     if (days > 0L)
932     {
933         days--;
934         days %= 7L;
935         days++;
936     }
937     return( (Z_int) days );
938 }
939 
DateCalc_Weeks_in_Year(Z_int year)940 Z_int DateCalc_Weeks_in_Year(Z_int year)
941 {
942     return( 52 + ((DateCalc_Day_of_Week(year,1,1)   == 4) or
943                   (DateCalc_Day_of_Week(year,12,31) == 4)) );
944 }
945 
DateCalc_Week_Number(Z_int year,Z_int month,Z_int day)946 Z_int DateCalc_Week_Number(Z_int year, Z_int month, Z_int day)
947 {
948     Z_int first;
949 
950     first = DateCalc_Day_of_Week(year,1,1) - 1;
951     return( (Z_int)
952         ( (DateCalc_Delta_Days(year,1,1, year,month,day) + first) / 7L )
953         + (first < 4) );
954 }
955 
DateCalc_week_of_year(Z_int * week,Z_int * year,Z_int month,Z_int day)956 boolean DateCalc_week_of_year(Z_int *week,
957                               Z_int *year, Z_int month, Z_int day)
958 {
959     if (DateCalc_check_date(*year,month,day))
960     {
961         *week = DateCalc_Week_Number(*year,month,day);
962         if (*week == 0) *week = DateCalc_Weeks_in_Year(--(*year));
963         else if (*week > DateCalc_Weeks_in_Year(*year))
964         {
965             *week = 1;
966             (*year)++;
967         }
968         return(true);
969     }
970     return(false);
971 }
972 
DateCalc_monday_of_week(Z_int week,Z_int * year,Z_int * month,Z_int * day)973 boolean DateCalc_monday_of_week(Z_int  week,
974                                 Z_int *year, Z_int *month, Z_int *day)
975 {
976     Z_int first;
977 
978     *month = *day = 1;
979     first = DateCalc_Day_of_Week(*year,1,1) - 1;
980     if (first < 4) week--;
981     return( DateCalc_add_delta_days(year,month,day, (week * 7L - first)) );
982 }
983 
984 boolean
DateCalc_nth_weekday_of_month_year(Z_int * year,Z_int * month,Z_int * day,Z_int dow,Z_int n)985 DateCalc_nth_weekday_of_month_year(Z_int *year, Z_int *month, Z_int *day,
986                                    Z_int  dow,  Z_int  n)
987 {
988     Z_int  mm = *month;
989     Z_int  first;
990     Z_long delta;
991 
992     *day = 1;
993     if ((*year < 1) or
994         (mm < 1) or (mm > 12) or
995         (dow < 1) or (dow > 7) or
996         (n < 1) or (n > 5))
997         return(false);
998     first = DateCalc_Day_of_Week(*year,mm,1);
999     if (dow < first) dow += 7;
1000     delta = (Z_long) (dow - first);
1001     delta += (n-1) * 7L;
1002     if (DateCalc_add_delta_days(year,month,day,delta) and (*month == mm))
1003         return(true);
1004     return(false);
1005 }
1006 
DateCalc_standard_to_business(Z_int * year,Z_int * week,Z_int * dow,Z_int month,Z_int day)1007 boolean DateCalc_standard_to_business(Z_int *year,  Z_int *week, Z_int *dow,
1008                                       Z_int  month, Z_int  day)
1009 {
1010     Z_int yy = *year;
1011 
1012     if (DateCalc_week_of_year(week,year,month,day))
1013     {
1014         *dow = DateCalc_Day_of_Week(yy,month,day);
1015         return(true);
1016     }
1017     return(false);
1018 }
1019 
DateCalc_business_to_standard(Z_int * year,Z_int * month,Z_int * day,Z_int week,Z_int dow)1020 boolean DateCalc_business_to_standard(Z_int *year, Z_int *month, Z_int *day,
1021                                       Z_int  week, Z_int  dow)
1022 {
1023     Z_int  first;
1024     Z_long delta;
1025 
1026     if (DateCalc_check_business_date(*year,week,dow))
1027     {
1028         *month = *day = 1;
1029         first = DateCalc_Day_of_Week(*year,1,1);
1030         delta = ((week + (first > 4) - 1) * 7L) + (dow - first);
1031         return( DateCalc_add_delta_days(year,month,day,delta) );
1032     }
1033     return(false);
1034 }
1035 
DateCalc_Delta_Days(Z_int year1,Z_int month1,Z_int day1,Z_int year2,Z_int month2,Z_int day2)1036 Z_long DateCalc_Delta_Days(Z_int year1, Z_int month1, Z_int day1,
1037                            Z_int year2, Z_int month2, Z_int day2)
1038 {
1039     return( DateCalc_Date_to_Days(year2,month2,day2) -
1040             DateCalc_Date_to_Days(year1,month1,day1) );
1041 }
1042 
DateCalc_delta_hms(Z_long * Dd,Z_int * Dh,Z_int * Dm,Z_int * Ds,Z_int hour1,Z_int min1,Z_int sec1,Z_int hour2,Z_int min2,Z_int sec2)1043 boolean DateCalc_delta_hms(Z_long *Dd,
1044                            Z_int  *Dh,    Z_int *Dm,   Z_int *Ds,
1045                            Z_int   hour1, Z_int  min1, Z_int  sec1,
1046                            Z_int   hour2, Z_int  min2, Z_int  sec2)
1047 {
1048     Z_long HH;
1049     Z_long MM;
1050     Z_long SS;
1051 
1052     if (DateCalc_check_time(hour1,min1,sec1) and
1053         DateCalc_check_time(hour2,min2,sec2))
1054     {
1055         SS = ((((hour2 * 60L) + min2) * 60L) + sec2) -
1056              ((((hour1 * 60L) + min1) * 60L) + sec1);
1057         DateCalc_Normalize_Signs(Dd,&HH,&MM,&SS);
1058         *Dh = (Z_int) HH;
1059         *Dm = (Z_int) MM;
1060         *Ds = (Z_int) SS;
1061         return(true);
1062     }
1063     return(false);
1064 }
1065 
DateCalc_delta_dhms(Z_long * Dd,Z_int * Dh,Z_int * Dm,Z_int * Ds,Z_int year1,Z_int month1,Z_int day1,Z_int hour1,Z_int min1,Z_int sec1,Z_int year2,Z_int month2,Z_int day2,Z_int hour2,Z_int min2,Z_int sec2)1066 boolean DateCalc_delta_dhms(Z_long *Dd,
1067                             Z_int  *Dh,    Z_int *Dm,     Z_int *Ds,
1068                             Z_int   year1, Z_int  month1, Z_int  day1,
1069                             Z_int   hour1, Z_int  min1,   Z_int  sec1,
1070                             Z_int   year2, Z_int  month2, Z_int  day2,
1071                             Z_int   hour2, Z_int  min2,   Z_int  sec2)
1072 {
1073     *Dd = *Dh = *Dm = *Ds = 0;
1074     if (DateCalc_check_date(year1,month1,day1) and
1075         DateCalc_check_date(year2,month2,day2))
1076     {
1077         *Dd = DateCalc_Delta_Days(year1,month1,day1, year2,month2,day2);
1078         return( DateCalc_delta_hms(Dd,Dh,Dm,Ds,
1079                                    hour1,min1,sec1,
1080                                    hour2,min2,sec2) );
1081     }
1082     return(false);
1083 }
1084 
DateCalc_delta_ymd(Z_int * year1,Z_int * month1,Z_int * day1,Z_int year2,Z_int month2,Z_int day2)1085 boolean DateCalc_delta_ymd(Z_int *year1, Z_int *month1, Z_int *day1,
1086                            Z_int  year2, Z_int  month2, Z_int  day2)
1087 {
1088     if (DateCalc_check_date(*year1,*month1,*day1) and
1089         DateCalc_check_date(year2,month2,day2))
1090     {
1091         *day1   = day2   - *day1;
1092         *month1 = month2 - *month1;
1093         *year1  = year2  - *year1;
1094         return(true);
1095     }
1096     return(false);
1097 }
1098 
DateCalc_delta_ymdhms(Z_int * D_y,Z_int * D_m,Z_int * D_d,Z_int * Dh,Z_int * Dm,Z_int * Ds,Z_int year1,Z_int month1,Z_int day1,Z_int hour1,Z_int min1,Z_int sec1,Z_int year2,Z_int month2,Z_int day2,Z_int hour2,Z_int min2,Z_int sec2)1099 boolean DateCalc_delta_ymdhms(Z_int *D_y,   Z_int *D_m,    Z_int *D_d,
1100                               Z_int *Dh,    Z_int *Dm,     Z_int *Ds,
1101                               Z_int  year1, Z_int  month1, Z_int  day1,
1102                               Z_int  hour1, Z_int  min1,   Z_int  sec1,
1103                               Z_int  year2, Z_int  month2, Z_int  day2,
1104                               Z_int  hour2, Z_int  min2,   Z_int  sec2)
1105 {
1106     Z_long Dd;
1107 
1108     if (not DateCalc_delta_ymd(&year1,&month1,&day1, year2,month2,day2))
1109         return(false);
1110     Dd = (Z_long) day1;
1111     if (not DateCalc_delta_hms(&Dd,Dh,Dm,Ds, hour1,min1,sec1, hour2,min2,sec2))
1112         return(false);
1113     *D_y = year1;
1114     *D_m = month1;
1115     *D_d = (Z_int) Dd;
1116     return(true);
1117 }
1118 
DateCalc_norm_delta_ymd(Z_int * year1,Z_int * month1,Z_int * day1,Z_int year2,Z_int month2,Z_int day2)1119 boolean DateCalc_norm_delta_ymd(Z_int *year1, Z_int *month1, Z_int *day1,
1120                                 Z_int  year2, Z_int  month2, Z_int  day2)
1121 {
1122     Z_long Dy = 0L;
1123     Z_long Dm = 0L;
1124     Z_long Dd = 0L;
1125     Z_long d2;
1126     Z_int  ty;
1127     Z_int  tm;
1128     Z_int  td;
1129 
1130     if (DateCalc_check_date(*year1,*month1,*day1) and
1131         DateCalc_check_date(year2,month2,day2))
1132     {
1133         d2 =    DateCalc_Date_to_Days(year2,month2,day2);
1134         Dd = d2-DateCalc_Date_to_Days(*year1,*month1,*day1);
1135         if ((Dd < -30L) or (Dd > 30L))
1136         {
1137             Dy = (Z_long) (year2  - *year1);
1138             Dm = (Z_long) (month2 - *month1);
1139             ty=*year1; tm=*month1; td=*day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td);
1140             if (!(((Dy >= 0L) and (Dm >= 0L) and (Dd >= 0L)) or
1141                   ((Dy <= 0L) and (Dm <= 0L) and (Dd <= 0L))))
1142             {
1143                 if      ((Dy < 0L) and (Dm > 0L)) { Dy++; Dm -= 12L; }
1144                 else if ((Dy > 0L) and (Dm < 0L)) { Dy--; Dm += 12L; }
1145                 if      ((Dm < 0L) and (Dd > 0L)) { Dm++; ty=*year1; tm=*month1; td=*day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
1146                 else if ((Dm > 0L) and (Dd < 0L)) { Dm--; ty=*year1; tm=*month1; td=*day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
1147                 if      ((Dy < 0L) and (Dd > 0L)) { Dy++; Dm -= 12L; }
1148                 else if ((Dy > 0L) and (Dd < 0L)) { Dy--; Dm += 12L; }
1149                 if      ((Dm < 0L) and (Dd > 0L)) { Dm++; ty=*year1; tm=*month1; td=*day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
1150                 else if ((Dm > 0L) and (Dd < 0L)) { Dm--; ty=*year1; tm=*month1; td=*day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
1151             }
1152         }
1153         *year1  = (Z_int) Dy;
1154         *month1 = (Z_int) Dm;
1155         *day1   = (Z_int) Dd;
1156         return(true);
1157     }
1158     return(false);
1159 }
1160 
DateCalc_norm_delta_ymdhms(Z_int * D_y,Z_int * D_m,Z_int * D_d,Z_int * Dhh,Z_int * Dmm,Z_int * Dss,Z_int year1,Z_int month1,Z_int day1,Z_int hour1,Z_int min1,Z_int sec1,Z_int year2,Z_int month2,Z_int day2,Z_int hour2,Z_int min2,Z_int sec2)1161 boolean DateCalc_norm_delta_ymdhms(Z_int *D_y,   Z_int *D_m,    Z_int *D_d,
1162                                    Z_int *Dhh,   Z_int *Dmm,    Z_int *Dss,
1163                                    Z_int  year1, Z_int  month1, Z_int  day1,
1164                                    Z_int  hour1, Z_int  min1,   Z_int  sec1,
1165                                    Z_int  year2, Z_int  month2, Z_int  day2,
1166                                    Z_int  hour2, Z_int  min2,   Z_int  sec2)
1167 {
1168     Z_long Dy = 0L;
1169     Z_long Dm = 0L;
1170     Z_long Dd = 0L;
1171     Z_long d2, hh, mm, ss;
1172     Z_int  ty;
1173     Z_int  tm;
1174     Z_int  td;
1175 
1176     if (DateCalc_check_date(year1,month1,day1) and
1177         DateCalc_check_time(hour1,min1,  sec1) and
1178         DateCalc_check_date(year2,month2,day2) and
1179         DateCalc_check_time(hour1,min2,  sec2))
1180     {
1181         ss = ( (hour2-hour1) * 60L + (min2-min1) ) * 60L + (sec2-sec1);
1182         d2 =    DateCalc_Date_to_Days(year2,month2,day2);
1183         Dd = d2-DateCalc_Date_to_Days(year1,month1,day1);
1184         if ((Dd < -30L) or (Dd > 30L))
1185         {
1186             Dy = (Z_long) (year2  - year1);
1187             Dm = (Z_long) (month2 - month1);
1188             ty=year1; tm=month1; td=day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td);
1189             if (!(((Dy >= 0L) and (Dm >= 0L) and (Dd >= 0L) and (ss >= 0L)) or
1190                   ((Dy <= 0L) and (Dm <= 0L) and (Dd <= 0L) and (ss <= 0L))))
1191             {
1192                 if      ((Dy < 0L) and (Dm > 0L)) { Dy++; Dm -= 12L; }
1193                 else if ((Dy > 0L) and (Dm < 0L)) { Dy--; Dm += 12L; }
1194                 if      ((Dm < 0L) and (Dd > 0L)) { Dm++; ty=year1; tm=month1; td=day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
1195                 else if ((Dm > 0L) and (Dd < 0L)) { Dm--; ty=year1; tm=month1; td=day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
1196                 if      ((Dy < 0L) and (Dd > 0L)) { Dy++; Dm -= 12L; }
1197                 else if ((Dy > 0L) and (Dd < 0L)) { Dy--; Dm += 12L; }
1198                 if      ((Dm < 0L) and (Dd > 0L)) { Dm++; ty=year1; tm=month1; td=day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
1199                 else if ((Dm > 0L) and (Dd < 0L)) { Dm--; ty=year1; tm=month1; td=day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
1200                 if      ((Dd < 0L) and (ss > 0L)) { Dd++; ss -= 86400L; }
1201                 else if ((Dd > 0L) and (ss < 0L)) { Dd--; ss += 86400L; }
1202                 if      ((Dm < 0L) and (ss > 0L)) { Dm++; ty=year1; tm=month1; td=day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
1203                 else if ((Dm > 0L) and (ss < 0L)) { Dm--; ty=year1; tm=month1; td=day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
1204                 if      ((Dy < 0L) and (ss > 0L)) { Dy++; Dm -= 12L; }
1205                 else if ((Dy > 0L) and (ss < 0L)) { Dy--; Dm += 12L; }
1206                 if      ((Dm < 0L) and (ss > 0L)) { Dm++; ty=year1; tm=month1; td=day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
1207                 else if ((Dm > 0L) and (ss < 0L)) { Dm--; ty=year1; tm=month1; td=day1; if (!DateCalc_add_delta_ym(&ty,&tm,&td,Dy,Dm)) return(false); Dd=d2-DateCalc_Date_to_Days(ty,tm,td); }
1208                 if      ((Dd < 0L) and (ss > 0L)) { Dd++; ss -= 86400L; }
1209                 else if ((Dd > 0L) and (ss < 0L)) { Dd--; ss += 86400L; }
1210             }
1211         }
1212         else
1213         {
1214             if      ((Dd < 0L) and (ss > 0L)) { Dd++; ss -= 86400L; }
1215             else if ((Dd > 0L) and (ss < 0L)) { Dd--; ss += 86400L; }
1216         }
1217         mm = (Z_long) ( ss / 60 );
1218         ss -= mm * 60;
1219         hh = (Z_long) ( mm / 60 );
1220         mm -= hh * 60;
1221         *D_y    = (Z_int) Dy;
1222         *D_m    = (Z_int) Dm;
1223         *D_d    = (Z_int) Dd;
1224         *Dhh    = (Z_int) hh;
1225         *Dmm    = (Z_int) mm;
1226         *Dss    = (Z_int) ss;
1227         return(true);
1228     }
1229     return(false);
1230 }
1231 
DateCalc_add_delta_days(Z_int * year,Z_int * month,Z_int * day,Z_long Dd)1232 boolean DateCalc_add_delta_days(Z_int *year, Z_int *month, Z_int *day,
1233                                                            Z_long Dd)
1234 {
1235     Z_long  days;
1236     boolean leap;
1237 
1238     if (((days = DateCalc_Date_to_Days(*year,*month,*day)) > 0L) and
1239         ((days += Dd) > 0L))
1240     {
1241         if (Dd != 0L)
1242         {
1243             *year = (Z_int) ( days / 365.2425 );
1244             *day  = (Z_int) ( days - DateCalc_Year_to_Days(*year) );
1245             if (*day < 1)
1246             {
1247                 *day = (Z_int) ( days - DateCalc_Year_to_Days(*year-1) );
1248             }
1249             else (*year)++;
1250             leap = DateCalc_leap_year(*year);
1251             if (*day > DateCalc_Days_in_Year_[leap][13])
1252             {
1253                 *day -= DateCalc_Days_in_Year_[leap][13];
1254                 leap  = DateCalc_leap_year(++(*year));
1255             }
1256             for ( *month = 12; *month >= 1; (*month)-- )
1257             {
1258                 if (*day > DateCalc_Days_in_Year_[leap][*month])
1259                 {
1260                     *day -= DateCalc_Days_in_Year_[leap][*month];
1261                     break;
1262                 }
1263             }
1264         }
1265         return(true);
1266     }
1267     return(false);
1268 }
1269 
DateCalc_add_delta_dhms(Z_int * year,Z_int * month,Z_int * day,Z_int * hour,Z_int * min,Z_int * sec,Z_long Dd,Z_long Dh,Z_long Dm,Z_long Ds)1270 boolean DateCalc_add_delta_dhms(Z_int *year, Z_int *month, Z_int *day,
1271                                 Z_int *hour, Z_int *min,   Z_int *sec,
1272                                 Z_long Dd,
1273                                 Z_long Dh,   Z_long Dm,    Z_long Ds)
1274 {
1275     if (DateCalc_check_date(*year,*month,*day) and
1276         DateCalc_check_time(*hour,*min,*sec))
1277     {
1278         DateCalc_Normalize_Ranges(&Dd,&Dh,&Dm,&Ds);
1279         Ds += ((((*hour * 60L) + *min) * 60L) + *sec) +
1280                ((( Dh   * 60L) +  Dm)  * 60L);
1281         while (Ds < 0L)
1282         {
1283             Ds += 86400L;
1284             Dd--;
1285         }
1286         if (Ds > 0L)
1287         {
1288             Dh = 0L;
1289             Dm = 0L;
1290             DateCalc_Normalize_Time(&Dd,&Dh,&Dm,&Ds);
1291             *hour = (Z_int) Dh;
1292             *min  = (Z_int) Dm;
1293             *sec  = (Z_int) Ds;
1294         }
1295         else *hour = *min = *sec = 0;
1296         return( DateCalc_add_delta_days(year,month,day,Dd) );
1297     }
1298     return(false);
1299 }
1300 
DateCalc_add_year_month(Z_int * year,Z_int * month,Z_long Dy,Z_long Dm)1301 boolean DateCalc_add_year_month(Z_int *year, Z_int *month,
1302                                 Z_long Dy,   Z_long Dm)
1303 {
1304     Z_long quot;
1305 
1306     if ((*year < 1) or (*month < 1) or (*month > 12)) return(false);
1307     if (Dm != 0L)
1308     {
1309         Dm  += (Z_long) (*month - 1);
1310         quot = (Z_long) (Dm / 12L);
1311         Dm  -= quot * 12L;
1312         if (Dm < 0L)
1313         {
1314             Dm += 12L;
1315             quot--;
1316         }
1317         *month = (Z_int) (Dm + 1);
1318         Dy += quot;
1319     }
1320     if (Dy != 0L)
1321     {
1322         Dy += (Z_long) *year;
1323         *year = (Z_int) Dy;
1324     }
1325     if (*year < 1) return(false);
1326     return(true);
1327 }
1328 
DateCalc_add_delta_ym(Z_int * year,Z_int * month,Z_int * day,Z_long Dy,Z_long Dm)1329 boolean DateCalc_add_delta_ym(Z_int *year, Z_int *month, Z_int *day,
1330                               Z_long Dy,   Z_long Dm)
1331 {
1332     Z_int Dd;
1333 
1334     if (not DateCalc_check_date(*year,*month,*day)) return(false);
1335     if (not DateCalc_add_year_month(year,month,Dy,Dm)) return(false);
1336     if (*day >
1337         (Dd = DateCalc_Days_in_Month_[DateCalc_leap_year(*year)][*month]))
1338             *day = Dd;
1339     return(true);
1340 }
1341 
DateCalc_add_delta_ymd(Z_int * year,Z_int * month,Z_int * day,Z_long Dy,Z_long Dm,Z_long Dd)1342 boolean DateCalc_add_delta_ymd(Z_int *year, Z_int *month, Z_int *day,
1343                                Z_long Dy,   Z_long Dm,    Z_long Dd)
1344 {
1345     if (not DateCalc_check_date(*year,*month,*day)) return(false);
1346     if (not DateCalc_add_year_month(year,month,Dy,Dm)) return(false);
1347     Dd += (Z_long) (*day - 1);
1348     *day = 1;
1349     return( DateCalc_add_delta_days(year,month,day,Dd) );
1350 }
1351 
DateCalc_add_delta_ymdhms(Z_int * year,Z_int * month,Z_int * day,Z_int * hour,Z_int * min,Z_int * sec,Z_long D_y,Z_long D_m,Z_long D_d,Z_long Dh,Z_long Dm,Z_long Ds)1352 boolean DateCalc_add_delta_ymdhms(Z_int *year, Z_int *month, Z_int *day,
1353                                   Z_int *hour, Z_int *min,   Z_int *sec,
1354                                   Z_long D_y,  Z_long D_m,   Z_long D_d,
1355                                   Z_long Dh,   Z_long Dm,    Z_long Ds)
1356 {
1357     if (not (DateCalc_check_date(*year,*month,*day) and
1358              DateCalc_check_time(*hour,*min,*sec))) return(false);
1359     if (not  DateCalc_add_year_month(year,month,D_y,D_m)) return(false);
1360     D_d += (Z_long) (*day - 1);
1361     *day = 1;
1362     return( DateCalc_add_delta_dhms(year,month,day,hour,min,sec,D_d,Dh,Dm,Ds) );
1363 }
1364 
DateCalc_add_norm_delta_ymd(Z_int * year,Z_int * month,Z_int * day,Z_long Dy,Z_long Dm,Z_long Dd)1365 boolean DateCalc_add_norm_delta_ymd(Z_int *year, Z_int *month, Z_int *day,
1366                                     Z_long Dy,   Z_long Dm,    Z_long Dd)
1367 {
1368     if (not DateCalc_add_delta_ym(year,month,day,Dy,Dm)) return(false);
1369     return( DateCalc_add_delta_days(year,month,day,Dd) );
1370 }
1371 
DateCalc_add_norm_delta_ymdhms(Z_int * year,Z_int * month,Z_int * day,Z_int * hour,Z_int * min,Z_int * sec,Z_long D_y,Z_long D_m,Z_long D_d,Z_long Dh,Z_long Dm,Z_long Ds)1372 boolean DateCalc_add_norm_delta_ymdhms(Z_int *year, Z_int *month, Z_int *day,
1373                                        Z_int *hour, Z_int *min,   Z_int *sec,
1374                                        Z_long D_y,  Z_long D_m,   Z_long D_d,
1375                                        Z_long Dh,   Z_long Dm,    Z_long Ds)
1376 {
1377     if (not DateCalc_add_delta_ym(year,month,day,D_y,D_m)) return(false);
1378     return( DateCalc_add_delta_dhms(year,month,day,hour,min,sec,D_d,Dh,Dm,Ds) );
1379 }
1380 
DateCalc_system_clock(Z_int * year,Z_int * month,Z_int * day,Z_int * hour,Z_int * min,Z_int * sec,Z_int * doy,Z_int * dow,Z_int * dst,boolean gmt)1381 boolean DateCalc_system_clock(Z_int  *year, Z_int *month, Z_int *day,
1382                               Z_int  *hour, Z_int *min,   Z_int *sec,
1383                               Z_int  *doy,  Z_int *dow,   Z_int *dst,
1384                               boolean gmt)
1385 {
1386     time_t seconds;
1387     struct tm *date;
1388 
1389     if (time(&seconds) >= 0)
1390     {
1391         if (gmt) date = gmtime(&seconds);
1392         else     date = localtime(&seconds);
1393         if (date != NULL)
1394         {
1395             *year  = (*date).tm_year + 1900;
1396             *month = (*date).tm_mon + 1;
1397             *day   = (*date).tm_mday;
1398             *hour  = (*date).tm_hour;
1399             *min   = (*date).tm_min;
1400             *sec   = (*date).tm_sec;
1401             *doy   = (*date).tm_yday + 1;
1402             *dow   = (*date).tm_wday; if (*dow == 0) *dow = 7;
1403             *dst   = (*date).tm_isdst;
1404             if (*dst != 0)
1405             {
1406                 if (*dst < 0) *dst = -1;
1407                 else          *dst =  1;
1408             }
1409             return(true);
1410         }
1411     }
1412     return(false);
1413 }
1414 
DateCalc_gmtime(Z_int * year,Z_int * month,Z_int * day,Z_int * hour,Z_int * min,Z_int * sec,Z_int * doy,Z_int * dow,Z_int * dst,time_t seconds)1415 boolean DateCalc_gmtime(Z_int  *year, Z_int *month, Z_int *day,
1416                         Z_int  *hour, Z_int *min,   Z_int *sec,
1417                         Z_int  *doy,  Z_int *dow,   Z_int *dst,
1418                         time_t  seconds)
1419 {
1420     struct tm *date;
1421 
1422     if ((seconds >= 0) and ((date = gmtime(&seconds)) != NULL))
1423     {
1424         *year  = (*date).tm_year + 1900;
1425         *month = (*date).tm_mon + 1;
1426         *day   = (*date).tm_mday;
1427         *hour  = (*date).tm_hour;
1428         *min   = (*date).tm_min;
1429         *sec   = (*date).tm_sec;
1430         *doy   = (*date).tm_yday + 1;
1431         *dow   = (*date).tm_wday; if (*dow == 0) *dow = 7;
1432         *dst   = (*date).tm_isdst;
1433         if (*dst != 0)
1434         {
1435             if (*dst < 0) *dst = -1;
1436             else          *dst =  1;
1437         }
1438         return(true);
1439     }
1440     return(false);
1441 }
1442 
DateCalc_localtime(Z_int * year,Z_int * month,Z_int * day,Z_int * hour,Z_int * min,Z_int * sec,Z_int * doy,Z_int * dow,Z_int * dst,time_t seconds)1443 boolean DateCalc_localtime(Z_int  *year, Z_int *month, Z_int *day,
1444                            Z_int  *hour, Z_int *min,   Z_int *sec,
1445                            Z_int  *doy,  Z_int *dow,   Z_int *dst,
1446                            time_t  seconds)
1447 {
1448     struct tm *date;
1449 
1450     if ((seconds >= 0) and ((date = localtime(&seconds)) != NULL))
1451     {
1452         *year  = (*date).tm_year + 1900;
1453         *month = (*date).tm_mon + 1;
1454         *day   = (*date).tm_mday;
1455         *hour  = (*date).tm_hour;
1456         *min   = (*date).tm_min;
1457         *sec   = (*date).tm_sec;
1458         *doy   = (*date).tm_yday + 1;
1459         *dow   = (*date).tm_wday; if (*dow == 0) *dow = 7;
1460         *dst   = (*date).tm_isdst;
1461         if (*dst != 0)
1462         {
1463             if (*dst < 0) *dst = -1;
1464             else          *dst =  1;
1465         }
1466         return(true);
1467     }
1468     return(false);
1469 }
1470 
1471 /* MacOS (Classic):                                            */
1472 /* <695056.0>     = Fri  1-Jan-1904 00:00:00 (time=0x00000000) */
1473 /* <744766.23295> = Mon  6-Feb-2040 06:28:15 (time=0xFFFFFFFF) */
1474 
1475 /* Unix:                                                       */
1476 /* <719163.0>     = Thu  1-Jan-1970 00:00:00 (time=0x00000000) */
1477 /* <744018.11647> = Tue 19-Jan-2038 03:14:07 (time=0x7FFFFFFF) */
1478 
DateCalc_mktime(time_t * seconds,Z_int year,Z_int month,Z_int day,Z_int hour,Z_int min,Z_int sec,Z_int doy,Z_int dow,Z_int dst)1479 boolean DateCalc_mktime(time_t *seconds,
1480                         Z_int year, Z_int month, Z_int day,
1481                         Z_int hour, Z_int min,   Z_int sec,
1482                         Z_int doy,  Z_int dow,   Z_int dst)
1483 {
1484     struct tm date;
1485 
1486     *seconds = (time_t) 0;
1487 
1488 #ifdef MACOS_TRADITIONAL
1489     if ( (year  < 1904) or (year  > 2040) or
1490 #else
1491     if ( (year  < 1970) or (year  > 2038) or
1492 #endif
1493          (month <    1) or (month >   12) or
1494          (day   <    1) or (day   >   31) or
1495          (hour  <    0) or (hour  >   23) or
1496          (min   <    0) or (min   >   59) or
1497          (sec   <    0) or (sec   >   59) )
1498     return(false);
1499 
1500 #ifdef MACOS_TRADITIONAL
1501     if ( (year == 2040) and ( (month >  2) or
1502                             ( (month == 2) and ( (day >  6) or
1503                                                ( (day == 6) and ( (hour >  6) or
1504                                                                 ( (hour == 6) and ( (min >  28) or
1505                                                                                   ( (min == 28) and (sec > 15) ) ))))))) )
1506     return(false);
1507 #else
1508     if ( (year == 2038) and ( (month >  1) or
1509                             ( (month == 1) and ( (day >  19) or
1510                                                ( (day == 19) and ( (hour >  3) or
1511                                                                  ( (hour == 3) and ( (min >  14) or
1512                                                                                    ( (min == 14) and (sec > 7) ) ))))))) )
1513     return(false);
1514 #endif
1515 
1516     year -= 1900;
1517     month--;
1518     if (doy <= 0) doy = -1;
1519     else          doy--;
1520     if (dow <= 0) dow = -1; else
1521     if (dow == 7) dow =  0;
1522     if (dst != 0)
1523     {
1524         if (dst < 0) dst = -1;
1525         else         dst =  1;
1526     }
1527     date.tm_year  = year;
1528     date.tm_mon   = month;
1529     date.tm_mday  = day;
1530     date.tm_hour  = hour;
1531     date.tm_min   = min;
1532     date.tm_sec   = sec;
1533     date.tm_yday  = doy;
1534     date.tm_wday  = dow;
1535     date.tm_isdst = dst;
1536     *seconds = mktime(&date);
1537     return(*seconds >= 0);
1538 }
1539 
DateCalc_timezone(Z_int * year,Z_int * month,Z_int * day,Z_int * hour,Z_int * min,Z_int * sec,Z_int * dst,time_t when)1540 boolean DateCalc_timezone(Z_int *year, Z_int *month, Z_int *day,
1541                           Z_int *hour, Z_int *min,   Z_int *sec,
1542                           Z_int *dst,  time_t when)
1543 {
1544     struct tm *date;
1545     Z_int  year1;
1546     Z_int  month1;
1547     Z_int  day1;
1548     Z_int  hour1;
1549     Z_int  min1;
1550     Z_int  sec1;
1551     Z_int  year2;
1552     Z_int  month2;
1553     Z_int  day2;
1554     Z_int  hour2;
1555     Z_int  min2;
1556     Z_int  sec2;
1557 
1558     if (when >= 0)
1559     {
1560         if ((date = gmtime(&when)) == NULL) return(false);
1561         year1  = (*date).tm_year + 1900;
1562         month1 = (*date).tm_mon + 1;
1563         day1   = (*date).tm_mday;
1564         hour1  = (*date).tm_hour;
1565         min1   = (*date).tm_min;
1566         sec1   = (*date).tm_sec;
1567         if ((date = localtime(&when)) == NULL) return(false);
1568         year2  = (*date).tm_year + 1900;
1569         month2 = (*date).tm_mon + 1;
1570         day2   = (*date).tm_mday;
1571         hour2  = (*date).tm_hour;
1572         min2   = (*date).tm_min;
1573         sec2   = (*date).tm_sec;
1574         if (DateCalc_delta_ymdhms(year, month, day,  hour, min, sec,
1575                                   year1,month1,day1, hour1,min1,sec1,
1576                                   year2,month2,day2, hour2,min2,sec2))
1577         {
1578             *dst = (*date).tm_isdst;
1579             if (*dst != 0)
1580             {
1581                 if (*dst < 0) *dst = -1;
1582                 else          *dst =  1;
1583             }
1584             return(true);
1585         }
1586     }
1587     return(false);
1588 }
1589 
1590 /* MacOS (Classic):                                            */
1591 /* <695056.0>     = Fri  1-Jan-1904 00:00:00 (time=0x00000000) */
1592 /* <744766.23295> = Mon  6-Feb-2040 06:28:15 (time=0xFFFFFFFF) */
1593 
1594 /* Unix:                                                       */
1595 /* <719163.0>     = Thu  1-Jan-1970 00:00:00 (time=0x00000000) */
1596 /* <744018.11647> = Tue 19-Jan-2038 03:14:07 (time=0x7FFFFFFF) */
1597 
1598 #ifdef MACOS_TRADITIONAL
1599     #define DateCalc_DAYS_TO_EPOCH  695056L
1600     #define DateCalc_DAYS_TO_OVFLW  744766L
1601     #define DateCalc_SECS_TO_OVFLW   23295L
1602 #else
1603     #define DateCalc_DAYS_TO_EPOCH  719163L
1604     #define DateCalc_DAYS_TO_OVFLW  744018L
1605     #define DateCalc_SECS_TO_OVFLW   11647L
1606 #endif
1607 
1608 /* Substitute for BSD's timegm(3) function: */
1609 
DateCalc_date2time(time_t * seconds,Z_int year,Z_int month,Z_int day,Z_int hour,Z_int min,Z_int sec)1610 boolean DateCalc_date2time(time_t *seconds,
1611                            Z_int year, Z_int month, Z_int day,
1612                            Z_int hour, Z_int min,   Z_int sec)
1613 {
1614     Z_long days;
1615 #ifdef MACOS_TRADITIONAL
1616     N_long secs;
1617 #else
1618     Z_long secs;
1619 #endif
1620 
1621     *seconds = (time_t) 0;
1622 
1623     days = DateCalc_Date_to_Days(year,month,day);
1624     secs = (((hour * 60L) + min) * 60L) + sec;
1625 
1626     if (   (days <  DateCalc_DAYS_TO_EPOCH) or
1627 #ifndef MACOS_TRADITIONAL
1628            (secs <  0L) or
1629 #endif
1630            (days >  DateCalc_DAYS_TO_OVFLW) or
1631          ( (days == DateCalc_DAYS_TO_OVFLW) and (secs > DateCalc_SECS_TO_OVFLW) ) )
1632     return(false);
1633 
1634     *seconds = (time_t) (((days - DateCalc_DAYS_TO_EPOCH) * 86400L) + secs);
1635     return(true);
1636 }
1637 
1638 /* Substitute for POSIX's gmtime(3) function: */
1639 
DateCalc_time2date(Z_int * year,Z_int * month,Z_int * day,Z_int * hour,Z_int * min,Z_int * sec,time_t seconds)1640 boolean DateCalc_time2date(Z_int *year, Z_int *month, Z_int *day,
1641                            Z_int *hour, Z_int *min,   Z_int *sec,
1642                            time_t seconds)
1643 {
1644 #ifdef MACOS_TRADITIONAL
1645     N_long ss = (N_long) seconds;
1646     N_long mm;
1647     N_long hh;
1648     N_long dd;
1649 
1650     dd = (N_long) (ss / 86400L);
1651     ss -= dd * 86400L;
1652     mm = (N_long) (ss / 60L);
1653     ss -= mm * 60L;
1654     hh = (N_long) (mm / 60L);
1655 #else
1656     Z_long ss = (Z_long) seconds;
1657     Z_long mm;
1658     Z_long hh;
1659     Z_long dd;
1660 
1661     if (ss < 0L) return(false);
1662     dd = (Z_long) (ss / 86400L);
1663     ss -= dd * 86400L;
1664     mm = (Z_long) (ss / 60L);
1665     ss -= mm * 60L;
1666     hh = (Z_long) (mm / 60L);
1667 #endif
1668 
1669     mm -= hh * 60L;
1670     dd += (DateCalc_DAYS_TO_EPOCH-1L);
1671     *sec   = (Z_int) ss;
1672     *min   = (Z_int) mm;
1673     *hour  = (Z_int) hh;
1674     *day   = (Z_int) 1;
1675     *month = (Z_int) 1;
1676     *year  = (Z_int) 1;
1677     return( DateCalc_add_delta_days(year,month,day,dd) );
1678 }
1679 
DateCalc_easter_sunday(Z_int * year,Z_int * month,Z_int * day)1680 boolean DateCalc_easter_sunday(Z_int *year, Z_int *month, Z_int *day)
1681 {
1682     /****************************************************************/
1683     /*                                                              */
1684     /*  Gauss'sche Regel (Gaussian Rule)                            */
1685     /*  ================================                            */
1686     /*                                                              */
1687     /*  Quelle / Source:                                            */
1688     /*                                                              */
1689     /*  H. H. Voigt, "Abriss der Astronomie", Wissenschaftsverlag,  */
1690     /*  Bibliographisches Institut, Seite 9.                        */
1691     /*                                                              */
1692     /****************************************************************/
1693 
1694     Z_int a, b, c, d, e, m, n;
1695 
1696     if ((*year < 1583) or (*year > 2299)) return(false);
1697 
1698     if      (*year < 1700) { m = 22; n = 2; }
1699     else if (*year < 1800) { m = 23; n = 3; }
1700     else if (*year < 1900) { m = 23; n = 4; }
1701     else if (*year < 2100) { m = 24; n = 5; }
1702     else if (*year < 2200) { m = 24; n = 6; }
1703     else                   { m = 25; n = 0; }
1704 
1705     a = *year % 19;
1706     b = *year % 4;
1707     c = *year % 7;
1708     d = (19 * a + m) % 30;
1709     e = (2 * b + 4 * c + 6 * d + n) % 7;
1710     *day = 22 + d + e;
1711     *month = 3;
1712     if (*day > 31)
1713     {
1714         *day -= 31; /* same as *day = d + e - 9; */
1715         (*month)++;
1716     }
1717     if ((*day == 26) and (*month == 4)) *day = 19;
1718     if ((*day == 25) and (*month == 4) and
1719         (d == 28) and (e == 6) and (a > 10)) *day = 18;
1720     return(true);
1721 }
1722 
1723 /*  Carnival Monday / Rosenmontag / Veille du Mardi Gras   =  easter sunday - 48  */
1724 /*  Mardi Gras / Karnevalsdienstag / Mardi Gras            =  easter sunday - 47  */
1725 /*  Ash Wednesday / Aschermittwoch / Mercredi des Cendres  =  easter sunday - 46  */
1726 /*  Palm Sunday / Palmsonntag / Dimanche des Rameaux       =  easter sunday - 7   */
1727 /*  Easter Friday / Karfreitag / Vendredi Saint            =  easter sunday - 2   */
1728 /*  Easter Saturday / Ostersamstag / Samedi de Paques      =  easter sunday - 1   */
1729 /*  Easter Monday / Ostermontag / Lundi de Paques          =  easter sunday + 1   */
1730 /*  Ascension of Christ / Christi Himmelfahrt / Ascension  =  easter sunday + 39  */
1731 /*  Whitsunday / Pfingstsonntag / Dimanche de Pentecote    =  easter sunday + 49  */
1732 /*  Whitmonday / Pfingstmontag / Lundi de Pentecote        =  easter sunday + 50  */
1733 /*  Feast of Corpus Christi / Fronleichnam / Fete-Dieu     =  easter sunday + 60  */
1734 
DateCalc_Decode_Month(charptr buffer,Z_int length,Z_int lang)1735 Z_int DateCalc_Decode_Month(charptr buffer, Z_int length, Z_int lang) /* 0 = error */
1736 {
1737     Z_int   i,j;
1738     Z_int   month;
1739     boolean same;
1740     boolean ok;
1741 
1742 /*****************************************************************************/
1743 /*  BEWARE that the parameter "length" must always be set in such a way      */
1744 /*  so that the string in "buffer[0]" up to "buffer[length-1]" does not      */
1745 /*  contain any terminating null character '\0'. Otherwise this routine      */
1746 /*  may read beyond allocated memory, probably resulting in an access        */
1747 /*  violation and program abortion. This problem cannot arise, for example,  */
1748 /*  if you use the library function "strlen" to determine the length         */
1749 /*  "length" of the string in "buffer".                                      */
1750 /*****************************************************************************/
1751 
1752     if ((lang < 1) or (lang > DateCalc_LANGUAGES)) lang = DateCalc_Language;
1753     month = 0;
1754     ok = true;
1755     for ( i = 1; ok and (i <= 12); i++ )
1756     {
1757         same = true;
1758         for ( j = 0; same and (j < length); j++ )
1759         {
1760             same = ( DateCalc_ISO_UC(buffer[j]) ==
1761                      DateCalc_ISO_UC(DateCalc_Month_to_Text_[lang][i][j]) );
1762         }
1763         if (same)
1764         {
1765             if (month > 0) ok = false;
1766             else           month = i;
1767         }
1768     }
1769     if (ok) return(month);
1770     else return(0);
1771 }
1772 
DateCalc_Decode_Day_of_Week(charptr buffer,Z_int length,Z_int lang)1773 Z_int DateCalc_Decode_Day_of_Week(charptr buffer, Z_int length, Z_int lang) /* 0 = error */
1774 {
1775     Z_int   i,j;
1776     Z_int   day;
1777     boolean same;
1778     boolean ok;
1779 
1780 /*****************************************************************************/
1781 /*  BEWARE that the parameter "length" must always be set in such a way      */
1782 /*  so that the string in "buffer[0]" up to "buffer[length-1]" does not      */
1783 /*  contain any terminating null character '\0'. Otherwise this routine      */
1784 /*  may read beyond allocated memory, probably resulting in an access        */
1785 /*  violation and program abortion. This problem cannot arise, for example,  */
1786 /*  if you use the library function "strlen" to determine the length         */
1787 /*  "length" of the string in "buffer".                                      */
1788 /*****************************************************************************/
1789 
1790     if ((lang < 1) or (lang > DateCalc_LANGUAGES)) lang = DateCalc_Language;
1791     day = 0;
1792     ok = true;
1793     for ( i = 1; ok and (i <= 7); i++ )
1794     {
1795         same = true;
1796         for ( j = 0; same and (j < length); j++ )
1797         {
1798             same = ( DateCalc_ISO_UC(buffer[j]) ==
1799                      DateCalc_ISO_UC(DateCalc_Day_of_Week_to_Text_[lang][i][j]) );
1800         }
1801         if (same)
1802         {
1803             if (day > 0) ok = false;
1804             else         day = i;
1805         }
1806     }
1807     if (ok) return(day);
1808     else return(0);
1809 }
1810 
DateCalc_Decode_Language(charptr buffer,Z_int length)1811 Z_int DateCalc_Decode_Language(charptr buffer, Z_int length) /* 0 = error */
1812 {
1813     Z_int   i,j;
1814     Z_int   lang;
1815     boolean same;
1816     boolean ok;
1817 
1818 /*****************************************************************************/
1819 /*  BEWARE that the parameter "length" must always be set in such a way      */
1820 /*  so that the string in "buffer[0]" up to "buffer[length-1]" does not      */
1821 /*  contain any terminating null character '\0'. Otherwise this routine      */
1822 /*  may read beyond allocated memory, probably resulting in an access        */
1823 /*  violation and program abortion. This problem cannot arise, for example,  */
1824 /*  if you use the library function "strlen" to determine the length         */
1825 /*  "length" of the string in "buffer".                                      */
1826 /*****************************************************************************/
1827 
1828     lang = 0;
1829     ok = true;
1830     for ( i = 1; ok and (i <= DateCalc_LANGUAGES); i++ )
1831     {
1832         same = true;
1833         for ( j = 0; same and (j < length); j++ )
1834         {
1835             same = ( DateCalc_ISO_UC(buffer[j]) ==
1836                      DateCalc_ISO_UC(DateCalc_Language_to_Text_[i][j]) );
1837         }
1838         if (same)
1839         {
1840             if (lang > 0) ok = false;
1841             else          lang = i;
1842         }
1843     }
1844     if (ok) return(lang);
1845     else return(0);
1846 }
1847 
DateCalc_decode_date_eu(charptr buffer,Z_int * year,Z_int * month,Z_int * day,Z_int lang)1848 boolean DateCalc_decode_date_eu(charptr buffer,
1849                                 Z_int *year, Z_int *month, Z_int *day, Z_int lang)
1850 {
1851     Z_int i,j;
1852     Z_int length;
1853 
1854     if ((lang < 1) or (lang > DateCalc_LANGUAGES)) lang = DateCalc_Language;
1855     *year = *month = *day = 0;
1856     length = strlen((char *)buffer);
1857     if (length > 0)
1858     {
1859         i = 0;
1860         while (DateCalc_scan9(buffer,length,i,true)) i++;
1861         j = length-1;
1862         while (DateCalc_scan9(buffer,length,j,true)) j--;
1863         if (i+1 < j)        /* at least 3 chars, else error! */
1864         {
1865             buffer += i;
1866             length = j-i+1;
1867             i = 1;
1868             while (DateCalc_scan9(buffer,length,i,false)) i++;
1869             j = length-2;
1870             while (DateCalc_scan9(buffer,length,j,false)) j--;
1871             if (j < i)  /* only numerical chars without delimiters */
1872             {
1873                 switch (length)
1874                 {
1875                 case 3:
1876                     *day   = DateCalc_Str2Int(buffer,  1);
1877                     *month = DateCalc_Str2Int(buffer+1,1);
1878                     *year  = DateCalc_Str2Int(buffer+2,1);
1879                     break;
1880                 case 4:
1881                     *day   = DateCalc_Str2Int(buffer,  1);
1882                     *month = DateCalc_Str2Int(buffer+1,1);
1883                     *year  = DateCalc_Str2Int(buffer+2,2);
1884                     break;
1885                 case 5:
1886                     *day   = DateCalc_Str2Int(buffer,  1);
1887                     *month = DateCalc_Str2Int(buffer+1,2);
1888                     *year  = DateCalc_Str2Int(buffer+3,2);
1889                     break;
1890                 case 6:
1891                     *day   = DateCalc_Str2Int(buffer,  2);
1892                     *month = DateCalc_Str2Int(buffer+2,2);
1893                     *year  = DateCalc_Str2Int(buffer+4,2);
1894                     break;
1895                 case 7:
1896                     *day   = DateCalc_Str2Int(buffer,  1);
1897                     *month = DateCalc_Str2Int(buffer+1,2);
1898                     *year  = DateCalc_Str2Int(buffer+3,4);
1899                     break;
1900                 case 8:
1901                     *day   = DateCalc_Str2Int(buffer,  2);
1902                     *month = DateCalc_Str2Int(buffer+2,2);
1903                     *year  = DateCalc_Str2Int(buffer+4,4);
1904                     break;
1905                 default:
1906                     return(false);
1907                     break;
1908                 }
1909             }
1910             else        /* at least one non-numerical char (i <= j) */
1911             {
1912                 *day  = DateCalc_Str2Int(buffer,i);
1913                 *year = DateCalc_Str2Int(buffer+(j+1),length-(j+1));
1914                 while (DateCalc_scanx(buffer,length,i,true)) i++;
1915                 while (DateCalc_scanx(buffer,length,j,true)) j--;
1916                 if (i <= j)         /* at least one char left for month */
1917                 {
1918                     buffer += i;
1919                     length = j-i+1;
1920                     i = 1;
1921                     while (DateCalc_scanx(buffer,length,i,false)) i++;
1922                     if (i >= length)    /* ok, no more delimiters */
1923                     {
1924                         i = 0;
1925                         while (DateCalc_scan9(buffer,length,i,false)) i++;
1926                         if (i >= length) /* only digits for month */
1927                         {
1928                             *month = DateCalc_Str2Int(buffer,length);
1929                         }
1930                         else             /* match with month names */
1931                         {
1932                             *month = DateCalc_Decode_Month(buffer,length,lang);
1933                         }
1934                     }
1935                     else return(false); /* delimiters inside month string */
1936                 }
1937                 else return(false); /* no chars left for month */
1938             }           /* at least one non-numerical char (i <= j) */
1939         }
1940         else return(false); /* less than 3 chars in buffer */
1941     }
1942     else return(false); /* length <= 0 */
1943     *year = DateCalc_Moving_Window(*year);
1944     return( DateCalc_check_date(*year,*month,*day) );
1945 }
1946 
DateCalc_decode_date_us(charptr buffer,Z_int * year,Z_int * month,Z_int * day,Z_int lang)1947 boolean DateCalc_decode_date_us(charptr buffer,
1948                                 Z_int *year, Z_int *month, Z_int *day, Z_int lang)
1949 {
1950     Z_int i,j,k;
1951     Z_int length;
1952 
1953     if ((lang < 1) or (lang > DateCalc_LANGUAGES)) lang = DateCalc_Language;
1954     *year = *month = *day = 0;
1955     length = strlen((char *)buffer);
1956     if (length > 0)
1957     {
1958         i = 0;
1959         while (DateCalc_scanx(buffer,length,i,true)) i++;
1960         j = length-1;
1961         while (DateCalc_scan9(buffer,length,j,true)) j--;
1962         if (i+1 < j)        /* at least 3 chars, else error! */
1963         {
1964             buffer += i;
1965             length = j-i+1;
1966             i = 1;
1967             while (DateCalc_scanx(buffer,length,i,false)) i++;
1968             j = length-2;
1969             while (DateCalc_scan9(buffer,length,j,false)) j--;
1970             if (i >= length)  /* only alphanumeric chars left */
1971             {
1972                 if (j < 0) /* case 0 : xxxx999999xxxx */
1973                 {          /*             j0     i    */
1974                     switch (length)
1975                     {
1976                     case 3:
1977                         *month = DateCalc_Str2Int(buffer,  1);
1978                         *day   = DateCalc_Str2Int(buffer+1,1);
1979                         *year  = DateCalc_Str2Int(buffer+2,1);
1980                         break;
1981                     case 4:
1982                         *month = DateCalc_Str2Int(buffer,  1);
1983                         *day   = DateCalc_Str2Int(buffer+1,1);
1984                         *year  = DateCalc_Str2Int(buffer+2,2);
1985                         break;
1986                     case 5:
1987                         *month = DateCalc_Str2Int(buffer,  1);
1988                         *day   = DateCalc_Str2Int(buffer+1,2);
1989                         *year  = DateCalc_Str2Int(buffer+3,2);
1990                         break;
1991                     case 6:
1992                         *month = DateCalc_Str2Int(buffer,  2);
1993                         *day   = DateCalc_Str2Int(buffer+2,2);
1994                         *year  = DateCalc_Str2Int(buffer+4,2);
1995                         break;
1996                     case 7:
1997                         *month = DateCalc_Str2Int(buffer,  1);
1998                         *day   = DateCalc_Str2Int(buffer+1,2);
1999                         *year  = DateCalc_Str2Int(buffer+3,4);
2000                         break;
2001                     case 8:
2002                         *month = DateCalc_Str2Int(buffer,  2);
2003                         *day   = DateCalc_Str2Int(buffer+2,2);
2004                         *year  = DateCalc_Str2Int(buffer+4,4);
2005                         break;
2006                     default:
2007                         return(false);
2008                         break;
2009                     }
2010                 }
2011                 else       /* case 1 : xxxxAAA999999xxxx */
2012                 {          /*              0 j      i    */
2013                     *month = DateCalc_Decode_Month(buffer,j+1,lang);
2014                     buffer += j+1;
2015                     length -= j+1;
2016                     switch (length)
2017                     {
2018                     case 2:
2019                         *day  = DateCalc_Str2Int(buffer,  1);
2020                         *year = DateCalc_Str2Int(buffer+1,1);
2021                         break;
2022                     case 3:
2023                         *day  = DateCalc_Str2Int(buffer,  1);
2024                         *year = DateCalc_Str2Int(buffer+1,2);
2025                         break;
2026                     case 4:
2027                         *day  = DateCalc_Str2Int(buffer,  2);
2028                         *year = DateCalc_Str2Int(buffer+2,2);
2029                         break;
2030                     case 5:
2031                         *day  = DateCalc_Str2Int(buffer,  1);
2032                         *year = DateCalc_Str2Int(buffer+1,4);
2033                         break;
2034                     case 6:
2035                         *day  = DateCalc_Str2Int(buffer,  2);
2036                         *year = DateCalc_Str2Int(buffer+2,4);
2037                         break;
2038                     default:
2039                         return(false);
2040                         break;
2041                     }
2042                 }
2043             }              /*              0  i  j    l         */
2044             else           /* case 2 : xxxxAAAxxxx9999xxxx _OR_ */
2045             {              /* case 3 : xxxxAAAxx99xx9999xx      */
2046                 k = 0;     /*              0  i    j    l       */
2047                 while (DateCalc_scan9(buffer,length,k,false)) k++;
2048                 if (k >= i) /* ok, only digits */
2049                 {
2050                     *month = DateCalc_Str2Int(buffer,i);
2051                 }
2052                 else       /* no, some non-digits */
2053                 {
2054                     *month = DateCalc_Decode_Month(buffer,i,lang);
2055                     if (*month == 0) return(false);
2056                 }
2057                 buffer += i;
2058                 length -= i;
2059                 j -= i;
2060                 k = j+1; /* remember start posn of day+year(2)/year(3) */
2061                 i = 1;
2062                 while (DateCalc_scanx(buffer,length,i,true)) i++;
2063                 j--;
2064                 while (DateCalc_scan9(buffer,length,j,true)) j--;
2065                 if (j < i) /* case 2 : xxxxAAAxxxx9999xxxx */
2066                 {          /*                j0   i   l    */
2067                     buffer += k;    /*            k        */
2068                     length -= k;
2069                     switch (length)
2070                     {
2071                     case 2:
2072                         *day  = DateCalc_Str2Int(buffer,  1);
2073                         *year = DateCalc_Str2Int(buffer+1,1);
2074                         break;
2075                     case 3:
2076                         *day  = DateCalc_Str2Int(buffer,  1);
2077                         *year = DateCalc_Str2Int(buffer+1,2);
2078                         break;
2079                     case 4:
2080                         *day  = DateCalc_Str2Int(buffer,  2);
2081                         *year = DateCalc_Str2Int(buffer+2,2);
2082                         break;
2083                     case 5:
2084                         *day  = DateCalc_Str2Int(buffer,  1);
2085                         *year = DateCalc_Str2Int(buffer+1,4);
2086                         break;
2087                     case 6:
2088                         *day  = DateCalc_Str2Int(buffer,  2);
2089                         *year = DateCalc_Str2Int(buffer+2,4);
2090                         break;
2091                     default:
2092                         return(false);
2093                         break;
2094                     }
2095                 }
2096                 else       /* case 3 : xxxxAAAxx99xx9999xx */
2097                 {          /*                 0 ij  k   l  */
2098                     *year = DateCalc_Str2Int(buffer+k,length-k);
2099                     k = i;
2100                     while (DateCalc_scan9(buffer,length,k,false)) k++;
2101                     if (k > j)          /* ok, only digits */
2102                     {
2103                         *day = DateCalc_Str2Int(buffer+i,j-i+1);
2104                     }
2105                     else return(false); /* non-digits inside day */
2106                 }
2107             }                 /* i < length */
2108         }
2109         else return(false); /* less than 3 chars in buffer */
2110     }
2111     else return(false); /* length <= 0 */
2112     *year = DateCalc_Moving_Window(*year);
2113     return( DateCalc_check_date(*year,*month,*day) );
2114 }
2115 
DateCalc_Fixed_Window(Z_int year)2116 Z_int DateCalc_Fixed_Window(Z_int year)
2117 {
2118     if (year < 0) return(0);
2119     if (year < 100)
2120     {
2121         if (year < DateCalc_YEAR_OF_EPOCH) year += 100;
2122         year += DateCalc_CENTURY_OF_EPOCH;
2123     }
2124     return(year);
2125 }
2126 
DateCalc_Moving_Window(Z_int year)2127 Z_int DateCalc_Moving_Window(Z_int year)
2128 {
2129     time_t seconds;
2130     struct tm *date;
2131     Z_int  current;
2132     Z_int  century;
2133 
2134     if (year < 0) return(0);
2135     if (year < 100)
2136     {
2137         if ((time(&seconds) >= 0) and ((date = gmtime(&seconds)) != NULL))
2138         {
2139             current = (*date).tm_year + 1900;
2140             century = (Z_int)(current / 100);
2141             year += century * 100;
2142             if      (year <  current - 50) year += 100;
2143             else if (year >= current + 50) year -= 100;
2144         }
2145         else year = DateCalc_Fixed_Window(year);
2146     }
2147     return(year);
2148 }
2149 
DateCalc_Compress(Z_int year,Z_int month,Z_int day)2150 Z_int DateCalc_Compress(Z_int year, Z_int month, Z_int day)
2151 {
2152     Z_int yy;
2153 
2154     if ((year >= DateCalc_EPOCH) and (year < (DateCalc_EPOCH + 100)))
2155     {
2156         yy = year;
2157         year -= DateCalc_EPOCH;
2158     }
2159     else
2160     {
2161         if ((year < 0) or (year > 99)) return(0);
2162         if (year < DateCalc_YEAR_OF_EPOCH)
2163         {
2164             yy = DateCalc_CENTURY_OF_EPOCH + 100 + year;
2165             year += 100 - DateCalc_YEAR_OF_EPOCH;
2166         }
2167         else
2168         {
2169             yy = DateCalc_CENTURY_OF_EPOCH + year;
2170             year -= DateCalc_YEAR_OF_EPOCH;
2171         }
2172     }
2173     if ((month < 1) or (month > 12)) return(0);
2174     if ((day < 1) or
2175         (day > DateCalc_Days_in_Month_[DateCalc_leap_year(yy)][month]))
2176         return(0);
2177     return( (year SHL 9) OR (month SHL 5) OR day );
2178 }
2179 
2180 boolean
DateCalc_uncompress(Z_int date,Z_int * century,Z_int * year,Z_int * month,Z_int * day)2181 DateCalc_uncompress(Z_int date,
2182                     Z_int *century, Z_int *year, Z_int *month, Z_int *day)
2183 {
2184     if (date > 0)
2185     {
2186         *year  =  date SHR 9;
2187         *month = (date AND 0x01FF) SHR 5;
2188         *day   =  date AND 0x001F;
2189 
2190         if (*year < 100)
2191         {
2192             if (*year < 100-DateCalc_YEAR_OF_EPOCH)
2193             {
2194                 *century = DateCalc_CENTURY_OF_EPOCH;
2195                 *year += DateCalc_YEAR_OF_EPOCH;
2196             }
2197             else
2198             {
2199                 *century = DateCalc_CENTURY_OF_EPOCH+100;
2200                 *year -= 100-DateCalc_YEAR_OF_EPOCH;
2201             }
2202             return( DateCalc_check_date(*century+*year,*month,*day) );
2203         }
2204     }
2205     return(false);
2206 }
2207 
DateCalc_check_compressed(Z_int date)2208 boolean DateCalc_check_compressed(Z_int date)
2209 {
2210     Z_int century;
2211     Z_int year;
2212     Z_int month;
2213     Z_int day;
2214 
2215     return( DateCalc_uncompress(date,&century,&year,&month,&day) );
2216 }
2217 
DateCalc_Compressed_to_Text(Z_int date,Z_int lang)2218 charptr DateCalc_Compressed_to_Text(Z_int date, Z_int lang)
2219 {
2220     Z_int   century;
2221     Z_int   year;
2222     Z_int   month;
2223     Z_int   day;
2224     charptr string;
2225 
2226     if ((lang < 1) or (lang > DateCalc_LANGUAGES)) lang = DateCalc_Language;
2227     string = (charptr) malloc(16);
2228     if (string == NULL) return(NULL);
2229     if (DateCalc_uncompress(date,&century,&year,&month,&day))
2230         sprintf((char *)string,"%02d-%.3s-%02d",day,
2231         DateCalc_Month_to_Text_[lang][month],year);
2232     else
2233         sprintf((char *)string,"??""-???""-??");
2234         /* prevent interpretation as trigraphs */
2235     return(string);
2236 }
2237 
DateCalc_Date_to_Text(Z_int year,Z_int month,Z_int day,Z_int lang)2238 charptr DateCalc_Date_to_Text(Z_int year, Z_int month, Z_int day, Z_int lang)
2239 {
2240     charptr string;
2241 
2242     if ((lang < 1) or (lang > DateCalc_LANGUAGES)) lang = DateCalc_Language;
2243     if (DateCalc_check_date(year,month,day) and
2244         ((string = (charptr) malloc(32)) != NULL))
2245     {
2246         if (DateCalc_Day_of_Week_Abbreviation_[lang][0][0] != '\0')
2247         {
2248             sprintf((char *)string,"%.3s %d-%.3s-%d",
2249                 DateCalc_Day_of_Week_Abbreviation_[lang][DateCalc_Day_of_Week(year,month,day)],
2250                 day,DateCalc_Month_to_Text_[lang][month],year);
2251             return(string);
2252         }
2253         else
2254         {
2255             sprintf((char *)string,"%.3s %d-%.3s-%d",
2256                 DateCalc_Day_of_Week_to_Text_[lang][DateCalc_Day_of_Week(year,month,day)],
2257                 day,DateCalc_Month_to_Text_[lang][month],year);
2258             return(string);
2259         }
2260     }
2261     return(NULL);
2262 }
2263 
DateCalc_English_Ordinal(charptr result,Z_int number)2264 charptr DateCalc_English_Ordinal(charptr result, Z_int number)
2265 {
2266     N_int length;
2267     N_int digit;
2268 
2269     sprintf((char *)result, "%d", number);
2270     if ((length = strlen((char *)result)))
2271     {
2272         if ( not
2273              (
2274                ( ((length > 1) and (result[length-2] != '1')) or (length == 1) )
2275                and
2276                ( (digit = (N_int)(result[length-1] XOR '0')) <= 3 )
2277              )
2278            )
2279         {
2280             digit = 0;
2281         }
2282         sprintf( (char *)(result+length), "%s",
2283             DateCalc_English_Ordinals_[digit] );
2284     }
2285     return(result);
2286 }
2287 
DateCalc_Date_to_Text_Long(Z_int year,Z_int month,Z_int day,Z_int lang)2288 charptr DateCalc_Date_to_Text_Long(Z_int year, Z_int month, Z_int day, Z_int lang)
2289 {
2290     charptr string;
2291     blockdef(buffer,64);
2292 
2293     if ((lang < 1) or (lang > DateCalc_LANGUAGES)) lang = DateCalc_Language;
2294     if (DateCalc_check_date(year,month,day) and
2295         ((string = (charptr) malloc(64)) != NULL))
2296     {
2297         switch (lang)
2298         {
2299             case 1:
2300                 sprintf(
2301                     (char *)string,
2302                     (char *)DateCalc_Date_Long_Format_[lang],
2303                     DateCalc_Day_of_Week_to_Text_[lang]
2304                         [DateCalc_Day_of_Week(year,month,day)],
2305                     DateCalc_Month_to_Text_[lang][month],
2306                     DateCalc_English_Ordinal(buffer,day),
2307                     year );
2308                 break;
2309             case 12:
2310                 sprintf(
2311                     (char *)string,
2312                     (char *)DateCalc_Date_Long_Format_[lang],
2313                     year,
2314                     DateCalc_Month_to_Text_[lang][month],
2315                     day,
2316                     DateCalc_Day_of_Week_to_Text_[lang]
2317                         [DateCalc_Day_of_Week(year,month,day)] );
2318                 break;
2319             default:
2320                 sprintf(
2321                     (char *)string,
2322                     (char *)DateCalc_Date_Long_Format_[lang],
2323                     DateCalc_Day_of_Week_to_Text_[lang]
2324                         [DateCalc_Day_of_Week(year,month,day)],
2325                     day,
2326                     DateCalc_Month_to_Text_[lang][month],
2327                     year );
2328                 break;
2329         }
2330         return(string);
2331     }
2332     return(NULL);
2333 }
2334 
DateCalc_Calendar(Z_int year,Z_int month,boolean orthodox,Z_int lang)2335 charptr DateCalc_Calendar(Z_int year, Z_int month, boolean orthodox, Z_int lang)
2336 {
2337     blockdef(buffer,64);
2338     charptr string;
2339     charptr cursor;
2340     Z_int first;
2341     Z_int last;
2342     Z_int day;
2343 
2344     if ((lang < 1) or (lang > DateCalc_LANGUAGES)) lang = DateCalc_Language;
2345     string = (charptr) malloc(256);
2346     if (string == NULL) return(NULL);
2347     cursor = string;
2348     DateCalc_Newline(&cursor,1);
2349     sprintf((char *)buffer,"%s %d",
2350         DateCalc_Month_to_Text_[lang][month],year);
2351     *buffer = DateCalc_ISO_UC(*buffer);
2352     DateCalc_Center(&cursor,buffer,27);
2353     if (DateCalc_Day_of_Week_Abbreviation_[lang][0][0] != '\0')
2354     {
2355         if (orthodox)
2356             sprintf((char *)cursor,"%3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s\n",
2357                 DateCalc_Day_of_Week_Abbreviation_[lang][7],
2358                 DateCalc_Day_of_Week_Abbreviation_[lang][1],
2359                 DateCalc_Day_of_Week_Abbreviation_[lang][2],
2360                 DateCalc_Day_of_Week_Abbreviation_[lang][3],
2361                 DateCalc_Day_of_Week_Abbreviation_[lang][4],
2362                 DateCalc_Day_of_Week_Abbreviation_[lang][5],
2363                 DateCalc_Day_of_Week_Abbreviation_[lang][6]);
2364         else /* conform to ISO standard */
2365             sprintf((char *)cursor,"%3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s\n",
2366                 DateCalc_Day_of_Week_Abbreviation_[lang][1],
2367                 DateCalc_Day_of_Week_Abbreviation_[lang][2],
2368                 DateCalc_Day_of_Week_Abbreviation_[lang][3],
2369                 DateCalc_Day_of_Week_Abbreviation_[lang][4],
2370                 DateCalc_Day_of_Week_Abbreviation_[lang][5],
2371                 DateCalc_Day_of_Week_Abbreviation_[lang][6],
2372                 DateCalc_Day_of_Week_Abbreviation_[lang][7]);
2373     }
2374     else
2375     {
2376         if (orthodox)
2377             sprintf((char *)cursor,"%3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s\n",
2378                 DateCalc_Day_of_Week_to_Text_[lang][7],
2379                 DateCalc_Day_of_Week_to_Text_[lang][1],
2380                 DateCalc_Day_of_Week_to_Text_[lang][2],
2381                 DateCalc_Day_of_Week_to_Text_[lang][3],
2382                 DateCalc_Day_of_Week_to_Text_[lang][4],
2383                 DateCalc_Day_of_Week_to_Text_[lang][5],
2384                 DateCalc_Day_of_Week_to_Text_[lang][6]);
2385         else /* conform to ISO standard */
2386             sprintf((char *)cursor,"%3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s\n",
2387                 DateCalc_Day_of_Week_to_Text_[lang][1],
2388                 DateCalc_Day_of_Week_to_Text_[lang][2],
2389                 DateCalc_Day_of_Week_to_Text_[lang][3],
2390                 DateCalc_Day_of_Week_to_Text_[lang][4],
2391                 DateCalc_Day_of_Week_to_Text_[lang][5],
2392                 DateCalc_Day_of_Week_to_Text_[lang][6],
2393                 DateCalc_Day_of_Week_to_Text_[lang][7]);
2394     }
2395     cursor += 28;
2396     first = DateCalc_Day_of_Week(year,month,1);
2397     last = DateCalc_Days_in_Month_[DateCalc_leap_year(year)][month];
2398     if (orthodox) { if (first == 7) first = 0; }
2399     else          { first--; }
2400     if (first) DateCalc_Blank(&cursor,(first<<2)-1);
2401     for ( day = 1; day <= last; day++, first++ )
2402     {
2403         if (first > 0)
2404         {
2405             if (first > 6)
2406             {
2407                 first = 0;
2408                 DateCalc_Newline(&cursor,1);
2409             }
2410             else DateCalc_Blank(&cursor,1);
2411         }
2412         sprintf((char *)cursor," %2d",day);
2413         cursor += 3;
2414     }
2415     DateCalc_Newline(&cursor,2);
2416     return(string);
2417 }
2418 
DateCalc_Dispose(charptr string)2419 void DateCalc_Dispose(charptr string)
2420 {
2421     free((voidptr) string);
2422 }
2423 
DateCalc_Version(void)2424 charptr DateCalc_Version(void)
2425 {
2426     return( (charptr) "6.4" );
2427 }
2428 
2429 /*****************************************************************************/
2430 /*  VERSION:  6.4                                                            */
2431 /*****************************************************************************/
2432 /*  VERSION HISTORY:                                                         */
2433 /*****************************************************************************/
2434 /*                                                                           */
2435 /*    Version 6.4  07.03.15  No changes.                                     */
2436 /*    Version 6.3  17.05.12  No changes.                                     */
2437 /*    Version 6.2  16.10.09  No changes.                                     */
2438 /*    Version 6.1  15.10.09  Fixed Polish language entries.                  */
2439 /*    Version 6.0  07.10.09  +: norm_delta_ymdhms, add_norm_delta_ymd[hms].  */
2440 /*    Version 5.8  12.09.09  Added "norm_delta_ymd()".                       */
2441 /*    Version 5.7  23.08.09  Fixed Dutch "oktober", Portuguese DOW abbrevs.  */
2442 /*    Version 5.6  28.07.09  Made the module MacOS X compatible.             */
2443 /*    Version 5.5  skipped due to an unauthorized upload by someone else.    */
2444 /*    Version 5.4  03.10.04  Added compiler directives for C++.              */
2445 /*    Version 5.3  29.09.02  No changes.                                     */
2446 /*    Version 5.2  18.09.02  No changes.                                     */
2447 /*    Version 5.1  08.09.02  Added conditional changes for MacOS/MacPerl.    */
2448 /*    Version 5.0  10.10.01  New YMD/HMS functions, replaced <ctype.h>, ...  */
2449 /*    Version 4.3  08.01.00  decode_date_??: (yy < 70 ? 20yy : 19yy)         */
2450 /*    Version 4.2  07.09.98  No changes.                                     */
2451 /*    Version 4.1  08.06.98  Fixed bug in "add_delta_ymd()".                 */
2452 /*    Version 4.0  12.05.98  Major rework. Added multi-language support.     */
2453 /*    Version 3.2  15.06.97  Added "week_of_year()".                         */
2454 /*    Version 3.1  12.06.97  No significant changes.                         */
2455 /*    Version 3.0  16.02.97  Changed conventions for unsuccessful returns.   */
2456 /*    Version 2.3  22.11.96  Fixed unbalanced "malloc" and "free".           */
2457 /*    Version 2.2  26.05.96  No significant changes.                         */
2458 /*    Version 2.1  26.05.96  Fixed HH MM SS parameter checks.                */
2459 /*    Version 2.0  25.05.96  Added time calculations. Major rework.          */
2460 /*    Version 1.6  20.04.96  Not published.                                  */
2461 /*    Version 1.5  14.03.96  No significant changes.                         */
2462 /*    Version 1.4  11.02.96  No significant changes.                         */
2463 /*    Version 1.3  10.12.95  Added "days_in_month()".                        */
2464 /*    Version 1.2b 27.11.95  No significant changes.                         */
2465 /*    Version 1.2a 21.11.95  Fix for type name clashes.                      */
2466 /*    Version 1.1  18.11.95  Fix for type name clashes.                      */
2467 /*    Version 1.01 16.11.95  Improved compliance w/ programming standards.   */
2468 /*    Version 1.0  14.11.95  First version under UNIX (with Perl module).    */
2469 /*    Version 0.9  01.11.93  First version of C library under MS-DOS.        */
2470 /*                                                                           */
2471 /*****************************************************************************/
2472 /*  AUTHOR:                                                                  */
2473 /*****************************************************************************/
2474 /*                                                                           */
2475 /*    Steffen Beyer                                                          */
2476 /*    mailto:STBEY@cpan.org                                                  */
2477 /*    http://www.engelschall.com/u/sb/download/                              */
2478 /*                                                                           */
2479 /*****************************************************************************/
2480 /*  COPYRIGHT:                                                               */
2481 /*****************************************************************************/
2482 /*                                                                           */
2483 /*    Copyright (c) 1993 - 2015 by Steffen Beyer.                            */
2484 /*    All rights reserved.                                                   */
2485 /*                                                                           */
2486 /*****************************************************************************/
2487 /*  LICENSE:                                                                 */
2488 /*****************************************************************************/
2489 /*                                                                           */
2490 /*    This library is free software; you can redistribute it and/or          */
2491 /*    modify it under the terms of the GNU Library General Public            */
2492 /*    License as published by the Free Software Foundation; either           */
2493 /*    version 2 of the License, or (at your option) any later version.       */
2494 /*                                                                           */
2495 /*    This library is distributed in the hope that it will be useful,        */
2496 /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
2497 /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU       */
2498 /*    Library General Public License for more details.                       */
2499 /*                                                                           */
2500 /*    You should have received a copy of the GNU Library General Public      */
2501 /*    License along with this library; if not, write to the                  */
2502 /*    Free Software Foundation, Inc.,                                        */
2503 /*    59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                  */
2504 /*    or download a copy from ftp://ftp.gnu.org/pub/gnu/COPYING.LIB-2.0      */
2505 /*                                                                           */
2506 /*****************************************************************************/
2507 #endif
2508