diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2020-06-15 00:12:57 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2020-06-15 00:12:57 +0200 |
commit | febe84af755d8b6941c6e59c1b350f889c4fccb0 (patch) | |
tree | 45cb13daa2c1ef116613a7e461e0c59fda1d5bd6 /sys/src/libc/9sys/tm2sec.c | |
parent | 8b3efcfc4e3b38eab3f0ff503e573c072ff890f5 (diff) |
libc: revert date change again. this is getting ridicuoulus.
this breaks the sample from the seconds manpage, and overall
produces funky results. this needs alot more testing.
term% seconds '23 may 2011'
seconds: tmparse: invalid date 23 may 2011 near 'may 2011'
term% seconds '2019-01-01 00:00:00'
-118370073600
Diffstat (limited to 'sys/src/libc/9sys/tm2sec.c')
-rw-r--r-- | sys/src/libc/9sys/tm2sec.c | 197 |
1 files changed, 195 insertions, 2 deletions
diff --git a/sys/src/libc/9sys/tm2sec.c b/sys/src/libc/9sys/tm2sec.c index 96d4c3d61..20bebd0c8 100644 --- a/sys/src/libc/9sys/tm2sec.c +++ b/sys/src/libc/9sys/tm2sec.c @@ -1,9 +1,202 @@ #include <u.h> #include <libc.h> +#define TZSIZE 150 +static void readtimezone(void); +static int rd_name(char**, char*); +static int rd_long(char**, long*); +static +struct +{ + char stname[4]; + char dlname[4]; + long stdiff; + long dldiff; + long dlpairs[TZSIZE]; +} timezone; + +#define SEC2MIN 60L +#define SEC2HOUR (60L*SEC2MIN) +#define SEC2DAY (24L*SEC2HOUR) + +/* + * days per month plus days/year + */ +static int dmsize[] = +{ + 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; +static int ldmsize[] = +{ + 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +/* + * return the days/month for the given year + */ +static int * +yrsize(int y) +{ + if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0)) + return ldmsize; + else + return dmsize; +} + +/* + * compute seconds since Jan 1 1970 GMT + * and convert to our timezone. + */ long tm2sec(Tm *tm) { - tmnorm(tm); - return tm->abs; + long secs, *p; + int i, yday, year, *d2m; + + if(strcmp(tm->zone, "GMT") != 0 && timezone.stname[0] == 0) + readtimezone(); + secs = 0; + + /* + * seconds per year + */ + year = tm->year + 1900; + for(i = 1970; i < year; i++){ + d2m = yrsize(i); + secs += d2m[0] * SEC2DAY; + } + + /* + * if mday is set, use mon and mday to compute yday + */ + if(tm->mday){ + yday = 0; + d2m = yrsize(year); + for(i=0; i<tm->mon; i++) + yday += d2m[i+1]; + yday += tm->mday-1; + }else{ + yday = tm->yday; + } + secs += yday * SEC2DAY; + + /* + * hours, minutes, seconds + */ + secs += tm->hour * SEC2HOUR; + secs += tm->min * SEC2MIN; + secs += tm->sec; + + /* + * Only handles zones mentioned in /env/timezone, + * but things get too ambiguous otherwise. + */ + if(strcmp(tm->zone, timezone.stname) == 0) + secs -= timezone.stdiff; + else if(strcmp(tm->zone, timezone.dlname) == 0) + secs -= timezone.dldiff; + else if(tm->zone[0] == 0){ + secs -= timezone.dldiff; + for(p = timezone.dlpairs; *p; p += 2) + if(secs >= p[0] && secs < p[1]) + break; + if(*p == 0){ + secs += timezone.dldiff; + secs -= timezone.stdiff; + } + } + return secs; +} + +static +void +readtimezone(void) +{ + char buf[TZSIZE*11+30], *p; + int i; + + memset(buf, 0, sizeof(buf)); + i = open("/env/timezone", 0); + if(i < 0) + goto error; + if(read(i, buf, sizeof(buf)) >= sizeof(buf)) + goto error; + close(i); + p = buf; + if(rd_name(&p, timezone.stname)) + goto error; + if(rd_long(&p, &timezone.stdiff)) + goto error; + if(rd_name(&p, timezone.dlname)) + goto error; + if(rd_long(&p, &timezone.dldiff)) + goto error; + for(i=0; i<TZSIZE; i++) { + if(rd_long(&p, &timezone.dlpairs[i])) + goto error; + if(timezone.dlpairs[i] == 0) + return; + } + +error: + timezone.stdiff = 0; + strcpy(timezone.stname, "GMT"); + timezone.dlpairs[0] = 0; +} + +static int +rd_name(char **f, char *p) +{ + int c, i; + + for(;;) { + c = *(*f)++; + if(c != ' ' && c != '\n') + break; + } + for(i=0; i<3; i++) { + if(c == ' ' || c == '\n') + return 1; + *p++ = c; + c = *(*f)++; + } + if(c != ' ' && c != '\n') + return 1; + *p = 0; + return 0; +} + +static int +rd_long(char **f, long *p) +{ + int c, s; + long l; + + s = 0; + for(;;) { + c = *(*f)++; + if(c == '-') { + s++; + continue; + } + if(c != ' ' && c != '\n') + break; + } + if(c == 0) { + *p = 0; + return 0; + } + l = 0; + for(;;) { + if(c == ' ' || c == '\n') + break; + if(c < '0' || c > '9') + return 1; + l = l*10 + c-'0'; + c = *(*f)++; + } + if(s) + l = -l; + *p = l; + return 0; } |