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