/* * cdate: convert date format * usage: cdate [-n] date * usage: cdate -k key1,key2,... [file] * key1,key2,... are fields that begin with 0 * * kenji Arisawa */ #include #include #include #define gline() Brdstr(&in, '\n', 1) #define atoul(s) ((ulong)atol(s)) #define MFIELD 32 Biobuf in; Biobuf out; ulong now; char *zone; int nflag=0; char *mon[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", }; void usage(void) { fprint(2,"usage: cdate [-n] ....\n"); fprint(2,"usage: cdate -k key1,key2,... [file]\n"); exits("usage"); } int smatch(char *s, char *p) { char *digit="0123456789"; char *s0; s0 = s; while(*s && *p){ if((*p == '0' && strchr(digit,*s))|| *s == *p){ p++; s++; continue; } break; } if(*s) return 0; return s - s0; } int mon2int(char *m) { int i; for(i=0; i < 12; i++) if(strcmp(m, mon[i]) == 0) break; if(i == 12) return 0; return i+1; } char * datefmt(ulong t) { static char buf[48]; Tm *tm; if(nflag){ snprint(buf,sizeof buf, "%lud", t); return buf; } tm = localtime(t); snprint(buf,sizeof buf,"%04d/%02d/%02d %02d:%02d:%02d", tm->year + 1900,tm->mon + 1,tm->mday, tm->hour, tm->min, tm->sec); return buf; } /* * note: atoi("08") returns 0 * therefore we should have a2i() */ int a2i(char *s) { while(*s == '0') s++; return atoi(s); } /* d2n convert: * "2005/02/08 14:31:49" to 1107840709 * "2005/02/08 14:31" to 1107840660 * "2005/02/08" to 1107788400 * "1107840709" to 1107840709 */ long d2n(char *s) { Tm tm; char *args[2], *d[3], *t[3]; int na,nd,nt; na = getfields(s,args,2,1," "); if(na == 0) usage(); nd = getfields(args[0],d,3,1,"/"); if(nd == 1) return atol(args[0]); if(nd != 3) usage(); tm.year = a2i(d[0]) - 1900; tm.mon = a2i(d[1]) - 1; tm.mday = a2i(d[2]); tm.hour = tm.min = tm.sec = 0; nt = getfields(args[1],t,3,1,":"); if(nt == 1) usage(); if(nt > 1){ tm.hour = a2i(t[0]); tm.min = a2i(t[1]); } if(nt ==3) tm.sec = a2i(t[2]); strcpy(tm.zone,zone); /* manual says: * Tm2sec converts a broken-down time to seconds since the * start of the epoch. It ignores wday, and assumes the local * time zone if zone is not GMT. * However * tm.zone[0] = 0 * does not work for local time zone. * it seems tm.zone must be explicitly given */ return tm2sec(&tm); } void pndate(char **argv, int argc) { Tm *tm; int m,n,d; char *mday,*other; char buf[32]; if(argc == 0) usage(); if(smatch(argv[0],"0000000000") == 10){ if(nflag) print("%s\n", argv[0]); else print("%s\n",datefmt(atol(argv[0]))); return; } if(smatch(argv[0],"0000/00/00") == 10){ if(argc == 1) snprint(buf, sizeof buf,"%s 00:00:00", argv[0]); else if(argc == 2){ n = smatch(argv[1],"00:00:00"); if(n == 2) snprint(buf, sizeof buf,"%s %s:00:00", argv[0],argv[1]); else if(n == 5) snprint(buf, sizeof buf,"%s %s:00", argv[0],argv[1]); else if(n == 8) snprint(buf, sizeof buf,"%s %s", argv[0],argv[1]); else usage(); } } else{ /* Hera we treat the types: * Nov 8 08:25 -> 2004/10/08 08:25:00 # 180 days past * Jul 19 2002 -> 2002/07/19 00:00:00 */ now = time(0); tm = localtime(now); m = mon2int(argv[0]); if(m == 0 || argc != 3) usage(); if((smatch(argv[1],"0") != 1) && (smatch(argv[1],"00") != 2)) usage(); mday = argv[1]; d = atoi(mday); other = argv[2]; if(smatch(other,"0000") == 4) snprint(buf, sizeof buf,"%s/%02d/%02d 00:00:00", other, m, d); else if(smatch(other,"00:00") == 5){ if(d2n(buf) > now + 30L*24*60*60) snprint(buf, sizeof buf, "%d/%02d/%02d %s:00", tm->year + 1899, m, d, other); else snprint(buf, sizeof buf, "%d/%02d/%02d %s:00", tm->year + 1900, m, d, other); } else usage(); } if(nflag) print("%ld\n", d2n(buf)); else print("%s\n", buf); } char * skipfields(char *s, int n) { int i; for(i=0; i < n; i++){ while(*s == ' ' || *s == '\t') s++; while(*s && *s != ' ' && *s != '\t') s++; } return s; } void pline(char *s, int *keys, long nkeys) { int i,k,n; char *t,c; c = 0; for(n = 0, i = 0; i < nkeys;i++){ k = keys[i]; if(k < n) continue; if( k > n){ t = skipfields(s, k - n); c = *t; *t = 0; if(c == 0){ Bprint(&out, "%s\n", s); break; } else{ Bprint(&out, "%s%c", s,c); *t = c; s = ++t; } } t = skipfields(s,1); c = *t; *t = 0; if(c == 0){ Bprint(&out, "%s\n", datefmt(atoul(s))); break; } else{ Bprint(&out, "%s%c", datefmt(atoul(s)),c); *t = c; s = ++t; n = k + 1; } } if(c != 0) Bprint(&out, "%s\n",s); } int compar(int *x, int *y) { //print("%d %d\n", *x, *y); if(*x > *y) return 1; if(*x < *y) return -1; return 0; } void main(int argc, char *argv[]) { char *key=nil; char *s,c,*file; int fd,k,n; long nkeys; int keys[MFIELD]; ARGBEGIN{ case 'k': key=ARGF(); if(key==nil) usage(); break; case 'n': nflag = 1; break; default: usage(); }ARGEND zone=getenv("timezone"); if(zone == nil) sysfatal("# getenv: %r"); strdup(zone); zone[3] = 0; if(key==nil){ if(*argv == nil) print("%s\n", datefmt(time(0))); else pndate(argv, argc); exits(nil); } for(n = 0;;){ for(s = key; *s && *s != ','; s++); c = *s; if(*s == ',') *s = 0; k=atoi(key); if(n == MFIELD) sysfatal("# error: keys exceed limit %d", MFIELD); keys[n++] = k; if(c == 0) break; key = ++s; } nkeys = n; qsort(keys, nkeys, sizeof keys[0], (int (*)(void*, void*))compar); file = *argv++; if(file && *argv != nil) usage(); fd = 0; if(file){ fd = open(file, OREAD); if(fd < 0) sysfatal("# cannot open %s: %r\n", *argv); } Binit(&in, fd, OREAD); Binit(&out, 1, OWRITE); while((s = gline())) pline(s,keys,nkeys); }