source: buchla-68k/orig/DATE/GDATE.C@ 4b63bf3

Last change on this file since 4b63bf3 was 3ae31e9, checked in by Thomas Lopatic <thomas@…>, 7 years ago

Imported original source code.

  • Property mode set to 100755
File size: 10.8 KB
Line 
1/* gdate.c -- get date -- Version 1 -- 1986-01-09 */
2/* requires the "notorious" timeb.h and ftime() */
3
4/*
5
6 Here's a string->tm converter that I wrote quite some time ago
7 that takes several forms of date input and heuristically tries
8 to figure out what it might be, more or less inspired by TOPS-20
9 (handles more date formats I think.)
10
11 This is what date(1) should have been built out of!
12
13 It's just one file, the comments should be enough to figure out
14 what is going on (very simple to interface, probably hairy to
15 modify tho.)
16
17 Original code by:
18 -Barry Shein, Boston University
19
20 Various mods by:
21 -D.N. Lynx Crowe
22
23*/
24
25#include "stdio.h"
26#include "ctype.h"
27
28#include "types.h"
29
30#include "time.h"
31#include "timeb.h"
32
33#define MAXTOK 20
34
35/*
36 * routines to turn a date from various formats to other formats
37 *
38 * Primary interesting routine is gdate() which eats a date
39 * string of several common formats (see comment) and
40 * fills in a standard UNIX tm structure.
41 *
42 * if you compile it with DEBUG defined it will
43 * pull in a main() routine to run standalone for testing.
44 */
45
46#define AMBIG -1 /* ambiguous month */
47#define FALSE -2 /* bad syntax */
48
49char *months[] = {
50
51 "january", "february", "march", "april", "may", "june", "july",
52 "august", "september", "october", "november", "december", 0
53};
54
55char *dow[] = {
56
57 "sunday", "monday", "tuesday", "wednesday", "thursday",
58 "friday", "saturday", 0
59};
60
61/*
62 * known time-zone name list
63 */
64
65char *tz[] = {
66
67 "adt", "ast", "edt", "est", "cdt", "cst", "mst", "mdt",
68 "pdt", "pst", "gmt",
69 0
70} ;
71
72char mdays[] = {
73
74 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
75} ;
76
77lcase(c)
78register char c ;
79{
80 return(isupper(c) ? tolower(c) : c) ;
81}
82
83/*
84 * get a digit string from sp into bp (buffer) returning new sp
85 */
86
87char *
88dstring(bp,sp)
89register char *sp, *bp ;
90{
91 register int i = 0 ;
92 while(isdigit(*sp))
93 if(i++ == MAXTOK) break ;
94 else *bp++ = *sp++ ;
95 *bp = '\0' ;
96 return(sp) ;
97}
98
99/*
100 * skip white space returning updated ptr
101 */
102
103char *
104skipw(sp)
105register char *sp ;
106{
107 while(isspace(*sp) || *sp == '-') ++sp ;
108 return(sp) ;
109}
110
111/*
112 * return how many chars of s1 prefix s2
113 */
114
115prefix(s1,s2)
116register char *s1, *s2 ;
117{
118 register int i = 0 ;
119
120 for(; *s1 == *s2 ; s1++,s2++,i++)
121 if(*s2 == '\0') break ;
122 return(*s1 == '\0' ? i : 0) ;
123}
124
125/*
126 * look up str in list for non-ambiguous (prefix) match
127 */
128
129find(sp,lp)
130register char *sp, **lp ;
131{
132 int i,j,ambig = 0 ;
133 register int k ;
134 int ret = FALSE ;
135
136 for(i = 0,k = 0 ; *lp ; lp++,k++)
137 if((j = prefix(sp,*lp)) > i)
138 {
139 ambig = 0 ;
140 i = j ;
141 ret = k + 1 ;
142 }
143 else if(j && (i == j)) ++ambig ;
144 return(ambig ? AMBIG : ret) ;
145}
146
147/*
148 * like find but demands exact match
149 */
150
151lookup(sp,lp)
152register char *sp, **lp ;
153{
154 int i = 0 ;
155
156 for(i=0 ; *lp ; lp++,i++)
157 if(strcmp(sp,*lp) == 0) return(i+1) ;
158 return(0) ;
159}
160
161/*
162 * extract a token
163 */
164
165char *
166extract(bp,sp)
167register char *bp, *sp ;
168{
169 register int i = 0 ;
170
171 sp = skipw(sp) ;
172 for(; isalnum(*sp); sp++)
173 if(i++ == MAXTOK) break ;
174 else *bp++ = lcase(*sp) ;
175 *bp = '\0' ;
176 return(sp) ;
177}
178
179/*
180 * fill up an area with a value (eg. zeros)
181 */
182
183fill(cp,c,n)
184register char *cp, c;
185register int n ;
186{
187 while(n--) *cp++ = c ;
188}
189
190char *gdate(), *gtime() ;
191long totime();
192
193#if DEBUG
194/*
195 * test driver
196 * translates first arg from command line (argv[1])
197 * and dumps out structure built.
198 */
199
200usage(sp) char *sp ;
201{
202 fprintf(stderr,"Usage: %s date\n",sp) ;
203 exit(1) ;
204}
205
206main(argc,argv) int argc ; char **argv ;
207{
208 char *cp ;
209 struct tm tm ;
210 long t,t2 ;
211
212 if(argc != 2) usage(*argv) ;
213 if((cp = gdate(*++argv,&tm)) != NULL)
214 printf("error: %s (%s)\n",*argv,cp) ;
215 printf("year : %d month: %d day: %d\n",
216 tm.tm_year,tm.tm_mon,tm.tm_mday);
217 printf("day of month: %d hour: %d minute: %d second: %d\n",
218 tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec) ;
219 printf("day of year: %d day of week: %d dst: %d\n",
220 tm.tm_yday, tm.tm_wday, tm.tm_isdst) ;
221 time(&t) ;
222 t2 = totime(&tm) ;
223 printf("%D %D %D\n",t,t2,t2-t) ;
224 exit(0) ;
225}
226#endif /* DEBUG */
227
228/*
229 * gdate(date_str_ptr,time_buf_ptr)
230 * (see CTIME(3) in UPM for second arg format)
231 * takes many reasonable date strings and translates to
232 * the time-buf structure (integers)
233 *
234 * formats (eg.):
235 * oct 19, 1983
236 * OcT 19, 1983 12:43
237 * oCt 19, 1983 12:43:33
238 * oct 19 1983 ...
239 * 19 oct 83 ....
240 * 10/19/83 12:43:33
241 * 19-OCT-83 12:43:00 (DEC style)
242 * Wed Oct 19 12:43 EST 83 (UNIX style)
243 * oct. 19, 83 1:44 pm est
244 * 831019124333 (see date(1))
245 * some variations on those themes also.
246 *
247 * BUGS: probably a few (maybe some in the eye of the beholder)
248 * does not set dst flag (unless 'EDT' is in string)
249 */
250
251char *
252gdate(sp,tp) register char *sp ; register struct tm *tp ;
253{
254 char buf[MAXTOK] ;
255
256 fill(tp,'\0',sizeof *tp) ;
257 sp = skipw(sp) ;
258 if(isdigit(*sp)) /* either '7/12/83' or '12 jul 83' */
259 {
260 if(isdigit(sp[1]) && isdigit(sp[2])) /* UNIX yymmddhhmmss */
261 {
262 buf[2] = '\0' ;
263 strncpy(buf,sp,2) ;
264 tp->tm_year = atoi(buf) ;
265 strncpy(buf,sp += 2,2) ;
266 tp->tm_mon = atoi(buf) ;
267 sp += 2 ;
268
269 if(!isdigit(*sp)) goto badday ;
270
271 strncpy(buf,sp,2) ;
272 tp->tm_mday = atoi(buf) ;
273 sp += 2 ;
274
275 if(!isdigit(*sp)) goto check ;
276
277 strncpy(buf,sp,2) ;
278 tp->tm_hour ;
279 sp += 2 ;
280
281 if(!isdigit(*sp)) goto check ;
282
283 strncpy(buf,sp,2) ;
284 tp->tm_min = atoi(buf) ;
285 sp += 2 ;
286
287 if(!isdigit(*sp)) goto check ;
288
289 strncpy(buf,sp,2) ;
290 tp->tm_min = atoi(buf) ;
291 goto check ;
292 }
293
294 sp = dstring(buf,sp) ;
295 sp = skipw(sp) ;
296
297 if(*sp == '/') /* must be '7/12/83' */
298 {
299 if((tp->tm_mon = atoi(buf)) < 1 || (tp->tm_mon > 12))
300 {
301 tp->tm_mon = FALSE ;
302 goto badmon ;
303 }
304
305 sp = skipw(++sp) ;
306
307 if(!isdigit(*sp)) goto badday ;
308
309 sp = dstring(buf,sp) ;
310 tp->tm_mday = atoi(buf) ;
311
312 sp = skipw(sp) ;
313
314 if(*sp != '/') goto badyr ;
315
316 sp = skipw(++sp) ;
317
318 if(!isdigit(*sp)) goto badyr ;
319
320 sp = dstring(buf,sp) ;
321 tp->tm_year = atoi(buf) ;
322
323 sp = gtime(sp,tp) ;
324
325 } else {
326
327 /*
328 * must be '12 jul 83'
329 */
330 tp->tm_mday = atoi(buf) ;
331
332 sp = extract(buf,sp) ;
333 if((tp->tm_mon = find(buf,months)) < 1) goto badmon ;
334
335 if(*sp == '.') ++sp ;
336
337 sp = skipw(sp) ;
338
339 if(!isdigit(*sp)) goto badyr ;
340
341 sp = dstring(buf,sp) ;
342 tp->tm_year = atoi(buf) ;
343
344 sp = gtime(sp,tp) ;
345 }
346
347 } else {
348
349 int flag = 0 ; /* used to indicate looking for UNIX style */
350
351 /*
352 * either 'jul 12 83' or (UNIX) Wed jul 12 18:33 EST 1983
353 */
354
355 sp = extract(buf,sp) ;
356
357 if(find(buf,dow) > 0) {
358 sp = extract(buf,sp) ;
359 ++flag ;
360 }
361
362 if((tp->tm_mon = find(buf,months)) < 1) goto badmon ;
363
364 if(*sp == '.') ++sp ;
365
366 sp = skipw(sp) ;
367
368 if(!isdigit(*sp)) goto badday ;
369
370 sp = dstring(buf,sp) ;
371 tp->tm_mday = atoi(buf) ;
372
373 sp = skipw(sp) ;
374
375 if(*sp == ',') sp++ ;
376
377 sp = skipw(sp) ;
378
379 if(flag) sp = skipw(gtime(sp,tp)) ;
380
381 if(!isdigit(*sp)) goto badyr ;
382
383 sp = dstring(buf,sp) ;
384 tp->tm_year = atoi(buf) ;
385
386 if(!flag) sp = gtime(sp,tp) ;
387 }
388check:
389 /*
390 * check for ridiculous numbers
391 */
392
393 if(tp->tm_mday < 1) goto badday ;
394
395 if(tp->tm_mday > mdays[tp->tm_mon-1])
396 if(!((tp->tm_mon == 2) && /* check for Feb 29 */
397 (tp->tm_mday == 29) && (days(tp->tm_year) == 365) ))
398 goto badday ;
399
400 if(tp->tm_year >= 1900) tp->tm_year -= 1900 ;
401
402 if(tp->tm_hour > 23) {
403 tp->tm_hour = FALSE ;
404 return(sp) ;
405 }
406
407 if(tp->tm_min > 59) {
408 tp->tm_hour = FALSE ;
409 return(sp) ;
410 }
411
412 if(tp->tm_sec > 59) {
413 tp->tm_sec = FALSE ;
414 return(sp) ;
415 }
416
417 /*
418 * fill in day of year, day of week (these calls must be
419 * in this order as dowk() needs doyr()
420 */
421
422 doyr(tp) ;
423 dowk(tp) ;
424
425 /*
426 * all done !
427 */
428
429 return(NULL) ;
430
431badday :
432 tp->tm_mday = FALSE ;
433 return(sp) ;
434
435badmon :
436 return(sp) ;
437
438badyr :
439 tp->tm_year = FALSE ;
440 return(sp) ;
441}
442
443/*
444 * get hh:mm:ss
445 */
446
447char *
448gtime(sp,tp)
449register char *sp;
450register struct tm *tp ;
451{
452 char buf[MAXTOK],*cp ;
453
454 sp = skipw(sp) ;
455
456 if(isdigit(*sp)) {
457 sp = dstring(buf,sp) ;
458 tp->tm_hour = atoi(buf) ;
459 sp = skipw(sp) ;
460
461 if(*sp == ':')
462 sp = skipw(++sp) ;
463 else
464 goto out ;
465
466 if(isdigit(*sp)) {
467 sp = dstring(buf,sp) ;
468 tp->tm_min = atoi(buf) ;
469 sp = skipw(sp) ;
470
471 if(*sp == ':')
472 sp = skipw(++sp) ;
473 else
474 goto out ;
475
476 if(isdigit(*sp)) {
477 sp = dstring(buf,sp) ;
478 tp->tm_sec = atoi(buf) ;
479 }
480 }
481 }
482out :
483 sp = skipw(sp) ;
484
485 if(isalpha(*sp)) { /* PM:AM or time zone or both */
486
487 cp = extract(buf,sp) ;
488
489 if(strcmp(buf,"am") == 0 || strcmp(buf,"pm") == 0) {
490
491 if(buf[0] == 'p' && tp->tm_hour < 12)
492 tp->tm_hour += 12 ;
493
494 sp = cp = skipw(cp) ;
495 cp = extract(buf,cp) ;
496 }
497
498 if(lookup(buf,tz)) {
499 if(buf[1] == 'd') tp->tm_isdst++ ;
500 sp = skipw(cp) ;
501 }
502 }
503
504 return(sp) ;
505}
506
507/*
508 * Ok, you were all wondering so here it is folks...
509 * THE LEAP YEAR CALCULATION
510 * note: does not take into account 1752.
511 */
512
513days(y)
514register int y ;
515{
516 if(y < 1970)
517 y += 1900 ;
518
519 if(((y % 4) == 0) && ( (y % 100) || ((y % 400)==0) ))
520 y = 366 ;
521 else
522 y = 365 ;
523
524 return(y) ;
525}
526
527/*
528 * translate a time.h structure to seconds since 1/1/70
529 * (ie. UNIX internal time format...GMT)
530 */
531
532long
533totime(tp)
534register struct tm *tp ;
535{
536 long ret = 0 ;
537 int i,j ;
538
539 struct timeb tb ;
540
541 if(tp->tm_year < 70) return(0) ;
542
543 for(i=1970,j=tp->tm_year+1900 ; i<j ; i++)
544 ret += days(i) ;
545
546 for(i=1 ; i < tp->tm_mon ; i++)
547 ret += mdays[i-1] ;
548
549 if((days(tp->tm_year) == 366) && (tp->tm_mon > 2))
550 ++ret ;
551
552 ret += (tp->tm_mday - 1) ;
553 ret *= 24 ;
554 ret += tp->tm_hour ;
555 ret *= 60 ;
556
557 ftime(&tb) ;
558
559 ret += (tp->tm_min + tb.timezone) ;
560 ret *= 60 ;
561 ret += tp->tm_sec ;
562 return(ret) ;
563}
564
565/*
566 * return day of the week
567 * of jan 1 of given year
568 */
569
570jan1(yr)
571{
572 register y, d;
573
574/*
575 * normal gregorian calendar
576 * one extra day per four years
577 */
578
579 y = yr;
580 d = 4+y+(y+3)/4;
581
582/*
583 * julian calendar
584 * regular gregorian
585 * less three days per 400
586 */
587
588 if(y > 1800) {
589 d -= (y-1701)/100;
590 d += (y-1601)/400;
591 }
592
593/*
594 * take care of weirdness at 1752.
595 */
596
597 if(y > 1752)
598 d += 3;
599
600 return(d%7);
601}
602
603/*
604 * given day of year and year calculate and insert day-of-week (0..6)
605 */
606
607dowk(tp) register struct tm *tp ;
608{
609 tp->tm_wday = (jan1(tp->tm_year+1900) + tp->tm_yday) % 7 ;
610}
611
612/*
613 * calculate day of year from year
614 */
615
616doyr(tp) register struct tm *tp ;
617{
618 register int i,j ;
619
620 j = ((tp->tm_mon > 2) && (days(tp->tm_year) == 366)) ? 1 : 0 ;
621
622 for(i=1 ; i < tp->tm_mon ; i++)
623 j += mdays[i-1] ;
624
625 tp->tm_yday = j + tp->tm_mday - 1 ;
626}
Note: See TracBrowser for help on using the repository browser.