1 /******************************************************************************
2 *
3 *  NSSDC/CDF                       EPOCH utility routines for C applications.
4 *
5 *  Version 2.5b, 29-Oct-97, Hughes STX.
6 *
7 *  Modification history:
8 *
9 *   V1.0  24-Jan-91, D Grogan   Original version (for CDF V2.0).
10 *   V1.1  25-Mar-91, J Love     Added support for Silicon Graphics (MIPSEB
11 *                               encoding, IRIX - UNIX).
12 *   V1.2  26-Mar-91, J Love     Added "types.h" include for SunOS 4.0.3
13 *                               systems (UNIX).  Added "ctypes.h" include and
14 *                               removed definitions of toupper & tolower.  Use
15 *                               toupper the safe way.  Added definition for
16 *                               toupper if SunOS 4.0.3.
17 *   V1.3  19-Jun-91, J Love     Changed epochParse to return FALSE if illegal
18 *                               date/time string (and added more error
19 *                               checking) and to set 'tSince0'.
20 *   V1.4  29-Jul-91, J Love     TRUE/FALSE.  Don't display error messages (the
21 *                               caller will do that).
22 *   V1.5  23-Sep-91, J Love     Modified for IBM-PC port.
23 *   V2.0   1-Apr-92, J Love     Added to CDF library.  Added additional ways
24 *                    A Warnock  to display an EPOCH date/time.
25 *   V2.1  30-Jun-92, J Love     CDF V2.3 (shareable/NeXT/zVar).
26 *   V2.2  24-Jan-94, J Love     CDF V2.4.  Handle negative EPOCHs.
27 *   V2.3  13-Dec-94, J Love     CDF V2.5.
28 *   V2.3a 18-Jan-95, J Love	Made `computeEPOCH' more flexible.
29 *   V2.3b 24-Jan-95, J Love	Changed `parseEPOCH' for Salford C.  Consider
30 *				milliseconds in `encodeEPOCH1'.
31 *   V2.3c 24-Feb-95, J Love	Solaris 2.3 IDL i/f.
32 *   V2.4   9-May-95, J Love	Added parseEPOCH1, parseEPOCH2, & parseEPOCH3.
33 *   V2.4a 13-Jun-95, J Love	EPOCH custom format.
34 *   V2.5   3-Oct-96, J Love	CDF V2.6 (and the OSF/1 bug in `sprintf').
35 *   V2.5a  8-Mar-97, J Love	Windows NT for MS Visual C/C++ on an IBM PC.
36 *   V2.5b 29-Oct-97, J Love	More Windows NT.
37 *   V2.6  29-Jan-04, M Liu      Added a new set of CDF_EPOCH16 functions for
38 *                               handling fraction of a second up to picosecond.
39 *
40 ******************************************************************************/
41 
42 #include "cdflib.h"
43 
44 /******************************************************************************
45 * Local macro definitions.
46 ******************************************************************************/
47 
48 #define MAX_PART_LEN		10
49 #define MAX_MOD_LEN		10
50 #define MAX_ePART_LEN		25
51 
52 /******************************************************************************
53 * Local function prototypes.
54 ******************************************************************************/
55 
56 static long JulianDay PROTOARGs((long, long, long));
57 static char *MonthToken PROTOARGs((long));
58 static char *FullDayToken PROTOARGs((char *));
59 static Logical AppendFractionPart PROTOARGs((
60   char *encoded, double fraction, int defaultWidth, char *modifier
61 ));
62 static Logical AppendIntegerPart PROTOARGs((
63   char *encoded, long integer, int defaultWidth, Logical defaultLeading0,
64   char *modifier
65 ));
66 static Logical AppendPart PROTOARGs((
67   char *encoded, char *ePart, int width, Logical leading0
68 ));
69 void encodeEPOCH16x2 PROTOARGs((
70   double epoch, char *encoded
71 ));
72 void encodeEPOCH16x3 PROTOARGs((
73   double epoch[], char *encoded
74 ));
75 
76 /******************************************************************************
77 * parseEPOCH.
78 * This function parses an input date/time string and returns an EPOCH
79 * value.  The format must be exactly as shown below.  Month abbreviations may
80 * be in any case and are always the first three letters of the month.
81 *
82 * Format:       dd-mmm-yyyy hh:mm:ss.mmm
83 * Examples:      1-Apr-1990 03:05:02.000
84 *               10-Oct-1993 23:45:49.999
85 *
86 * The expected format is the same as that produced by encodeEPOCH.
87 ******************************************************************************/
88 
parseEPOCH(inString)89 VISIBLE_PREFIX double parseEPOCH (inString)
90 char *inString;
91 {
92   char moString[4];
93   long year, month, day, hour, minute, second, msec;
94   int monthX;
95   if (sscanf(inString,"%ld-%c%c%c-%ld %ld:%ld:%ld.%ld",
96              &day, &(moString[0]), &(moString[1]), &(moString[2]), &year,
97              &hour, &minute, &second, &msec) != 9) return ILLEGAL_EPOCH_VALUE;
98   moString[0] = (char) MakeUpper((int)moString[0]);   /* J */
99   moString[1] = (char) MakeLower((int)moString[1]);   /* a */
100   moString[2] = (char) MakeLower((int)moString[2]);   /* n */
101   moString[3] = NUL;
102   for (monthX = 1, month = 0; monthX <= 12; monthX++) {
103     if (!strcmp(moString,MonthToken(monthX))) {
104       month = monthX;
105       break;
106     }
107   }
108   if (month == 0) return ILLEGAL_EPOCH_VALUE;
109   return computeEPOCH (year, month, day, hour, minute, second, msec);
110 }
111 
112 /******************************************************************************
113 * parseEPOCH16.
114 * This function is an extension of parseEPOCH. It is used to handle the time
115 * that may contain as small as picoseconds (one trillionth of a second).
116 * A section of micro-, nano- and pico-second is added.
117 *
118 * Format:	dd-mmm-yyyy hh:mm:ss.mmm.uuu.nnn.ppp
119 * Examples:	 1-Apr-1990 03:05:02.000.000.000.000
120 *		10-Oct-1993 23:45:49.999.999.999.999
121 *
122 * The expected format is the same as that produced by encodeEPOCH16.
123 ******************************************************************************/
124 
parseEPOCH16(inString,epoch)125 VISIBLE_PREFIX double parseEPOCH16 (inString, epoch)
126 char *inString;
127 double epoch[2];
128 {
129   char moString[4];
130   long year, month, day, hour, minute, second, msec, usec, nsec, psec;
131   double mmm;
132   int monthX;
133   if (sscanf(inString,"%ld-%c%c%c-%ld %ld:%ld:%ld.%ld.%ld.%ld.%ld",
134 	     &day, &(moString[0]), &(moString[1]), &(moString[2]), &year,
135 	     &hour, &minute, &second, &msec, &usec, &nsec, &psec) != 12)
136         return ILLEGAL_EPOCH_VALUE;
137   moString[0] = (char) MakeUpper((int)moString[0]);   /* J */
138   moString[1] = (char) MakeLower((int)moString[1]);   /* a */
139   moString[2] = (char) MakeLower((int)moString[2]);   /* n */
140   moString[3] = NUL;
141   for (monthX = 1, month = 0; monthX <= 12; monthX++) {
142     if (!strcmp(moString,MonthToken(monthX))) {
143       month = monthX;
144       break;
145     }
146   }
147   if (month == 0) return ILLEGAL_EPOCH_VALUE;
148   mmm = computeEPOCH (year, month, day, hour, minute, second, 0L);
149   if (mmm == ILLEGAL_EPOCH_VALUE) return ILLEGAL_EPOCH_VALUE;
150   if (msec < 0 || msec > 999) return ILLEGAL_EPOCH_VALUE;
151   if (usec < 0 || usec > 999) return ILLEGAL_EPOCH_VALUE;
152   if (nsec < 0 || nsec > 999) return ILLEGAL_EPOCH_VALUE;
153   if (psec < 0 || psec > 999) return ILLEGAL_EPOCH_VALUE;
154   if (year == 9999 && month == 12 && day == 31 && hour == 23 && minute == 59 &&
155       second == 59 && msec == 999 && usec == 999 && nsec == 999 && psec == 999) {
156     epoch[0] = -1.0E31;
157     epoch[1] = -1.0E31;
158     return 0.0;
159   }
160   epoch[0] = mmm / (double) 1000.0;
161   epoch[1] = msec * pow(10.0, 9.0) + usec * pow(10.0, 6.0) + nsec * pow(10.0, 3.0) +
162 	     psec;
163   return (double) 0.0;
164 }
165 
166 /******************************************************************************
167 * parseEPOCH1.
168 * This function parses an input date/time string and returns an EPOCH
169 * value.  The format must be exactly as shown below.  Note that if there are
170 * less than 8 digits after the decimal point, zeros (0's) are assumed for the
171 * missing digits.
172 *
173 * Format:	yyyymmdd.ttttttt
174 * Examples:	19950508.0000000
175 *		19671231.58      (== 19671213.5800000)
176 *
177 * The expected format is the same as that produced by encodeEPOCH1.
178 ******************************************************************************/
179 
parseEPOCH1(inString)180 VISIBLE_PREFIX double parseEPOCH1 (inString)
181 char *inString;
182 {
183   char temp[EPOCH1_STRING_LEN+1]; double fraction; int i;
184   long year, month, day, hour, minute, second, msec, fractionL;
185   strcpyX (temp, inString, EPOCH1_STRING_LEN);
186   for (i = strlen(temp); i < EPOCH1_STRING_LEN; i++) temp[i] = '0';
187   temp[i] = NUL;
188   if (sscanf(temp,"%4ld%2ld%2ld.%ld",
189 	     &year, &month, &day, &fractionL) != 4) return ILLEGAL_EPOCH_VALUE;
190   fraction = ((double) fractionL) / 10000000.0;
191   hour = (long) (fraction * 24.0);
192   fraction -= (double) (hour / 24.0);
193   minute = (long) (fraction * 1440.0);
194   fraction -= (double) (minute / 1440.0);
195   second = (long) (fraction * 86400.0);
196   fraction -= (double) (second / 86400.0);
197   msec = (long) (fraction * 86400000.0);
198   return computeEPOCH (year, month, day, hour, minute, second, msec);
199 }
200 
201 /******************************************************************************
202 * parseEPOCH16_1.
203 * This function is an extension of parseEPOCH1. It is used to handle the time
204 * that may contain as small as picoseconds.
205 * The ttttttt... portion (at least 7-digit or more) represents a fraction of a
206 * day,
207 *
208 * Format:       yyyymmdd.ttttttttttttttt
209 * Examples:     19950508.000000000000000
210 *               19671231.58      (== 19671213.580000000000000)
211 *
212 * The expected format is the same as that produced by encodeEPOCH16_1.
213 ******************************************************************************/
214 
parseEPOCH16_1(inString,epoch)215 VISIBLE_PREFIX double parseEPOCH16_1 (inString, epoch)
216 char *inString;
217 double epoch[2];
218 {
219   char temp[EPOCH16_1_STRING_LEN+1]; double fraction; int i;
220   long year, month, day, hour, minute, second, fractionL1, fractionL2;
221   double mmm;
222 
223   if (!strcmp (inString, "99991231.999999999999999")) {
224     epoch[0] = -1.0E31;
225     epoch[1] = -1.0E31;
226     return 0.0;
227   }
228 
229   strcpyX (temp, inString, EPOCH16_1_STRING_LEN);
230   for (i = strlen(temp); i < EPOCH16_1_STRING_LEN; i++) temp[i] = '0';
231   temp[i] = NUL;
232   if (sscanf(temp,"%4ld%2ld%2ld.%7ld%8ld",
233              &year, &month, &day, &fractionL1, &fractionL2) != 5)
234      return ILLEGAL_EPOCH_VALUE;
235   fraction = ((double) fractionL1 * pow(10.0, 8.0) + (double) fractionL2) *
236 	     pow(10.0, -15.0);
237   hour = (long) (fraction * 24.0);
238   fraction -= (double) (hour / 24.0);
239   minute = (long) (fraction * 1440.0);
240   fraction -= (double) (minute / 1440.0);
241   second = (long) (fraction * 86400.0);
242   fraction -= (double) (second / 86400.0);
243   mmm =  computeEPOCH (year, month, day, hour, minute, second, 0L);
244   if (mmm == ILLEGAL_EPOCH_VALUE) return ILLEGAL_EPOCH_VALUE;
245   epoch[0] = mmm / (double) 1000.0;
246   epoch[1] = fraction * 86400.0 * pow(10.0, 12.0);
247   return (double) 0.0;
248 }
249 
250 /******************************************************************************
251 * parseEPOCH2.
252 * This function parses an input date/time string and returns an EPOCH
253 * value.  The format must be exactly as shown below.
254 *
255 * Format:	yyyymmddhhmmss
256 * Examples:	19950508000000
257 *		19671231235959
258 *
259 * The expected format is the same as that produced by encodeEPOCH2.
260 ******************************************************************************/
261 
parseEPOCH2(inString)262 VISIBLE_PREFIX double parseEPOCH2 (inString)
263 char *inString;
264 {
265   long year, month, day, hour, minute, second;
266   if (sscanf(inString,"%4ld%2ld%2ld%2ld%2ld%2ld",
267 	     &year,&month,&day,&hour,&minute,&second) != 6) {
268     return ILLEGAL_EPOCH_VALUE;
269   }
270   return computeEPOCH (year, month, day, hour, minute, second, 0L);
271 }
272 
273 /******************************************************************************
274 * parseEPOCH16_2.
275 * This function is an extension of parseEPOCH2. It is used to handle the time
276 * that may contain as small as picoseconds.
277 *
278 * Format:       yyyymmddhhmmss
279 * Examples:     19950508000000
280 *               19671231235959
281 *
282 * The expected format is the same as that produced by encodeEPOCH16_2.
283 ******************************************************************************/
284 
parseEPOCH16_2(inString,epoch)285 VISIBLE_PREFIX double parseEPOCH16_2 (inString, epoch)
286 char *inString;
287 double epoch[2];
288 {
289   long year, month, day, hour, minute, second;
290   double mmm;
291   if (sscanf(inString,"%4ld%2ld%2ld%2ld%2ld%2ld",
292              &year,&month,&day,&hour,&minute,&second) != 6) {
293     return ILLEGAL_EPOCH_VALUE;
294   }
295   mmm = computeEPOCH (year, month, day, hour, minute, second, 0L);
296   if (mmm == ILLEGAL_EPOCH_VALUE) return ILLEGAL_EPOCH_VALUE;
297   epoch[0] = mmm / (double) 1000.0;
298   epoch[1] = 0.0;
299   return (double) 0.0;
300 }
301 
302 /******************************************************************************
303 * parseEPOCH3.
304 * This function parses an input date/time string and returns an EPOCH
305 * value.  The format must be exactly as shown below.
306 *
307 * Format:	yyyy-mm-ddThh:mm:ss.cccZ
308 * Examples:	1990-04-01T03:05:02.000Z
309 *		1993-10-10T23:45:49.999Z
310 *
311 * The expected format is the same as that produced by encodeEPOCH3.
312 ******************************************************************************/
313 
parseEPOCH3(inString)314 VISIBLE_PREFIX double parseEPOCH3 (inString)
315 char *inString;
316 {
317   long year, month, day, hour, minute, second, msec;
318   if (sscanf(inString,"%ld-%ld-%ldT%ld:%ld:%ld.%ldZ",
319 	     &year,&month,&day,&hour,&minute,&second,&msec) != 7) {
320     return ILLEGAL_EPOCH_VALUE;
321   }
322   return computeEPOCH (year, month, day, hour, minute, second, msec);
323 }
324 
325 /******************************************************************************
326 * parseEPOCH16_3.
327 * This function is an extension of parseEPOCH3. It is used to handle the time
328 * that may contain as small as picoseconds.
329 *
330 * Format:       yyyy-mm-ddThh:mm:ss.ccc.mmm.nnn.pppZ
331 * Examples:     1990-04-01T03:05:02.000.000.000.000Z
332 *               1993-10-10T23:45:49.999.999.999.999Z
333 *
334 * The expected format is the same as that produced by encodeEPOCH16_3.
335 ******************************************************************************/
336 
parseEPOCH16_3(inString,epoch)337 VISIBLE_PREFIX double parseEPOCH16_3 (inString, epoch)
338 char *inString;
339 double epoch[2];
340 {
341   long year, month, day, hour, minute, second, msec, usec, nsec, psec;
342   int len;
343   double mmm;
344   len = strlen(inString);
345   if (len < EPOCH16_3_STRING_LEN) return ILLEGAL_EPOCH_VALUE;
346   if (sscanf(inString,"%ld-%ld-%ldT%ld:%ld:%ld.%ld.%ld.%ld.%ldZ",
347              &year,&month,&day,&hour,&minute,&second,&msec,&usec,&nsec,&psec)
348       != 10) {
349     return ILLEGAL_EPOCH_VALUE;
350   }
351   if (year == 9999 && month == 12 && day == 31 && hour == 23 && minute == 59 &&
352       second == 59 && msec == 999 && usec == 999 && nsec == 999 && psec == 999) {
353     epoch[0] = -1.0E31;
354     epoch[1] = -1.0E31;
355     return (double) 0.0;
356   }
357 
358   mmm = computeEPOCH (year, month, day, hour, minute, second, 0L);
359   if (mmm == ILLEGAL_EPOCH_VALUE) return ILLEGAL_EPOCH_VALUE;
360   epoch[0] = mmm / (double) 1000.0;
361   epoch[1] = (double) psec + (double) nsec * pow(10.0, 3.0) +
362 	     (double) usec * pow(10.0, 6.0) + (double) msec * pow(10.0, 9.0);
363   return (double) 0.0;
364 }
365 
366 /******************************************************************************
367 * encodeEPOCH.
368 * Converts an EPOCH value into a readable date/time string.
369 *
370 * Format:	dd-mmm-yyyy hh:mm:ss.ccc
371 * Examples:	01-Apr-1990 03:05:02.000
372 *		10-Oct-1993 23:45:49.999
373 *
374 * This format is the same as that expected by parseEPOCH.
375 ******************************************************************************/
376 
encodeEPOCH(epoch,epString)377 VISIBLE_PREFIX void encodeEPOCH (epoch, epString)
378 double epoch;
379 char epString[EPOCH_STRING_LEN+1];
380 {
381   if (epoch == -1.0E31) {
382     strcpyX(epString, "31-Dec-9999 23:59:59.999", 0);
383     return;
384   }
385 
386   encodeEPOCHx (epoch, "<dom.02>-<month>-<year> <hour>:<min>:<sec>.<fos>",
387 		epString);
388   return;
389 }
390 
391 /******************************************************************************
392 * encodeEPOCH16.
393 * This function is an extension of parseEPOCH. It is used to handle the time
394 * that may contain as small as picoseconds (10**-12 second).
395 *
396 *
397 * Format:       dd-mmm-yyyy hh:mm:ss.ccc.uuu.nnn.ppp
398 * Examples:     01-Apr-1990 03:05:02.000.000.000.000
399 *               10-Oct-1993 23:45:49.999.999.999.999
400 *               012345678901234567890123456789012345
401 * This format is the same as that expected by parseEPOCH16.
402 ******************************************************************************/
403 
encodeEPOCH16(epoch,epString)404 VISIBLE_PREFIX void encodeEPOCH16 (epoch, epString)
405 double epoch[2];
406 char epString[EPOCH16_STRING_LEN+1];
407 {
408   char tmp[EPOCH1_STRING_LEN+1];
409 
410   if (epoch[0] == -1.0E31 && epoch[1] == -1.0E31) {
411     strcpyX(epString, "31-Dec-9999 23:59:59.999.999.999.999", 0);
412     return;
413   }
414 
415   encodeEPOCHx (epoch[0]*1000.0,
416 		"<dom.02>-<month>-<year> <hour>:<min>:<sec>.<fos>",
417                 epString);
418   encodeEPOCH16x2 (epoch[1], tmp);
419   strcpyX(epString+21, tmp, 15);
420   epString[EPOCH16_STRING_LEN] = NUL;
421   return;
422 }
423 
424 /******************************************************************************
425 * encodeEPOCH1.
426 * Converts an EPOCH value into a readable date/time string.
427 *
428 * Format:	yyyymmdd.ttttttt
429 * Examples:	19900401.3658893
430 *		19611231.0000000
431 *
432 * This format is the same as that expected by parseEPOCH1.
433 ******************************************************************************/
434 
encodeEPOCH1(epoch,epString)435 VISIBLE_PREFIX void encodeEPOCH1 (epoch, epString)
436 double epoch;
437 char epString[EPOCH1_STRING_LEN+1];
438 {
439   if (epoch == -1.0E31) {
440     strcpyX(epString, "99991231.9999999", 0);
441     return;
442   }
443 
444   encodeEPOCHx (epoch, "<year><mm.02><dom.02>.<fod.7>",
445 		epString);
446   return;
447 }
448 
449 /******************************************************************************
450 * encodeEPOCH16_1.
451 * This function is an extension of encodeEPOCH1. It is used to handle the time
452 * that may contain as small as picoseconds.
453 *
454 * Converts an EPOCH value into a readable date/time string.
455 *
456 * Format:       yyyymmdd.ttttttttttttttt
457 * Examples:     19900401.365889324567890
458 *               19611231.000000000000000
459 *
460 * This format is the same as that expected by parseEPOCH16_1.
461 ******************************************************************************/
462 
encodeEPOCH16_1(epoch,epString)463 VISIBLE_PREFIX void encodeEPOCH16_1 (epoch, epString)
464 double epoch[2];
465 char epString[EPOCH16_1_STRING_LEN+1];
466 {
467   char tmp[EPOCH16_1_STRING_LEN+1];
468 
469   if (epoch[0] == -1.0E31 && epoch[1] == -1.0E31) {
470     strcpyX(epString, "99991231.999999999999999", 0);
471     return;
472   }
473 
474   encodeEPOCHx (epoch[0]*1000.0, "<year><mm.02><dom.02>.<fod.7>",
475                 epString);
476   encodeEPOCH16x3 (epoch, tmp);
477   strcpyX (epString+9, tmp, 15);
478   epString[EPOCH16_1_STRING_LEN] = NUL;
479   return ;
480 }
481 
482 /******************************************************************************
483 * encodeEPOCH2.
484 * Converts an EPOCH value into a readable date/time string.
485 *
486 * Format:	yyyymmddhhmmss
487 * Examples:	19900401235959
488 *		19611231000000
489 *
490 * This format is the same as that expected by parseEPOCH2.
491 ******************************************************************************/
492 
encodeEPOCH2(epoch,epString)493 VISIBLE_PREFIX void encodeEPOCH2 (epoch, epString)
494 double epoch;
495 char epString[EPOCH2_STRING_LEN+1];
496 {
497   if (epoch == -1.0E31) {
498     strcpyX(epString, "99991231235959", 0);
499     return;
500   }
501 
502   encodeEPOCHx (epoch, "<year><mm.02><dom.02><hour><min><sec>",
503 		epString);
504   return;
505 }
506 
507 /******************************************************************************
508 * encodeEPOCH16_2.
509 * This function is an extension of encodeEPOCH2. It is used to handle the time
510 * that may contain as small as picoseconds.
511 *
512 * Format:       yyyymmddhhmmss
513 * Examples:     19900401235959
514 *               19611231000000
515 *
516 * This format is the same as that expected by parseEPOCH16_2.
517 ******************************************************************************/
518 
encodeEPOCH16_2(epoch,epString)519 VISIBLE_PREFIX void encodeEPOCH16_2 (epoch, epString)
520 double epoch[2];
521 char epString[EPOCH16_2_STRING_LEN+1];
522 {
523   if (epoch[0] == -1.0E31 && epoch[1] == -1.0E31) {
524     strcpyX(epString, "99991231235959", 0);
525     return;
526   }
527 
528   encodeEPOCHx (epoch[0]*1000.0, "<year><mm.02><dom.02><hour><min><sec>",
529                 epString);
530   return;
531 }
532 
533 /******************************************************************************
534 * encodeEPOCH3.
535 * Converts an EPOCH value into a readable date/time string.
536 *
537 * Format:	yyyy-mm-ddThh:mm:ss.cccZ
538 * Examples:	1990-04-01T03:05:02.000Z
539 *		1993-10-10T23:45:49.999Z
540 *
541 * This format is the same as that expected by parseEPOCH3.
542 ******************************************************************************/
543 
encodeEPOCH3(epoch,epString)544 VISIBLE_PREFIX void encodeEPOCH3 (epoch, epString)
545 double epoch;
546 char epString[EPOCH3_STRING_LEN+1];
547 {
548   if (epoch == -1.0E31) {
549     strcpyX(epString, "9999-12-31T23:59:59.999Z", 0);
550     return;
551   }
552 
553   encodeEPOCHx (epoch, "<year>-<mm.02>-<dom.02>T<hour>:<min>:<sec>.<fos>Z",
554 		epString);
555   return;
556 }
557 
558 /******************************************************************************
559 * encodeEPOCH16_3.
560 * This function is an extension of encodeEPOCH3. It is used to handle the time
561 * that may contain as small as picoseconds.
562 *
563 * Format:       yyyy-mm-ddThh:mm:ss.mmm.uuu.nnn.pppZ
564 * Examples:     1990-04-01T03:05:02.000.000.000.000Z
565 *               1993-10-10T23:45:49.999.999.999.999Z
566 *               012345678901234567890123456789012345
567 * This format is the same as that expected by parseEPOCH16_3.
568 ******************************************************************************/
569 
encodeEPOCH16_3(epoch,epString)570 VISIBLE_PREFIX void encodeEPOCH16_3 (epoch, epString)
571 double epoch[2];
572 char epString[EPOCH16_3_STRING_LEN+1];
573 {
574   char tmp[EPOCH16_3_STRING_LEN+1];
575 
576   if (epoch[0] == -1.0E31 && epoch[1] == -1.0E31) {
577     strcpyX(epString, "9999-12-31T23:59:59.999.999.999.999Z", 0);
578     return;
579   }
580 
581   encodeEPOCHx (epoch[0]*1000.0,
582 		"<year>-<mm.02>-<dom.02>T<hour>:<min>:<sec>.",
583                 tmp);
584   strcpyX(epString, tmp, 20);
585   encodeEPOCH16x2 (epoch[1], tmp);
586   strcpyX(epString+20, tmp, 15);
587   epString[35] = 'Z';
588   epString[EPOCH16_3_STRING_LEN] = NUL;
589   return;
590 }
591 
592 /******************************************************************************
593 * encodeEPOCHx.
594 ******************************************************************************/
595 
encodeEPOCHx(epoch,format,encoded)596 VISIBLE_PREFIX void encodeEPOCHx (epoch, format, encoded)
597 double epoch;
598 char format[EPOCHx_FORMAT_MAX];
599 char encoded[EPOCHx_STRING_MAX];
600 {
601   char *ptr = format;		/* Current position in format string. */
602   char *ptrD;			/* Pointer to decimal point. */
603   char *ptrE;			/* Pointer to ending right angle bracket. */
604   char *p;			/* Temporary pointer. */
605   char part[MAX_PART_LEN+1];	/* Part being encoded. */
606   char mod[MAX_MOD_LEN+1];	/* Part modifier. */
607   long year, month, day, hour,
608        minute, second, msec;	/* EPOCH components. */
609   /****************************************************************************
610   * Break EPOCH down into its components, validate the format specification,
611   * and initialize the encoded string.
612   ****************************************************************************/
613   if (format == NULL || NULstring(format)) {
614     encodeEPOCH (epoch, encoded);
615     return;
616   }
617   EPOCHbreakdown (epoch, &year, &month, &day, &hour, &minute, &second, &msec);
618   MakeNUL (encoded);
619   /****************************************************************************
620   * Scan format string.
621   ****************************************************************************/
622   for (;;) {
623      switch (*ptr) {
624        /***********************************************************************
625        * End of format string.
626        ***********************************************************************/
627        case NUL:
628 	 return;
629        /***********************************************************************
630        * Start of part to be encoded.
631        ***********************************************************************/
632        case '<':
633 	 /*********************************************************************
634 	 * If next character is also a `<' (character stuffing), then append
635 	 * a `<' and move on.
636 	 *********************************************************************/
637 	 if (*(ptr+1) == '<') {
638 	   strcatX (encoded, "<", EPOCHx_STRING_MAX);
639 	   ptr += 2;
640 	   break;
641 	 }
642 	 /*********************************************************************
643 	 * Find ending right angle bracket.
644 	 *********************************************************************/
645 	 ptrE = strchr (ptr + 1, '>');
646 	 if (ptrE == NULL) {
647 	   strcatX (encoded, "?", EPOCHx_STRING_MAX);
648 	   return;
649 	 }
650 	 /*********************************************************************
651 	 * Check for a part modifier.
652 	 *********************************************************************/
653 	 ptrD = strchr (ptr + 1, '.');
654 	 if (ptrD != NULL && ptrD < ptrE) {
655 	   MakeNUL (part);
656 	   for (p = ptr+1; p != ptrD; p++) catchrX (part, (int) *p,
657 						    MAX_PART_LEN);
658 	   MakeNUL (mod);
659 	   for (p = ptrD+1; p != ptrE; p++) catchrX (mod, (int) *p,
660 						     MAX_MOD_LEN);
661 	 }
662 	 else {
663 	   MakeNUL (part);
664 	   for (p = ptr+1; p != ptrE; p++) catchrX (part, (int) *p,
665 						    MAX_PART_LEN);
666 	   MakeNUL (mod);
667 	 }
668 	 ptr = ptrE + 1;
669 	 /*********************************************************************
670 	 * Day (of month), <dom>.
671 	 *********************************************************************/
672 	 if (!strcmp(part,"dom")) {
673 	   if (!AppendIntegerPart(encoded,day,0,FALSE,mod)) return;
674 	   break;
675 	 }
676 	 /*********************************************************************
677 	 * Day of year, <doy>.
678 	 *********************************************************************/
679 	 if (!strcmp(part,"doy")) {
680 	   long doy = JulianDay(year,month,day) - JulianDay(year,1L,1L) + 1;
681 	   if (!AppendIntegerPart(encoded,doy,3,TRUE,mod)) return;
682 	   break;
683 	 }
684 	 /*********************************************************************
685 	 * Month (3-character), <month>.
686 	 *********************************************************************/
687 	 if (!strcmp(part,"month")) {
688 	   strcatX (encoded, MonthToken(month), EPOCHx_STRING_MAX);
689 	   break;
690 	 }
691 	 /*********************************************************************
692 	 * Month (digits), <mm>.
693 	 *********************************************************************/
694 	 if (!strcmp(part,"mm")) {
695 	   if (!AppendIntegerPart(encoded,month,0,FALSE,mod)) return;
696 	   break;
697 	 }
698 	 /*********************************************************************
699 	 * Year (full), <year>.
700 	 *********************************************************************/
701 	 if (!strcmp(part,"year")) {
702 	   if (!AppendIntegerPart(encoded,year,4,TRUE,mod)) return;
703 	   break;
704 	 }
705 	 /*********************************************************************
706 	 * Year (2-digit), <yr>.
707 	 *********************************************************************/
708 	 if (!strcmp(part,"yr")) {
709 	   long yr = year % 100L;
710 	   if (!AppendIntegerPart(encoded,yr,2,TRUE,mod)) return;
711 	   break;
712 	 }
713 	 /*********************************************************************
714 	 * Hour, <hour>.
715 	 *********************************************************************/
716 	 if (!strcmp(part,"hour")) {
717 	   if (!AppendIntegerPart(encoded,hour,2,TRUE,mod)) return;
718 	   break;
719 	 }
720 	 /*********************************************************************
721 	 * Minute, <min>.
722 	 *********************************************************************/
723 	 if (!strcmp(part,"min")) {
724 	   if (!AppendIntegerPart(encoded,minute,2,TRUE,mod)) return;
725 	   break;
726 	 }
727 	 /*********************************************************************
728 	 * Second, <sec>.
729 	 *********************************************************************/
730 	 if (!strcmp(part,"sec")) {
731 	   if (!AppendIntegerPart(encoded,second,2,TRUE,mod)) return;
732 	   break;
733 	 }
734 	 /*********************************************************************
735 	 * Fraction of second, <fos>.
736 	 *********************************************************************/
737 	 if (!strcmp(part,"fos")) {
738 	   double fos = ((double) msec) / 1000.0;
739 	   if (!AppendFractionPart(encoded,fos,3,mod)) return;
740 	   break;
741 	 }
742 	 /*********************************************************************
743 	 * Fraction of day, <fod>.
744 	 *********************************************************************/
745 	 if (!strcmp(part,"fod")) {
746 	   double fod = ((double) hour / 24.0) +
747 			((double) minute / 1440.0) +
748 			((double) second / 86400.0) +
749 			((double) msec / 86400000.0);
750 	   if (!AppendFractionPart(encoded,fod,8,mod)) return;
751 	   break;
752 	 }
753 	 /*********************************************************************
754 	 * Unknown/unsupported part.
755 	 *********************************************************************/
756 	 strcatX (encoded, "?", EPOCHx_STRING_MAX);
757 	 return;
758        /***********************************************************************
759        * Character to be copied.
760        ***********************************************************************/
761        default:
762 	 catchrX (encoded, (int) *ptr, EPOCHx_STRING_MAX);
763 	 ptr++;
764 	 break;
765      }
766   }
767 }
768 
769 /******************************************************************************
770 * encodeEPOCH16_x.
771 ******************************************************************************/
772 
encodeEPOCH16_x(epoch,format,encoded)773 VISIBLE_PREFIX void encodeEPOCH16_x (epoch, format, encoded)
774 double epoch[2];
775 char format[EPOCHx_FORMAT_MAX];
776 char encoded[EPOCHx_STRING_MAX];
777 {
778   char *ptr = format;		/* Current position in format string. */
779   char *ptrD;			/* Pointer to decimal point. */
780   char *ptrE;			/* Pointer to ending right angle bracket. */
781   char *p;			/* Temporary pointer. */
782   char part[MAX_PART_LEN+1];	/* Part being encoded. */
783   char mod[MAX_MOD_LEN+1];	/* Part modifier. */
784   long year, month, day, hour,
785        minute, second;
786   long msec, usec, nsec, psec;	/* EPOCH components. */
787   /****************************************************************************
788   * Break EPOCH down into its components, validate the format specification,
789   * and initialize the encoded string.
790   ****************************************************************************/
791   if (format == NULL || NULstring(format)) {
792     encodeEPOCH (epoch[0]*1000.0, encoded);
793     /* add epoch[1]... */
794     return;
795   }
796   EPOCH16breakdown (epoch, &year, &month, &day, &hour, &minute, &second,
797 		    &msec, &usec, &nsec, &psec);
798   MakeNUL (encoded);
799   /****************************************************************************
800   * Scan format string.
801   ****************************************************************************/
802   for (;;) {
803      switch (*ptr) {
804        /***********************************************************************
805        * End of format string.
806        ***********************************************************************/
807        case NUL:
808 	 return;
809        /***********************************************************************
810        * Start of part to be encoded.
811        ***********************************************************************/
812        case '<':
813 	 /*********************************************************************
814 	 * If next character is also a `<' (character stuffing), then append
815 	 * a `<' and move on.
816 	 *********************************************************************/
817 	 if (*(ptr+1) == '<') {
818 	   strcatX (encoded, "<", EPOCHx_STRING_MAX);
819 	   ptr += 2;
820 	   break;
821 	 }
822 	 /*********************************************************************
823 	 * Find ending right angle bracket.
824 	 *********************************************************************/
825 	 ptrE = strchr (ptr + 1, '>');
826 	 if (ptrE == NULL) {
827 	   strcatX (encoded, "?", EPOCHx_STRING_MAX);
828 	   return;
829 	 }
830 	 /*********************************************************************
831 	 * Check for a part modifier.
832 	 *********************************************************************/
833 	 ptrD = strchr (ptr + 1, '.');
834 	 if (ptrD != NULL && ptrD < ptrE) {
835 	   MakeNUL (part);
836 	   for (p = ptr+1; p != ptrD; p++) catchrX (part, (int) *p,
837 						    MAX_PART_LEN);
838 	   MakeNUL (mod);
839 	   for (p = ptrD+1; p != ptrE; p++) catchrX (mod, (int) *p,
840 						     MAX_MOD_LEN);
841 	 }
842 	 else {
843 	   MakeNUL (part);
844 	   for (p = ptr+1; p != ptrE; p++) catchrX (part, (int) *p,
845 						    MAX_PART_LEN);
846 	   MakeNUL (mod);
847 	 }
848 	 ptr = ptrE + 1;
849 	 /*********************************************************************
850 	 * Day (of month), <dom>.
851 	 *********************************************************************/
852 	 if (!strcmp(part,"dom")) {
853 	   if (!AppendIntegerPart(encoded,day,0,FALSE,mod)) return;
854 	   break;
855 	 }
856 	 /*********************************************************************
857 	 * Day of year, <doy>.
858 	 *********************************************************************/
859 	 if (!strcmp(part,"doy")) {
860 	   long doy = JulianDay(year,month,day) - JulianDay(year,1L,1L) + 1;
861 	   if (!AppendIntegerPart(encoded,doy,3,TRUE,mod)) return;
862 	   break;
863 	 }
864 	 /*********************************************************************
865 	 * Month (3-character), <month>.
866 	 *********************************************************************/
867 	 if (!strcmp(part,"month")) {
868 	   strcatX (encoded, MonthToken(month), EPOCHx_STRING_MAX);
869 	   break;
870 	 }
871 	 /*********************************************************************
872 	 * Month (digits), <mm>.
873 	 *********************************************************************/
874 	 if (!strcmp(part,"mm")) {
875 	   if (!AppendIntegerPart(encoded,month,0,FALSE,mod)) return;
876 	   break;
877 	 }
878 	 /*********************************************************************
879 	 * Year (full), <year>.
880 	 *********************************************************************/
881 	 if (!strcmp(part,"year")) {
882 	   if (!AppendIntegerPart(encoded,year,4,TRUE,mod)) return;
883 	   break;
884 	 }
885 	 /*********************************************************************
886 	 * Year (2-digit), <yr>.
887 	 *********************************************************************/
888 	 if (!strcmp(part,"yr")) {
889 	   long yr = year % 100L;
890 	   if (!AppendIntegerPart(encoded,yr,2,TRUE,mod)) return;
891 	   break;
892 	 }
893 	 /*********************************************************************
894 	 * Hour, <hour>.
895 	 *********************************************************************/
896 	 if (!strcmp(part,"hour")) {
897 	   if (!AppendIntegerPart(encoded,hour,2,TRUE,mod)) return;
898 	   break;
899 	 }
900 	 /*********************************************************************
901 	 * Minute, <min>.
902 	 *********************************************************************/
903 	 if (!strcmp(part,"min")) {
904 	   if (!AppendIntegerPart(encoded,minute,2,TRUE,mod)) return;
905 	   break;
906 	 }
907 	 /*********************************************************************
908 	 * Second, <sec>.
909 	 *********************************************************************/
910 	 if (!strcmp(part,"sec")) {
911 	   if (!AppendIntegerPart(encoded,second,2,TRUE,mod)) return;
912 	   break;
913 	 }
914          /*********************************************************************
915          * Fraction of second, <fos>.
916          *********************************************************************/
917          if (!strcmp(part,"fos")) {
918            double fos = (double) msec / pow (10.0, 3.0) +
919 			(double) usec / pow (10.0, 6.0) +
920 			(double) nsec / pow (10.0, 9.0) +
921 			(double) psec / pow (10.0, 12.0);
922            if (!AppendFractionPart(encoded,fos,12,mod)) return;
923            break;
924          }
925 	 /*********************************************************************
926 	 * Millisecond, <msc>.
927 	 *********************************************************************/
928 	 if (!strcmp(part,"msc")) {
929 	   if (!AppendIntegerPart(encoded,msec,3,TRUE,mod)) return;
930 	   break;
931 	 }
932          /*********************************************************************
933          * Microsecond, <usc>.
934          *********************************************************************/
935          if (!strcmp(part,"usc")) {
936            if (!AppendIntegerPart(encoded,usec,3,TRUE,mod)) return;
937            break;
938          }
939          /*********************************************************************
940          * Nanosecond, <nec>.
941          *********************************************************************/
942          if (!strcmp(part,"nsc")) {
943            if (!AppendIntegerPart(encoded,nsec,3,TRUE,mod)) return;
944            break;
945          }
946          /*********************************************************************
947          * Picosecond, <pec>.
948          *********************************************************************/
949          if (!strcmp(part,"psc")) {
950            if (!AppendIntegerPart(encoded,psec,3,TRUE,mod)) return;
951            break;
952          }
953 	 /*********************************************************************
954 	 * Fraction of day, <fod>.
955 	 *********************************************************************/
956 	 if (!strcmp(part,"fod")) {
957 	   double fod = ((double) hour / 24.0) +
958 			((double) minute / 1440.0) +
959 			((double) second / 86400.0) +
960 			((double) msec / 86400000.0);
961 	   if (!AppendFractionPart(encoded,fod,15,mod)) return;
962 	   break;
963 	 }
964 	 /*********************************************************************
965 	 * Unknown/unsupported part.
966 	 *********************************************************************/
967 	 strcatX (encoded, "?", EPOCHx_STRING_MAX);
968 	 return;
969        /***********************************************************************
970        * Character to be copied.
971        ***********************************************************************/
972        default:
973 	 catchrX (encoded, (int) *ptr, EPOCHx_STRING_MAX);
974 	 ptr++;
975 	 break;
976      }
977   }
978 }
979 
AppendFractionPart(encoded,fraction,defaultWidth,modifier)980 static Logical AppendFractionPart (encoded, fraction, defaultWidth, modifier)
981 char *encoded;
982 double fraction;
983 int defaultWidth;
984 char *modifier;
985 {
986   char ePart[MAX_ePART_LEN+1]; int width, i;
987   if (!NULstring(modifier)) {
988     if (sscanf(modifier,"%d",&width) != 1) {
989       strcatX (encoded, "?", EPOCHx_STRING_MAX);
990       return FALSE;
991     }
992     if (width < 1) {
993       strcatX (encoded, "?", EPOCHx_STRING_MAX);
994       return FALSE;
995     }
996   }
997   else
998     width = defaultWidth;
999   sprintf (ePart, "%*.*f", width + 2, width, fraction);
1000 #if defined(alphaosf)
1001   /****************************************************************************
1002   * V3.2 of OSF/1 apparently has a bug involving `sprintf'.  The preceeding
1003   * call to `sprintf' produces a string containing one too many digits after
1004   * the decimal.  Eg., if width=7 the encoded string might be 0.12345678
1005   * rather than 0.1234567 as it should be.  So we'll fix it...
1006   ****************************************************************************/
1007   ePart[width+2] = NUL;
1008 #endif
1009   /****************************************************************************
1010   * If the encoded value was rounded up to 1.000..., then replace all of the
1011   * digits after the decimal with `9's before appending.
1012   ****************************************************************************/
1013   if (ePart[0] == '1') {
1014     for (i = 0; i < width; i++) ePart[i+2] = '9';
1015   }
1016   return AppendPart(encoded,strchr(ePart,'.')+1,width,FALSE);
1017 }
1018 
AppendIntegerPart(encoded,integer,defaultWidth,defaultLeading0,modifier)1019 static Logical AppendIntegerPart (encoded, integer, defaultWidth,
1020 				  defaultLeading0, modifier)
1021 char *encoded;
1022 long integer;
1023 int defaultWidth;
1024 Logical defaultLeading0;
1025 char *modifier;
1026 {
1027   char ePart[MAX_ePART_LEN+1]; int width; Logical leading0;
1028   if (!NULstring(modifier)) {
1029     if (sscanf(modifier,"%d",&width) != 1) {
1030       strcatX (encoded, "?", EPOCHx_STRING_MAX);
1031       return FALSE;
1032     }
1033     if (width < 0) {
1034       strcatX (encoded, "?", EPOCHx_STRING_MAX);
1035       return FALSE;
1036     }
1037     leading0 = (modifier[0] == '0');
1038   }
1039   else {
1040     width = defaultWidth;
1041     leading0 = defaultLeading0;
1042   }
1043   sprintf (ePart, "%ld", integer);
1044   return AppendPart (encoded, ePart, width, leading0);
1045 }
1046 
AppendPart(encoded,ePart,width,leading0)1047 static Logical AppendPart (encoded, ePart, width, leading0)
1048 char *encoded;
1049 char *ePart;
1050 int width;
1051 Logical leading0;
1052 {
1053   int i;
1054   if (width == 0) {
1055     strcatX (encoded, ePart, EPOCHx_STRING_MAX);
1056   }
1057   else {
1058     int length = (int) strlen(ePart);
1059     if (length > width) {
1060       for (i = 0; i < width; i++) strcatX (encoded, "*", EPOCHx_STRING_MAX);
1061     }
1062     else {
1063       int pad = width - length;
1064       if (pad > 0) {
1065         for (i = 0; i < pad; i++) strcatX (encoded, BOO(leading0,"0"," "),
1066 					   EPOCHx_STRING_MAX);
1067       }
1068       strcatX (encoded, ePart, EPOCHx_STRING_MAX);
1069     }
1070   }
1071   return TRUE;
1072 }
1073 
encodeEPOCH16x2(epoch,encoded)1074 void encodeEPOCH16x2 (epoch, encoded)
1075 double epoch;
1076 char *encoded;
1077 {
1078   long msec, usec, nsec, psec;
1079   double mmm;
1080   psec = (long) fmod (epoch, (double) 1000.0);
1081   mmm = epoch / (double) 1000.0;
1082   nsec = (long) fmod (mmm, (double) 1000.0);
1083   mmm = mmm / (double) 1000.0;
1084   usec = (long) fmod (mmm, (double) 1000.0);
1085   msec = (long) (mmm / (double) 1000.0);
1086   sprintf(encoded, "%3.3ld.%3.3ld.%3.3ld.%3.3ld", msec, usec, nsec, psec);
1087   encoded[15] = NUL;
1088   return;
1089 }
1090 
encodeEPOCH16x3(epoch,encoded)1091 void encodeEPOCH16x3 (epoch, encoded)
1092 double epoch[2];
1093 char *encoded;
1094 {
1095   char tmp[17+1];
1096   long year, month, day, hour, minute, second, msec, usec, nsec, psec;
1097   double mmm1, mmm2, mmm3;
1098   EPOCH16breakdown (epoch, &year, &month, &day, &hour, &minute, &second,
1099 		    &msec, &usec, &nsec, &psec);
1100   mmm1 = ((double) hour * 3600.0 + (double) minute * 60.0 + (double) second) /
1101 	  86400.0;
1102   mmm2 = ((double) msec * pow(10.0, 9.0) + (double) usec * pow(10.0, 6.0) +
1103 	  (double) nsec * pow(10.0, 3.0) + (double) psec) /
1104 	  (86400.0 * pow(10.0, 12.0));
1105   mmm3 = mmm1 + mmm2;
1106   if (mmm3 >= 1.0) {
1107     if (mmm1 > 0.0 || mmm2 > 1.0E9)
1108       strcpyX (tmp, "0.999999999999999", 0);
1109   } else
1110     sprintf(tmp, "%.15f", mmm3);
1111   strcpyX (encoded, tmp+2, 15);
1112 /*  encoded[16] = NUL; */
1113   return;
1114 }
1115 
1116 /******************************************************************************
1117 * computeEPOCH.
1118 * Computes (and returns) an EPOCH value based on its component parts.
1119 * ILLEGAL_EPOCH_VALUE is returned if an illegal component part is detected.
1120 ******************************************************************************/
1121 
computeEPOCH(year,month,day,hour,minute,second,msec)1122 VISIBLE_PREFIX double computeEPOCH (year, month, day, hour, minute, second,
1123 				    msec)
1124 long year, month, day, hour, minute, second, msec;
1125 {
1126   long daysSince0AD, msecInDay;
1127 
1128   /****************************************************************************
1129   * Mark 9999-12-31 23:59:59:999 as an invalid date.
1130   ****************************************************************************/
1131   if (year == 9999 && month == 12 && day == 31 && hour == 23 &&
1132       minute == 59 && second == 59 && msec == 999) return -1.0*pow(10.0, 31.0);
1133 
1134   /****************************************************************************
1135   * Calculate the days since 0 A.D (1-Jan-0000).  If a value of zero is passed
1136   * in for `month', assume that `day' is the day-of-year (DOY) with January 1st
1137   * being day 1.
1138   ****************************************************************************/
1139   if (month == 0) {
1140     if (year < 0 || year > 9999) return ILLEGAL_EPOCH_VALUE;
1141     if (day < 1 || day > 366) return ILLEGAL_EPOCH_VALUE;
1142     daysSince0AD = (JulianDay(year,1L,1L) + (day-1)) - 1721060L;
1143   }
1144   else {
1145     if (year < 0 || year > 9999) return ILLEGAL_EPOCH_VALUE;
1146     if (month < 1 || month > 12) return ILLEGAL_EPOCH_VALUE;
1147     if (day < 1 || day > 31) return ILLEGAL_EPOCH_VALUE;
1148     daysSince0AD = JulianDay(year,month,day) - 1721060L;
1149   }
1150   /****************************************************************************
1151   * Calculate the millisecond in the day (with the first millisecond being 0).
1152   * If values of zero are passed in for `hour', `minute', and `second', assume
1153   * that `msec' is the millisecond in the day.
1154   ****************************************************************************/
1155   if (hour == 0 && minute == 0 && second == 0) {
1156     if (msec < 0 || msec > 86399999L) return ILLEGAL_EPOCH_VALUE;
1157     msecInDay = msec;
1158   }
1159   else {
1160     if (hour < 0 || hour > 23) return ILLEGAL_EPOCH_VALUE;
1161     if (minute < 0 || minute > 59) return ILLEGAL_EPOCH_VALUE;
1162     if (second < 0 || second > 59) return ILLEGAL_EPOCH_VALUE;
1163     if (msec < 0 || msec > 999) return ILLEGAL_EPOCH_VALUE;
1164     msecInDay = (3600000L * hour) + (60000L * minute) + (1000 * second) + msec;
1165   }
1166   /****************************************************************************
1167   * Return the milliseconds since 0 A.D.
1168   ****************************************************************************/
1169   return ((86400000L * ((double) daysSince0AD)) + ((double) msecInDay));
1170 }
1171 
1172 /******************************************************************************
1173 * computeEPOCH16.
1174 * This function is an extension of computeEPOCH. It is used to handle the time
1175 * that may contain as small as picoseconds.
1176 ******************************************************************************/
1177 
computeEPOCH16(year,month,day,hour,minute,second,msec,usec,nsec,psec,epoch)1178 VISIBLE_PREFIX double computeEPOCH16 (year, month, day, hour, minute,
1179                                       second, msec, usec, nsec, psec,
1180 				      epoch)
1181 long year, month, day, hour, minute, second, msec, usec, nsec, psec;
1182 double epoch[2];
1183 {
1184   long daysSince0AD;
1185 
1186   /****************************************************************************
1187   * Mark 9999-12-31 23:59:59:999:999:999:999 as an invalid date.
1188   ****************************************************************************/
1189   if (year == 9999 && month == 12 && day == 31 && hour == 23 &&
1190       minute == 59 && second == 59 && msec == 999 && usec == 999 &&
1191       nsec == 999 && psec == 999) {
1192     epoch[0] = -1.0E31;
1193     epoch[1] = -1.0E31;
1194     return 0.0;
1195   }
1196 
1197   /****************************************************************************
1198   * Calculate the days since 0 A.D (1-Jan-0000).  If a value of zero is passed
1199   * in for `month', assume that `day' is the day-of-year (DOY) with January 1st
1200   * being day 1.
1201   ****************************************************************************/
1202   if (month == 0) {
1203     if (year < 0 || year > 9999) return ILLEGAL_EPOCH_VALUE;
1204     if (day < 1 || day > 366) return ILLEGAL_EPOCH_VALUE;
1205     daysSince0AD = (JulianDay(year,1L,1L) + (day-1)) - 1721060L;
1206   }
1207   else {
1208     if (year < 0 || year > 9999) return ILLEGAL_EPOCH_VALUE;
1209     if (month < 1 || month > 12) return ILLEGAL_EPOCH_VALUE;
1210     if (day < 1 || day > 31) return ILLEGAL_EPOCH_VALUE;
1211     daysSince0AD = JulianDay(year,month,day) - 1721060L;
1212   }
1213   /****************************************************************************
1214   * Calculate the millisecond in the day (with the first millisecond being 0).
1215   * If values of zero are passed in for `hour', `minute', and `second', assume
1216   * that `msec' is the millisecond in the day.
1217   ****************************************************************************/
1218   if (hour < 0 || hour > 23) return ILLEGAL_EPOCH_VALUE;
1219   if (minute < 0 || minute > 59) return ILLEGAL_EPOCH_VALUE;
1220   if (second < 0 || second > 59) return ILLEGAL_EPOCH_VALUE;
1221   if (msec < 0 || msec > 999) return ILLEGAL_EPOCH_VALUE;
1222   if (usec < 0 || usec > 999) return ILLEGAL_EPOCH_VALUE;
1223   if (nsec < 0 || nsec > 999) return ILLEGAL_EPOCH_VALUE;
1224   if (psec < 0 || psec > 999) return ILLEGAL_EPOCH_VALUE;
1225   /****************************************************************************
1226   * Return the seconds and picoseconds since 0 A.D.
1227   ****************************************************************************/
1228   epoch[0] = 86400.0 * (double) daysSince0AD + 3600.0 * (double) hour +
1229              60.0 * (double) minute + (double) second;
1230   epoch[1] = (double) psec + (double) nsec * pow(10.0, 3.0) +
1231              (double) usec * pow(10.0, 6.0) + (double) msec * pow(10.0, 9.0);
1232   return (double) 0.0;
1233 }
1234 
1235 /******************************************************************************
1236 * EPOCHbreakdown.
1237 * Breaks an EPOCH value down into its component parts.
1238 ******************************************************************************/
1239 
EPOCHbreakdown(epoch,year,month,day,hour,minute,second,msec)1240 VISIBLE_PREFIX void EPOCHbreakdown (epoch, year, month, day, hour, minute,
1241 				    second, msec)
1242 double epoch;
1243 long *year, *month, *day, *hour, *minute, *second, *msec;
1244 {
1245   long jd,i,j,k,l,n;
1246   double msec_AD, second_AD, minute_AD, hour_AD, day_AD;
1247 
1248   if (epoch == -1.0E31) {
1249     *year = 9999;
1250     *month = 12;
1251     *day = 31;
1252     *hour = 23;
1253     *minute = 59;
1254     *second = 59;
1255     *msec = 999;
1256     return;
1257   }
1258 
1259   if (NegativeZeroReal8(&epoch)) {
1260     *year = 0;
1261     *month = 0;
1262     *day = 0;
1263     *hour = 0;
1264     *minute = 0;
1265     *second = 0;
1266     *msec = 0;
1267     return;
1268   }
1269 
1270   if (epoch < 0.0) epoch = -epoch;
1271   epoch = MINIMUM ((double)MAX_EPOCH_BINARY, epoch);
1272 
1273   msec_AD = epoch;
1274   second_AD = msec_AD / 1000.0;
1275   minute_AD = second_AD / 60.0;
1276   hour_AD = minute_AD / 60.0;
1277   day_AD = hour_AD / 24.0;
1278 
1279   jd = (long) (1721060 + day_AD);
1280   l=jd+68569;
1281   n=4*l/146097;
1282   l=l-(146097*n+3)/4;
1283   i=4000*(l+1)/1461001;
1284   l=l-1461*i/4+31;
1285   j=80*l/2447;
1286   k=l-2447*j/80;
1287   l=j/11;
1288   j=j+2-12*l;
1289   i=100*(n-49)+i+l;
1290 
1291   *year = i;
1292   *month = j;
1293   *day = k;
1294 
1295   *hour   = (long) fmod (hour_AD, (double) 24.0);
1296   *minute = (long) fmod (minute_AD, (double) 60.0);
1297   *second = (long) fmod (second_AD, (double) 60.0);
1298   *msec   = (long) fmod (msec_AD, (double) 1000.0);
1299 
1300   return;
1301 }
1302 
1303 /******************************************************************************
1304 * EPOCH16breakdown.
1305 * This function is an extension of EPOCHbreakdown. It is used to handle the
1306 * time that may contain as small as picoseconds.
1307 ******************************************************************************/
1308 
EPOCH16breakdown(epoch,year,month,day,hour,minute,second,msec,usec,nsec,psec)1309 VISIBLE_PREFIX void EPOCH16breakdown (epoch, year, month, day, hour,
1310                                       minute, second, msec, usec, nsec, psec)
1311 double epoch[2];
1312 long *year, *month, *day, *hour, *minute, *second;
1313 long *msec, *usec, *nsec, *psec;
1314 {
1315   long jd,i,j,k,l,n;
1316   double second_AD, minute_AD, hour_AD, day_AD;
1317   double psec_SC, nsec_SC, usec_SC;
1318 
1319   if (epoch[0] == -1.0E31 && epoch[1] == -1.0E31) {
1320     *year = 9999;
1321     *month = 12;
1322     *day = 31;
1323     *hour = 23;
1324     *minute = 59;
1325     *second = 59;
1326     *msec = 999;
1327     *usec = 999;
1328     *nsec = 999;
1329     *psec = 999;
1330     return;
1331   }
1332 
1333   if (NegativeZeroReal8(&epoch[0])) {
1334     *year = 0;
1335     *month = 0;
1336     *day = 0;
1337     *hour = 0;
1338     *minute = 0;
1339     *second = 0;
1340   }
1341   if (NegativeZeroReal8(&epoch[1])) {
1342     *msec = 0;
1343     *usec = 0;
1344     *nsec = 0;
1345     *psec = 0;
1346   }
1347 
1348   if (epoch[0] < 0.0) epoch[0] = -epoch[0];
1349   if (epoch[1] < 0.0) epoch[1] = -epoch[1];
1350   epoch[0] = MINIMUM ((double)MAX_EPOCH16_1_BINARY, epoch[0]);
1351   if (epoch[0] == MAX_EPOCH16_1_BINARY)
1352     epoch[1] = MINIMUM ((double)MAX_EPOCH16_2_BINARY, epoch[1]);
1353   else
1354     epoch[1] = MINIMUM ((double)MAX_EPOCH16_2_BINARY+1.0, epoch[1]);
1355 
1356   second_AD = epoch[0];
1357   minute_AD = second_AD / 60.0;
1358   hour_AD = minute_AD / 60.0;
1359   day_AD = hour_AD / 24.0;
1360 
1361   jd = (long) (1721060 + day_AD);
1362   l=jd+68569;
1363   n=4*l/146097;
1364   l=l-(146097*n+3)/4;
1365   i=4000*(l+1)/1461001;
1366   l=l-1461*i/4+31;
1367   j=80*l/2447;
1368   k=l-2447*j/80;
1369   l=j/11;
1370   j=j+2-12*l;
1371   i=100*(n-49)+i+l;
1372 
1373   *year = i;
1374   *month = j;
1375   *day = k;
1376 
1377   *hour   = (long) fmod (hour_AD, (double) 24.0);
1378   *minute = (long) fmod (minute_AD, (double) 60.0);
1379   *second = (long) fmod (second_AD, (double) 60.0);
1380 
1381   psec_SC = epoch[1];
1382   *psec = (long) fmod(epoch[1], (double) 1000.0);
1383   nsec_SC = psec_SC / 1000.0;
1384   *nsec = (long) fmod(nsec_SC, (double) 1000.0);
1385   usec_SC = nsec_SC / 1000.0;
1386   *usec = (long) fmod(usec_SC, (double) 1000.0);
1387   *msec = (long) (usec_SC / (double) 1000.0);
1388 
1389   return;
1390 }
1391 
1392 /******************************************************************************
1393 * JulianDay.
1394 * The year, month, and day are assumed to have already been validated.  This
1395 * is the day since 0 AD/1 BC.  (Julian day may not be the proper term.)
1396 ******************************************************************************/
1397 
JulianDay(y,m,d)1398 static long JulianDay (y,m,d)
1399 long y, m, d;
1400 {
1401   return (367*y-7*(y+(m+9)/12)/4-3*((y+(m-9)/7)/100+1)/4+275*m/9+d+1721029);
1402 }
1403 
1404 /******************************************************************************
1405 * MonthToken.
1406 ******************************************************************************/
1407 
MonthToken(month)1408 static char *MonthToken (month)
1409 long month;
1410 {
1411   switch (month) {
1412     case 1: return "Jan";
1413     case 2: return "Feb";
1414     case 3: return "Mar";
1415     case 4: return "Apr";
1416     case 5: return "May";
1417     case 6: return "Jun";
1418     case 7: return "Jul";
1419     case 8: return "Aug";
1420     case 9: return "Sep";
1421     case 10: return "Oct";
1422     case 11: return "Nov";
1423     case 12: return "Dec";
1424   }
1425   return "???";
1426 }
1427 
1428 /******************************************************************************
1429 * FullDayToken.
1430 ******************************************************************************/
1431 
FullDayToken(day3)1432 static char *FullDayToken (day3)
1433 char *day3;
1434 {
1435   if (!strcmp(day3,"Sun")) return "Sunday";
1436   if (!strcmp(day3,"Mon")) return "Monday";
1437   if (!strcmp(day3,"Tue")) return "Tuesday";
1438   if (!strcmp(day3,"Wed")) return "Wednesday";
1439   if (!strcmp(day3,"Thu")) return "Thursday";
1440   if (!strcmp(day3,"Fri")) return "Friday";
1441   if (!strcmp(day3,"Sat")) return "Saturday";
1442   return "Someday";
1443 }
1444 
1445 /******************************************************************************
1446 * TimeStamp.
1447 * Gets the date & time from the system and encodes a string in the following
1448 * form:
1449 *
1450 *     ddddddddd, dd-mmm-yyyy hh:mm:ss
1451 *
1452 * Examples:
1453 *
1454 *     Saturday, 23-Oct-1993 09:37:34
1455 *     Sunday, 2-Jan-1994 10:00:00
1456 *     Wednesday, 27-Oct-1993 23:59:59
1457 *
1458 * Trailing blanks are not appended if the string is shorter than its maximum
1459 * possible length.
1460 ******************************************************************************/
1461 
TimeStamp(stampStr)1462 VISIBLE_PREFIX void TimeStamp (stampStr)
1463 char *stampStr;
1464 {
1465   time_t bintim;
1466   char ctimeStr[CTIME_STRING_LEN+1], dayOfWeek3[3+1], dayOfMonth[2+1],
1467        year[4+1], month[3+1], hourMinuteSecond[8+1];
1468   time (&bintim);
1469   strcpyX (ctimeStr, ctime(&bintim), CTIME_STRING_LEN);
1470   strcpyX (dayOfWeek3, ctimeStr, 3);
1471   strcpyX (dayOfMonth, &ctimeStr[8], 2);
1472   if (dayOfMonth[0] == ' ') memmove (dayOfMonth, &dayOfMonth[1], 2);
1473   strcpyX (year, &ctimeStr[20], 4);
1474   strcpyX (month, &ctimeStr[4], 3);
1475   strcpyX (hourMinuteSecond, &ctimeStr[11], 8);
1476   sprintf (stampStr, "%s, %s-%s-%s %s", FullDayToken(dayOfWeek3), dayOfMonth,
1477 	   month, year, hourMinuteSecond);
1478   return;
1479 }
1480