mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-24 11:41:58 +00:00
lib9: rewrite date routines to use /usr/share/zoneinfo directly
This commit is contained in:
parent
1cccddd6b3
commit
f35a04866f
7 changed files with 499 additions and 124 deletions
159
src/lib9/ctime.c
159
src/lib9/ctime.c
|
@ -1,21 +1,135 @@
|
|||
/*
|
||||
* This routine converts time as follows.
|
||||
* The epoch is 0000 Jan 1 1970 GMT.
|
||||
* The argument time is in seconds since then.
|
||||
* The localtime(t) entry returns a pointer to an array
|
||||
* containing
|
||||
*
|
||||
* seconds (0-59)
|
||||
* minutes (0-59)
|
||||
* hours (0-23)
|
||||
* day of month (1-31)
|
||||
* month (0-11)
|
||||
* year-1970
|
||||
* weekday (0-6, Sun is 0)
|
||||
* day of the year
|
||||
* daylight savings flag
|
||||
*
|
||||
* The routine gets the daylight savings time from the environment.
|
||||
*
|
||||
* asctime(tvec))
|
||||
* where tvec is produced by localtime
|
||||
* returns a ptr to a character string
|
||||
* that has the ascii time in the form
|
||||
*
|
||||
* \\
|
||||
* Thu Jan 01 00:00:00 GMT 1970n0
|
||||
* 012345678901234567890123456789
|
||||
* 0 1 2
|
||||
*
|
||||
* ctime(t) just calls localtime, then asctime.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
static
|
||||
void
|
||||
ct_numb(char *cp, int n)
|
||||
{
|
||||
#include "zoneinfo.h"
|
||||
|
||||
cp[0] = ' ';
|
||||
if(n >= 10)
|
||||
cp[0] = (n/10)%10 + '0';
|
||||
cp[1] = n%10 + '0';
|
||||
static char dmsize[12] =
|
||||
{
|
||||
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||||
};
|
||||
|
||||
#define dysize ctimedysize
|
||||
static int dysize(int);
|
||||
static void ct_numb(char*, int);
|
||||
|
||||
char*
|
||||
ctime(long t)
|
||||
{
|
||||
return asctime(localtime(t));
|
||||
}
|
||||
|
||||
Tm*
|
||||
localtime(long tim)
|
||||
{
|
||||
Tinfo ti;
|
||||
Tm *ct;
|
||||
|
||||
if (zonelookuptinfo(&ti, tim)!=-1) {
|
||||
ct = gmtime(tim+ti.tzoff);
|
||||
strncpy(ct->zone, ti.zone, sizeof ct->zone);
|
||||
ct->zone[sizeof ct->zone-1] = 0;
|
||||
ct->tzoff = ti.tzoff;
|
||||
return ct;
|
||||
}
|
||||
return gmtime(tim);
|
||||
}
|
||||
|
||||
Tm*
|
||||
gmtime(long tim)
|
||||
{
|
||||
int d0, d1;
|
||||
long hms, day;
|
||||
static Tm xtime;
|
||||
|
||||
/*
|
||||
* break initial number into days
|
||||
*/
|
||||
hms = tim % 86400L;
|
||||
day = tim / 86400L;
|
||||
if(hms < 0) {
|
||||
hms += 86400L;
|
||||
day -= 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* generate hours:minutes:seconds
|
||||
*/
|
||||
xtime.sec = hms % 60;
|
||||
d1 = hms / 60;
|
||||
xtime.min = d1 % 60;
|
||||
d1 /= 60;
|
||||
xtime.hour = d1;
|
||||
|
||||
/*
|
||||
* day is the day number.
|
||||
* generate day of the week.
|
||||
* The addend is 4 mod 7 (1/1/1970 was Thursday)
|
||||
*/
|
||||
|
||||
xtime.wday = (day + 7340036L) % 7;
|
||||
|
||||
/*
|
||||
* year number
|
||||
*/
|
||||
if(day >= 0)
|
||||
for(d1 = 1970; day >= dysize(d1); d1++)
|
||||
day -= dysize(d1);
|
||||
else
|
||||
for (d1 = 1970; day < 0; d1--)
|
||||
day += dysize(d1-1);
|
||||
xtime.year = d1-1900;
|
||||
xtime.yday = d0 = day;
|
||||
|
||||
/*
|
||||
* generate month
|
||||
*/
|
||||
|
||||
if(dysize(d1) == 366)
|
||||
dmsize[1] = 29;
|
||||
for(d1 = 0; d0 >= dmsize[d1]; d1++)
|
||||
d0 -= dmsize[d1];
|
||||
dmsize[1] = 28;
|
||||
xtime.mday = d0 + 1;
|
||||
xtime.mon = d1;
|
||||
strcpy(xtime.zone, "GMT");
|
||||
return &xtime;
|
||||
}
|
||||
|
||||
char*
|
||||
asctime(Tm *t)
|
||||
{
|
||||
int i;
|
||||
char *ncp;
|
||||
static char cbuf[30];
|
||||
|
||||
|
@ -33,12 +147,6 @@ asctime(Tm *t)
|
|||
ct_numb(cbuf+14, t->min+100);
|
||||
ct_numb(cbuf+17, t->sec+100);
|
||||
ncp = t->zone;
|
||||
for(i=0; i<3; i++)
|
||||
if(ncp[i] == 0)
|
||||
break;
|
||||
for(; i<3; i++)
|
||||
ncp[i] = '?';
|
||||
ncp = t->zone;
|
||||
cbuf[20] = *ncp++;
|
||||
cbuf[21] = *ncp++;
|
||||
cbuf[22] = *ncp;
|
||||
|
@ -50,9 +158,24 @@ asctime(Tm *t)
|
|||
return cbuf;
|
||||
}
|
||||
|
||||
char*
|
||||
ctime(long t)
|
||||
static
|
||||
int
|
||||
dysize(int y)
|
||||
{
|
||||
return asctime(localtime(t));
|
||||
|
||||
if(y%4 == 0 && (y%100 != 0 || y%400 == 0))
|
||||
return 366;
|
||||
return 365;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
ct_numb(char *cp, int n)
|
||||
{
|
||||
|
||||
cp[0] = ' ';
|
||||
if(n >= 10)
|
||||
cp[0] = (n/10)%10 + '0';
|
||||
cp[1] = n%10 + '0';
|
||||
}
|
||||
|
||||
|
|
100
src/lib9/date.c
100
src/lib9/date.c
|
@ -1,100 +0,0 @@
|
|||
#define NOPLAN9DEFINES
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <stdlib.h> /* setenv etc. */
|
||||
#include <time.h>
|
||||
|
||||
static int
|
||||
dotz(time_t t, char *tzone)
|
||||
{
|
||||
struct tm *gtm;
|
||||
struct tm tm;
|
||||
|
||||
strftime(tzone, 32, "%Z", localtime(&t));
|
||||
tm = *localtime(&t); /* set local time zone field */
|
||||
gtm = gmtime(&t);
|
||||
tm.tm_sec = gtm->tm_sec;
|
||||
tm.tm_min = gtm->tm_min;
|
||||
tm.tm_hour = gtm->tm_hour;
|
||||
tm.tm_mday = gtm->tm_mday;
|
||||
tm.tm_mon = gtm->tm_mon;
|
||||
tm.tm_year = gtm->tm_year;
|
||||
tm.tm_wday = gtm->tm_wday;
|
||||
return t - mktime(&tm);
|
||||
}
|
||||
|
||||
static void
|
||||
tm2Tm(struct tm *tm, Tm *bigtm, int tzoff, char *zone)
|
||||
{
|
||||
memset(bigtm, 0, sizeof *bigtm);
|
||||
bigtm->sec = tm->tm_sec;
|
||||
bigtm->min = tm->tm_min;
|
||||
bigtm->hour = tm->tm_hour;
|
||||
bigtm->mday = tm->tm_mday;
|
||||
bigtm->mon = tm->tm_mon;
|
||||
bigtm->year = tm->tm_year;
|
||||
bigtm->wday = tm->tm_wday;
|
||||
bigtm->tzoff = tzoff;
|
||||
strncpy(bigtm->zone, zone, 3);
|
||||
bigtm->zone[3] = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
Tm2tm(Tm *bigtm, struct tm *tm)
|
||||
{
|
||||
/* initialize with current time to get local time zone! (tm_isdst) */
|
||||
time_t t;
|
||||
time(&t);
|
||||
*tm = *localtime(&t);
|
||||
|
||||
tm->tm_sec = bigtm->sec;
|
||||
tm->tm_min = bigtm->min;
|
||||
tm->tm_hour = bigtm->hour;
|
||||
tm->tm_mday = bigtm->mday;
|
||||
tm->tm_mon = bigtm->mon;
|
||||
tm->tm_year = bigtm->year;
|
||||
tm->tm_wday = bigtm->wday;
|
||||
}
|
||||
|
||||
Tm*
|
||||
p9gmtime(long x)
|
||||
{
|
||||
time_t t;
|
||||
struct tm tm;
|
||||
static Tm bigtm;
|
||||
|
||||
t = (time_t)x;
|
||||
tm = *gmtime(&t);
|
||||
tm2Tm(&tm, &bigtm, 0, "GMT");
|
||||
return &bigtm;
|
||||
}
|
||||
|
||||
Tm*
|
||||
p9localtime(long x)
|
||||
{
|
||||
time_t t;
|
||||
struct tm tm;
|
||||
static Tm bigtm;
|
||||
char tzone[32];
|
||||
|
||||
t = (time_t)x;
|
||||
tm = *localtime(&t);
|
||||
tm2Tm(&tm, &bigtm, dotz(t, tzone), tzone);
|
||||
return &bigtm;
|
||||
}
|
||||
|
||||
long
|
||||
p9tm2sec(Tm *bigtm)
|
||||
{
|
||||
time_t t;
|
||||
struct tm tm;
|
||||
char tzone[32];
|
||||
|
||||
Tm2tm(bigtm, &tm);
|
||||
t = mktime(&tm);
|
||||
if(strcmp(bigtm->zone, "GMT") == 0 || strcmp(bigtm->zone, "UCT") == 0){
|
||||
t += dotz(t, tzone);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
|
@ -88,7 +88,6 @@ LIB9OFILES=\
|
|||
create.$O\
|
||||
crypt.$O\
|
||||
ctime.$O\
|
||||
date.$O\
|
||||
dial.$O\
|
||||
dirfstat.$O\
|
||||
dirfwstat.$O\
|
||||
|
@ -149,6 +148,7 @@ LIB9OFILES=\
|
|||
syslog.$O\
|
||||
sysname.$O\
|
||||
time.$O\
|
||||
tm2sec.$O\
|
||||
tokenize.$O\
|
||||
truerand.$O\
|
||||
u16.$O\
|
||||
|
@ -158,6 +158,7 @@ LIB9OFILES=\
|
|||
wait.$O\
|
||||
waitpid.$O\
|
||||
write.$O\
|
||||
zoneinfo.$O\
|
||||
|
||||
OFILES=\
|
||||
$LIB9OFILES\
|
||||
|
@ -193,3 +194,4 @@ testgoogfmt: testfltfmt.$O googfmt.$O $XLIB
|
|||
testgoogprint: testprint.$O googfmt.$O $XLIB
|
||||
$LD -o $target testprint.$O googfmt.$O
|
||||
|
||||
ctime.$O tm2sec.$O zoneinfo.$O: zoneinfo.h
|
||||
|
|
|
@ -2,14 +2,20 @@
|
|||
#include <libc.h>
|
||||
|
||||
int
|
||||
opentemp(char *template)
|
||||
opentemp(char *template, int mode)
|
||||
{
|
||||
int fd;
|
||||
int fd, fd1;
|
||||
|
||||
fd = mkstemp(template);
|
||||
if(fd < 0)
|
||||
return -1;
|
||||
remove(template);
|
||||
return fd;
|
||||
/* reopen for mode */
|
||||
fd1 = open(template, mode);
|
||||
if(fd1 < 0){
|
||||
close(fd);
|
||||
remove(template);
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
return fd1;
|
||||
}
|
||||
|
||||
|
|
110
src/lib9/tm2sec.c
Normal file
110
src/lib9/tm2sec.c
Normal file
|
@ -0,0 +1,110 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
#include "zoneinfo.h"
|
||||
|
||||
#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)
|
||||
{
|
||||
Tinfo ti0, ti1, *ti;
|
||||
long secs;
|
||||
int i, yday, year, *d2m;
|
||||
|
||||
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;
|
||||
|
||||
/*
|
||||
* Assume the local time zone if zone is not GMT
|
||||
*/
|
||||
if(strcmp(tm->zone, "GMT") != 0) {
|
||||
i = zonelookuptinfo(&ti0, secs);
|
||||
ti = &ti0;
|
||||
if (i != -1)
|
||||
if (ti->tzoff!=0) {
|
||||
/*
|
||||
* to what local time period `secs' belongs?
|
||||
*/
|
||||
if (ti->tzoff>0) {
|
||||
/*
|
||||
* east of GMT; check previous local time transition
|
||||
*/
|
||||
if (ti->t+ti->tzoff > secs)
|
||||
if (zonetinfo(&ti1, i-1)!=-1)
|
||||
ti = &ti1;
|
||||
} else
|
||||
/*
|
||||
* west of GMT; check next local time transition
|
||||
*/
|
||||
if (zonetinfo(&ti1, i+1))
|
||||
if (ti1.t+ti->tzoff < secs)
|
||||
ti = &ti1;
|
||||
// fprint(2, "tt: %ld+%d %ld\n", (long)ti->t, ti->tzoff, (long)secs);
|
||||
secs -= ti->tzoff;
|
||||
}
|
||||
}
|
||||
|
||||
if(secs < 0)
|
||||
secs = 0;
|
||||
return secs;
|
||||
}
|
215
src/lib9/zoneinfo.c
Normal file
215
src/lib9/zoneinfo.c
Normal file
|
@ -0,0 +1,215 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
/*
|
||||
* Access local time entries of zoneinfo files.
|
||||
* Formats 0 and 2 are supported, and 4-byte timestamps
|
||||
*
|
||||
* Copyright © 2008 M. Teichgräber
|
||||
* Contributed under the terms of the Lucent Public License 1.02.
|
||||
*/
|
||||
#include "zoneinfo.h"
|
||||
|
||||
static
|
||||
struct Zoneinfo
|
||||
{
|
||||
int timecnt; /* # of transition times */
|
||||
int typecnt; /* # of local time types */
|
||||
int charcnt; /* # of characters of time zone abbreviation strings */
|
||||
|
||||
uchar *ptime;
|
||||
uchar *ptype;
|
||||
uchar *ptt;
|
||||
uchar *pzone;
|
||||
} z;
|
||||
|
||||
static uchar *tzdata;
|
||||
|
||||
static
|
||||
uchar*
|
||||
readtzfile(char *file)
|
||||
{
|
||||
uchar *p;
|
||||
int fd;
|
||||
Dir *d;
|
||||
|
||||
fd = open(file, OREAD);
|
||||
if (fd<0)
|
||||
return nil;
|
||||
d = dirfstat(fd);
|
||||
if (d==nil)
|
||||
return nil;
|
||||
p = malloc(d->length);
|
||||
if (p!=nil)
|
||||
readn(fd, p, d->length);
|
||||
free(d);
|
||||
close(fd);
|
||||
return p;
|
||||
}
|
||||
static char *zonefile;
|
||||
void
|
||||
tzfile(char *f)
|
||||
{
|
||||
if (tzdata!=nil) {
|
||||
free(tzdata);
|
||||
tzdata = nil;
|
||||
}
|
||||
z.timecnt = 0;
|
||||
zonefile = f;
|
||||
}
|
||||
|
||||
static
|
||||
long
|
||||
get4(uchar *p)
|
||||
{
|
||||
return (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
|
||||
}
|
||||
|
||||
enum {
|
||||
TTinfosz = 4+1+1,
|
||||
};
|
||||
|
||||
static
|
||||
int
|
||||
parsehead(void)
|
||||
{
|
||||
uchar *p;
|
||||
int ver;
|
||||
|
||||
ver = tzdata[4];
|
||||
if (ver!=0)
|
||||
if (ver!='2')
|
||||
return -1;
|
||||
|
||||
p = tzdata + 4 + 1 + 15;
|
||||
|
||||
z.timecnt = get4(p+3*4);
|
||||
z.typecnt = get4(p+4*4);
|
||||
if (z.typecnt==0)
|
||||
return -1;
|
||||
z.charcnt = get4(p+5*4);
|
||||
z.ptime = p+6*4;
|
||||
z.ptype = z.ptime + z.timecnt*4;
|
||||
z.ptt = z.ptype + z.timecnt;
|
||||
z.pzone = z.ptt + z.typecnt*TTinfosz;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
ttinfo(Tinfo *ti, int tti)
|
||||
{
|
||||
uchar *p;
|
||||
int i;
|
||||
|
||||
i = z.ptype[tti];
|
||||
assert(i<z.typecnt);
|
||||
p = z.ptt + i*TTinfosz;
|
||||
ti->tzoff = get4(p);
|
||||
ti->dlflag = p[4];
|
||||
assert(p[5]<z.charcnt);
|
||||
ti->zone = (char*)z.pzone + p[5];
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
readtimezone(void)
|
||||
{
|
||||
char *tmp;
|
||||
|
||||
z.timecnt = 0;
|
||||
switch (zonefile==nil) {
|
||||
default:
|
||||
if ((tmp=getenv("timezone"))!=nil) {
|
||||
tzdata = readtzfile(tmp);
|
||||
free(tmp);
|
||||
break;
|
||||
}
|
||||
zonefile = "/etc/localtime";
|
||||
/* fall through */
|
||||
case 0:
|
||||
tzdata = readtzfile(zonefile);
|
||||
}
|
||||
if (tzdata==nil)
|
||||
return;
|
||||
|
||||
if (strncmp("TZif", (char*)tzdata, 4)!=0)
|
||||
goto errfree;
|
||||
|
||||
if (parsehead()==-1) {
|
||||
errfree:
|
||||
free(tzdata);
|
||||
tzdata = nil;
|
||||
z.timecnt = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
tlong
|
||||
gett4(uchar *p)
|
||||
{
|
||||
long l;
|
||||
|
||||
l = get4(p);
|
||||
if (l<0)
|
||||
return 0;
|
||||
return l;
|
||||
}
|
||||
int
|
||||
zonetinfo(Tinfo *ti, int i)
|
||||
{
|
||||
if (tzdata==nil)
|
||||
readtimezone();
|
||||
if (i<0 || i>=z.timecnt)
|
||||
return -1;
|
||||
ti->t = gett4(z.ptime + 4*i);
|
||||
ttinfo(ti, i);
|
||||
return i;
|
||||
}
|
||||
|
||||
int
|
||||
zonelookuptinfo(Tinfo *ti, tlong t)
|
||||
{
|
||||
uchar *p;
|
||||
int i;
|
||||
tlong oldtt, tt;
|
||||
|
||||
if (tzdata==nil)
|
||||
readtimezone();
|
||||
oldtt = 0;
|
||||
p = z.ptime;
|
||||
for (i=0; i<z.timecnt; i++) {
|
||||
tt = gett4(p);
|
||||
if (t<tt)
|
||||
break;
|
||||
oldtt = tt;
|
||||
p += 4;
|
||||
}
|
||||
if (i>0) {
|
||||
ttinfo(ti, i-1);
|
||||
ti->t = oldtt;
|
||||
// fprint(2, "t:%ld off:%d dflag:%d %s\n", (long)ti->t, ti->tzoff, ti->dlflag, ti->zone);
|
||||
return i-1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
zonedump(int fd)
|
||||
{
|
||||
int i;
|
||||
uchar *p;
|
||||
tlong t;
|
||||
Tinfo ti;
|
||||
|
||||
if (tzdata==nil)
|
||||
readtimezone();
|
||||
p = z.ptime;
|
||||
for (i=0; i<z.timecnt; i++) {
|
||||
t = gett4(p);
|
||||
ttinfo(&ti, i);
|
||||
fprint(fd, "%ld\t%d\t%d\t%s\n", (long)t, ti.tzoff, ti.dlflag, ti.zone);
|
||||
p += 4;
|
||||
}
|
||||
}
|
19
src/lib9/zoneinfo.h
Normal file
19
src/lib9/zoneinfo.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#define zonetinfo _p9zonetinfo
|
||||
#define zonedump _p9zonedump
|
||||
#define zonelookuptinfo _p9zonelookuptinfo
|
||||
|
||||
typedef long tlong;
|
||||
|
||||
typedef
|
||||
struct Tinfo
|
||||
{
|
||||
long t;
|
||||
int tzoff;
|
||||
int dlflag;
|
||||
char *zone;
|
||||
} Tinfo;
|
||||
|
||||
extern int zonelookuptinfo(Tinfo*, tlong);
|
||||
extern int zonetinfo(Tinfo*, int);
|
||||
extern void zonedump(int fd);
|
||||
|
Loading…
Reference in a new issue