shithub: riscv

Download patch

ref: d9f9e10e7b3ad61342ec1d9b034dd17f8452ccbc
parent: 9afa5550f7497f84fb157ba07ff94301dbe06bcc
author: Ori Bernstein <[email protected]>
date: Sat Sep 26 07:20:42 EDT 2020

upas: convert to tmdate, change timezone format

Complete the conversion of upas to remove ctime,
use the new date library, and print time zones
in +hhmm format, instead of NNN format.

This may affect code that expects specific names
for timezones. Fix that code.

--- a/sys/src/cmd/upas/Mail/mail.c
+++ b/sys/src/cmd/upas/Mail/mail.c
@@ -82,6 +82,7 @@
 
 	doquote = needsrcquote;
 	quotefmtinstall();
+	tmfmtinstall();
 
 	/* open these early so we won't miss notification of new mail messages while we read mbox */
 	plumbsendfd = plumbopen("send", OWRITE|OCEXEC);
--- a/sys/src/cmd/upas/Mail/mesg.c
+++ b/sys/src/cmd/upas/Mail/mesg.c
@@ -224,14 +224,13 @@
 int
 thisyear(char *year)
 {
-	static char now[10];
-	char *s;
+	Tzone *tz;
+	Tm tm;
 
-	if(now[0] == '\0'){
-		s = ctime(time(nil));
-		strcpy(now, s+24);
-	}
-	return strncmp(year, now, 4) == 0;
+	/* ignore errors: screwed means utc */
+	tz = tzload("local");
+	tmnow(&tm, tz);
+	return atoi(year) == (tm.year + 1900);
 }
 
 char*
--- a/sys/src/cmd/upas/Mail/reply.c
+++ b/sys/src/cmd/upas/Mail/reply.c
@@ -388,7 +388,9 @@
 	Channel *sync;
 	Message *r;
 	int first, nfld, delit, ofd;
-	char *copy, *fld[100], *now;
+	char *copy, *fld[100];
+	Tzone *tz;
+	Tm now;
 
 	body = winreadbody(m->w, &n);
 	/* assemble to: list from first line, to: line, and cc: line */
@@ -467,11 +469,12 @@
 
 	ofd = open(outgoing, OWRITE|OCEXEC);	/* no error check necessary */
 	if(ofd >= 0){
-		/* From dhog Fri Aug 24 22:13:00 EDT 2001 */
-		now = ctime(time(0));
-		fprint(ofd, "From %s %s", user, now);
+		/* From dhog Fri Aug 24 22:13:00 +0500 2001 */
+		tz = tzload("local");
+		tmnow(&now, tz);
+		fprint(ofd, "From %s %τ", user, tmfmt(&now, "WW MMM _D hh:mm:ss Z YYYY"));
 		fprint(ofd, "From: %s\n", user);
-		fprint(ofd, "Date: %s", now);
+		fprint(ofd, "Date: %τ", tmfmt(&now, "WW MMM _D hh:mm:ss Z YYYY"));
 		for(i=0; i<natt; i++)
 			if(included[i])
 				fprint(ofd, "Include: %s\n", attlist[i]);
--- a/sys/src/cmd/upas/common/common.h
+++ b/sys/src/cmd/upas/common/common.h
@@ -20,6 +20,7 @@
 	Fstored		= 1<<6, /* S */
 	Nflags		= 7,
 };
+#define Timefmt "WW MMM _D hh:mm:ss ?Z YYYY"
 
 /*
  * flag.c
--- a/sys/src/cmd/upas/common/folder.c
+++ b/sys/src/cmd/upas/common/folder.c
@@ -1,7 +1,5 @@
 #include "common.h"
 
-#define Ctimefmt "WW MMM _D hh:mm:ss ?Z YYYY"
-
 enum{
 	Mbox	= 1,
 	Mdir,
@@ -186,10 +184,11 @@
 int
 appendfolder(Biobuf *b, char *addr, int fd)
 {
-	char *s, *t;
-	int r;
+	char *s;
+	int r, n;
 	Biobuf bin;
 	Folder *f;
+	Tzone *tz;
 	Tm tm;
 
 	f = getfolder(b);
@@ -196,12 +195,13 @@
 	Bseek(f->out, 0, 2);
 	Binit(&bin, fd, OREAD);
 	s = Brdstr(&bin, '\n', 0);
-	if(s == nil || strncmp(s, "From ", 5) != 0)
-		Bprint(f->out, "From %s %.28s\n", addr, ctime(f->t));
-	else if(strncmp(s, "From ", 5) == 0 
-		&& (t = strchr(s + 5, ' ')) != nil
-		&& tmparse(&tm, Ctimefmt, t + 1, nil, nil) != nil)
-		f->t = tm2sec(&tm);
+	n = strlen(s);
+	if(!s || strncmp(s, "From ", 5) != 0){
+		tz = tzload("local");
+		tmtime(&tm, f->t, tz);
+		Bprint(f->out, "From %s %τ\n", addr, tmfmt(&tm, Timefmt));
+	}else if(n > 5 && tmparse(&tm, Timefmt, s + 5, nil, nil) != nil)
+		f->t = tmnorm(&tm);
 	if(s)
 		Bwrite(f->out, s, strlen(s));
 	free(s);
--- a/sys/src/cmd/upas/common/libsys.c
+++ b/sys/src/cmd/upas/common/libsys.c
@@ -5,14 +5,15 @@
 /*
  *  return the date
  */
-char*
-thedate(void)
+Tmfmt
+thedate(Tm *tm)
 {
-	static char now[64];
+	Tzone *tz;
 
-	strcpy(now, ctime(time(0)));
-	now[28] = 0;
-	return now;
+	/* if the local time is screwed, just do gmt */
+	tz = tzload("local");
+	tmnow(tm, tz);
+	return tmfmt(tm, Timefmt);
 }
 
 /*
--- a/sys/src/cmd/upas/common/sys.h
+++ b/sys/src/cmd/upas/common/sys.h
@@ -35,7 +35,7 @@
 char	*domainname_read(void);
 char	**sysnames_read(void);
 char	*getlog(void);
-char	*thedate(void);
+Tmfmt	thedate(Tm*);
 Biobuf	*sysopen(char*, char*, ulong);
 int	sysopentty(void);
 int	sysclose(Biobuf*);
--- a/sys/src/cmd/upas/filterkit/deliver.c
+++ b/sys/src/cmd/upas/filterkit/deliver.c
@@ -14,13 +14,15 @@
 void
 main(int argc, char **argv)
 {
-	char *to, *s;
+	char *to;
+	Tmfmt tf;
+	Tm tm;
 	int r;
-	long l;
 	Addr *a;
 
 	ARGBEGIN{
 	}ARGEND;
+	tmfmtinstall();
 	if(argc != 3)
 		usage();
 	if(to = strrchr(argv[0], '!'))
@@ -30,9 +32,9 @@
 	a = readaddrs(argv[1], nil);
 	if(a == nil)
 		sysfatal("missing from address");
-	s = ctime(l = time(0));
+	tf = thedate(&tm);
 	werrstr("");
-	r = fappendfolder(a->val, l, argv[2], 0);
-	syslog(0, "mail", "delivered %s From %s %.28s (%s) %d %r", to, a->val, s, argv[0], r);
+	r = fappendfolder(a->val, tmnorm(&tm), argv[2], 0);
+	syslog(0, "mail", "delivered %s From %s %τ (%s) %d %r", to, a->val, tf, argv[0], r);
 	exits("");
 }
--- a/sys/src/cmd/upas/filterkit/list.c
+++ b/sys/src/cmd/upas/filterkit/list.c
@@ -306,6 +306,7 @@
 	} ARGEND;
 
 	quotefmtinstall();
+	tmfmtinstall();
 
 	if(argc < 3)
 		usage();
--- a/sys/src/cmd/upas/filterkit/mbappend.c
+++ b/sys/src/cmd/upas/filterkit/mbappend.c
@@ -7,15 +7,15 @@
 void
 append(int fd, char *mb, char *from, long t)
 {
-	char *folder, *s;
+	char *folder;
+	Tm tm;
 	int r;
 
-	s = ctime(t);
 	folder = foldername(from, getuser(), mb);
 	r = fappendfolder(0, t, folder, fd);
 	if(r == 0)
 		werrstr("");
-	syslog(0, "mail", "mbappend %s %.28s (%s) %r", mb, s, folder);
+	syslog(0, "mail", "mbappend %s %τ (%s) %r", mb, thedate(&tm), folder);
 	if(r)
 		exits("fail");
 }
@@ -36,6 +36,7 @@
 
 	from = nil;
 	t = time(0);
+	tmfmtinstall();
 	ARGBEGIN{
 	case 't':
 		t = strtoul(EARGF(usage()), 0, 0);
--- a/sys/src/cmd/upas/filterkit/mbcreate.c
+++ b/sys/src/cmd/upas/filterkit/mbcreate.c
@@ -24,6 +24,7 @@
 	}ARGEND
 
 	r = 0;
+	tmfmtinstall();
 	for(; *argv; argv++)
 		r |= f(getuser(), *argv);
 	if(r)
--- a/sys/src/cmd/upas/filterkit/mbremove.c
+++ b/sys/src/cmd/upas/filterkit/mbremove.c
@@ -235,6 +235,7 @@
 	}ARGEND
 
 	r = 0;
+	tmfmtinstall();
 	for(; *argv; argv++)
 		r |= f(getuser(), *argv);
 	if(r)
--- a/sys/src/cmd/upas/filterkit/token.c
+++ b/sys/src/cmd/upas/filterkit/token.c
@@ -62,6 +62,7 @@
 	ARGBEGIN {
 	} ARGEND;
 
+	tmfmtinstall();
 	switch(argc){
 	case 2:
 		exits(check_token(argv[0], argv[1]));
--- a/sys/src/cmd/upas/fs/extra/strtotmtst.c
+++ b/sys/src/cmd/upas/fs/extra/strtotmtst.c
@@ -8,9 +8,10 @@
 	ARGBEGIN{
 	}ARGEND
 
+	tmfmtinstall();
 	for(; *argv; argv++)
 		if(strtotm(*argv, &tm) >= 0)
-			print("%s", asctime(&tm));
+			print("%τ\n", tmfmt(&tm, nil));
 		else
 			print("bad\n");
 	exits("");
--- a/sys/src/cmd/upas/fs/fs.c
+++ b/sys/src/cmd/upas/fs/fs.c
@@ -174,16 +174,15 @@
 static int
 Δfmt(Fmt *f)
 {
-	char buf[32];
 	uvlong v;
+	Tm tm;
 
 	v = va_arg(f->args, uvlong);
 	if(f->flags & FmtSharp)
 		if((v>>8) == 0)
 			return fmtstrcpy(f, "");
-	strcpy(buf, ctime(v>>8));
-	buf[28] = 0;
-	return fmtstrcpy(f, buf);
+	tmtime(&tm, v>>8, tzload("local"));
+	return fmtprint(f, "%τ", tmfmt(&tm, "WW MMM _D hh:mm:ss Z YYYY"));
 }
 
 static int
@@ -320,6 +319,7 @@
 	fmtinstall(L'Δ', Δfmt);
 	fmtinstall('F', fcallfmt);
 	fmtinstall('H', encodefmt);		/* forces tls stuff */
+	tmfmtinstall();
 	quotefmtinstall();
 	if(pipe(p) < 0)
 		error("pipe failed");
--- a/sys/src/cmd/upas/fs/mbox.c
+++ b/sys/src/cmd/upas/fs/mbox.c
@@ -366,11 +366,11 @@
 	if(m->fileid > 1000000ull<<8)
 		return;
 	if(m->unixdate && strtotm(m->unixdate, &tm) >= 0)
-		v = tm2sec(&tm);
+		v = tmnorm(&tm);
 	else if(m->date822 && strtotm(m->date822, &tm) >= 0)
-		v = tm2sec(&tm);
+		v = tmnorm(&tm);
 	else if(rxtotm(m, &tm) >= 0)
-		v = tm2sec(&tm);
+		v = tmnorm(&tm);
 	else{
 		logmsg(gettopmsg(mb, m), "%s:%s: datasec %s %s\n", mb->path,
 			m->whole? m->whole->name: "?",
--- a/sys/src/cmd/upas/fs/plan9.c
+++ b/sys/src/cmd/upas/fs/plan9.c
@@ -34,7 +34,7 @@
 		return -1;
 	if(memtotm(p, n - (p - s), &tm) < 0)
 		return -1;
-	if(tm2sec(&tm) < 1000000)
+	if(tmnorm(&tm) < 1000000)
 		return -1;
 	return 0;
 }
--- a/sys/src/cmd/upas/imap4d/date.c
+++ b/sys/src/cmd/upas/imap4d/date.c
@@ -1,142 +1,10 @@
 #include "imap4d.h"
 
-static char *wdayname[] = {
-	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
-};
-
-static char *monname[] = {
-	"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-};
-
-/*
- * zone	: [A-Za-z][A-Za-z][A-Za-z]	some time zone names
- *	| [A-IK-Z]			military time; rfc1123 says the rfc822 spec is wrong.
- *	| "UT"				universal time
- *	| [+-][0-9][0-9][0-9][0-9]
- * zones is the rfc-822 list of time zone names
- */
-static Namedint zones[] =
-{
-	{"A",	-1 * 3600},
-	{"B",	-2 * 3600},
-	{"C",	-3 * 3600},
-	{"CDT", -5 * 3600},
-	{"CST", -6 * 3600},
-	{"D",	-4 * 3600},
-	{"E",	-5 * 3600},
-	{"EDT", -4 * 3600},
-	{"EST", -5 * 3600},
-	{"F",	-6 * 3600},
-	{"G",	-7 * 3600},
-	{"GMT", 0},
-	{"H",	-8 * 3600},
-	{"I",	-9 * 3600},
-	{"K",	-10 * 3600},
-	{"L",	-11 * 3600},
-	{"M",	-12 * 3600},
-	{"MDT", -6 * 3600},
-	{"MST", -7 * 3600},
-	{"N",	+1 * 3600},
-	{"O",	+2 * 3600},
-	{"P",	+3 * 3600},
-	{"PDT", -7 * 3600},
-	{"PST", -8 * 3600},
-	{"Q",	+4 * 3600},
-	{"R",	+5 * 3600},
-	{"S",	+6 * 3600},
-	{"T",	+7 * 3600},
-	{"U",	+8 * 3600},
-	{"UT",	0},
-	{"V",	+9 * 3600},
-	{"W",	+10 * 3600},
-	{"X",	+11 * 3600},
-	{"Y",	+12 * 3600},
-	{"Z",	0},
-};
-
-static void
-zone2tm(Tm *tm, char *s)
-{
-	int i;
-	Tm aux, *atm;
-
-	if(*s == '+' || *s == '-'){
-		i = strtol(s, &s, 10);
-		tm->tzoff = (i/100)*3600 + i%100;
-		strncpy(tm->zone, "", 4);
-		return;
-	}
-
-	/*
-	 * look it up in the standard rfc822 table
-	 */
-	strncpy(tm->zone, s, 3);
-	tm->zone[3] = 0;
-	tm->tzoff = 0;
-	for(i = 0; i < nelem(zones); i++){
-		if(cistrcmp(zones[i].name, s) == 0){
-			tm->tzoff = zones[i].v;
-			return;
-		}
-	}
-
-	/*
-	 * one last try: look it up in the current local timezone
-	 * probe a couple of times to get daylight/standard time change.
-	 */
-	aux = *tm;
-	memset(aux.zone, 0, 4);
-	aux.hour--;
-	for(i = 0; i < 2; i++){
-		atm = localtime(tm2sec(&aux));
-		if(cistrcmp(tm->zone, atm->zone) == 0){
-			tm->tzoff = atm->tzoff;
-			return;
-		}
-		aux.hour++;
-	}
-
-	strncpy(tm->zone, "GMT", 4);
-	tm->tzoff = 0;
-}
-
-/*
- * hh[:mm[:ss]]
- */
-static void
-time2tm(Tm *tm, char *s)
-{
-	tm->hour = strtoul(s, &s, 10);
-	if(*s++ != ':')
-		return;
-	tm->min = strtoul(s, &s, 10);
-	if(*s++ != ':')
-		return;
-	tm->sec = strtoul(s, &s, 10);
-}
-
-static int
-dateindex(char *d, char **tab, int n)
-{
-	int i;
-
-	for(i = 0; i < n; i++)
-		if(cistrcmp(d, tab[i]) == 0)
-			return i;
-	return -1;
-}
-
 int
 imap4date(Tm *tm, char *date)
 {
-	char *flds[4];
-
-	if(getfields(date, flds, 3, 0, "-") != 3)
+	if(tmparse(tm, "DD-?MM-YYYY hh:mm:ss ?Z", date, nil, nil) == nil)
 		return 0;
-
-	tm->mday = strtol(flds[0], nil, 10);
-	tm->mon = dateindex(flds[1], monname, 12);
-	tm->year = strtol(flds[2], nil, 10) - 1900;
 	return 1;
 }
 
@@ -146,29 +14,17 @@
 ulong
 imap4datetime(char *date)
 {
-	char *flds[4], *sflds[4];
-	ulong t;
 	Tm tm;
+	vlong s;
 
-	if(getfields(date, flds, 4, 0, " ") != 3)
-		return ~0;
-
-	if(!imap4date(&tm, flds[0]))
-		return ~0;
-
-	if(getfields(flds[1], sflds, 3, 0, ":") != 3)
-		return ~0;
-
-	tm.hour = strtol(sflds[0], nil, 10);
-	tm.min = strtol(sflds[1], nil, 10);
-	tm.sec = strtol(sflds[2], nil, 10);
-
-	strcpy(tm.zone, "GMT");
-	tm.yday = 0;
-	t = tm2sec(&tm);
-	zone2tm(&tm, flds[2]);
-	t -= tm.tzoff;
-	return t;
+	s = -1;
+	if(tmparse(&tm, "?DD-?MM-YYYY hh:mm:ss ?Z", date, nil, nil) != nil)
+		s = tmnorm(&tm);
+	else if(tmparse(&tm, "?W, ?DD-?MM-YYYY hh:mm:ss ?Z", date, nil, nil) != nil)
+		s = tmnorm(&tm);
+	if(s > 0 && s < (1ULL<<31))
+		return s;
+	return ~0;
 }
 
 /*
@@ -181,85 +37,18 @@
 Tm*
 date2tm(Tm *tm, char *date)
 {
-	char *flds[7], *s, dstr[64];
-	int n;
-	Tm gmt, *atm;
+	char **f, *fmts[] = {
+		"?W, ?DD ?MMM YYYY hh:mm:ss ?Z",
+		"?W ?M ?DD hh:mm:ss ?Z YYYY",
+		"?W, DD-?MM-YY hh:mm:ss ?Z",
+		"?DD ?MMM YYYY hh:mm:ss ?Z",
+		"?M ?DD hh:mm:ss ?Z YYYY",
+		"DD-?MM-YYYY hh:mm:ss ?Z",
+		nil,
+	};
 
-	/*
-	 * default date is Thu Jan  1 00:00:00 GMT 1970
-	 */
-	tm->wday = 4;
-	tm->mday = 1;
-	tm->mon = 1;
-	tm->hour = 0;
-	tm->min = 0;
-	tm->sec = 0;
-	tm->year = 70;
-	strcpy(tm->zone, "GMT");
-	tm->tzoff = 0;
-
-	strncpy(dstr, date, sizeof dstr);
-	dstr[sizeof dstr - 1] = 0;
-	n = tokenize(dstr, flds, 7);
-	if(n != 6 && n != 5)
-		return nil;
-
-	if(n == 5){
-		for(n = 5; n >= 1; n--)
-			flds[n] = flds[n - 1];
-		n = 5;
-	}else{
-		/*
-		 * Wday[,]
-		 */
-		s = strchr(flds[0], ',');
-		if(s != nil)
-			*s = 0;
-		tm->wday = dateindex(flds[0], wdayname, 7);
-		if(tm->wday < 0)
-			return nil;
-	}
-
-	/*
-	 * check for the two major formats:
-	 * Month first or day first
-	 */
-	tm->mon = dateindex(flds[1], monname, 12);
-	if(tm->mon >= 0){
-		tm->mday = strtoul(flds[2], nil, 10);
-		time2tm(tm, flds[3]);
-		zone2tm(tm, flds[4]);
-		tm->year = strtoul(flds[5], nil, 10);
-		if(strlen(flds[5]) > 2)
-			tm->year -= 1900;
-	}else{
-		tm->mday = strtoul(flds[1], nil, 10);
-		tm->mon = dateindex(flds[2], monname, 12);
-		if(tm->mon < 0)
-			return nil;
-		tm->year = strtoul(flds[3], nil, 10);
-		if(strlen(flds[3]) > 2)
-			tm->year -= 1900;
-		time2tm(tm, flds[4]);
-		zone2tm(tm, flds[5]);
-	}
-
-	if(n == 5){
-		gmt = *tm;
-		strncpy(gmt.zone, "", 4);
-		gmt.tzoff = 0;
-		atm = gmtime(tm2sec(&gmt));
-		tm->wday = atm->wday;
-	}else{
-		/*
-		 * Wday[,]
-		 */
-		s = strchr(flds[0], ',');
-		if(s != nil)
-			*s = 0;
-		tm->wday = dateindex(flds[0], wdayname, 7);
-		if(tm->wday < 0)
-			return nil;
-	}
-	return tm;
+	for(f = fmts; *f; f++)
+		if(tmparse(tm, *f, date, nil, nil) != nil)
+			return tm;
+	return nil;
 }
--- a/sys/src/cmd/upas/imap4d/imap4d.c
+++ b/sys/src/cmd/upas/imap4d/imap4d.c
@@ -215,6 +215,7 @@
 	Binit(&bin, dup(0, -1), OREAD);
 	close(0);
 	Binit(&bout, 1, OWRITE);
+	tmfmtinstall();
 	quotefmtinstall();
 	fmtinstall('F', Ffmt);
 	fmtinstall('D', Dfmt);	/* rfc822; # imap date %Z */
@@ -501,6 +502,8 @@
 	char *mbox, head[128];
 	uint t, n, now;
 	int flags, ok;
+	Tzone *tz;
+	Tm tm;
 	Uidplus u;
 
 	mustbe(' ');
@@ -536,7 +539,9 @@
 		return;
 	}
 
-	snprint(head, sizeof head, "From %s %s", username, ctime(t));
+	tz = tzload("local");
+	tmtime(&tm, t, tz);
+	snprint(head, sizeof head, "From %s %τ", username, tmfmt(&tm, "WW MMM _D hh:mm:ss Z YYYY"));
 	ok = appendsave(mbox, flags, head, &bin, n, &u);
 	crnl();
 	check();
--- a/sys/src/cmd/upas/imap4d/nlisttst.c
+++ b/sys/src/cmd/upas/imap4d/nlisttst.c
@@ -1,7 +1,5 @@
 #include "nlist.c"
 
-char	username[] = "quanstro";
-char	mboxdir[] = "/mail/box/quanstro/";
 Biobuf	bout;
 Bin	*parsebin;
 
--- a/sys/src/cmd/upas/imap4d/print.c
+++ b/sys/src/cmd/upas/imap4d/print.c
@@ -90,40 +90,25 @@
 	return fmtstrcpy(f, encfs(buf, sizeof buf, s));
 }
 
-static char *day[] = {
-	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
-};
-
-static char *mon[] = {
-	"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-};
-
 int
 Dfmt(Fmt *f)
 {
-	char buf[128], *p, *e, *sgn, *fmt;
-	int off;
-	Tm *tm;
+	char buf[128], *fmt;
+	Tm *tm, t;
+	Tzone *tz;
 
 	tm = va_arg(f->args, Tm*);
-	if(tm == nil)
-		tm = localtime(time(0));
-	sgn = "+";
-	if(tm->tzoff < 0)
-		sgn = "";
-	e = buf + sizeof buf;
-	p = buf;
-	off = (tm->tzoff/3600)*100 + (tm->tzoff/60)%60;
+	if(tm == nil){
+		tz = tzload("local");
+		tm = tmtime(&t, time(0), tz);
+	}
 	if((f->flags & FmtSharp) == 0){
 		/* rfc822 style */
-		fmt = "%.2d %s %.4d %.2d:%.2d:%.2d %s%.4d";
-		p = seprint(p, e, "%s, ", day[tm->wday]);
+		fmt = "WW, DD MMM YYYY hh:mm:ss Z";
 	}else
-		fmt = "%2d-%s-%.4d %2.2d:%2.2d:%2.2d %s%4.4d";
-	seprint(p, e, fmt,
-		tm->mday, mon[tm->mon], tm->year + 1900, tm->hour, tm->min, tm->sec,
-		sgn, off);
+		fmt = "DD-MMM-YYYY hh:mm:ss Z";
 	if(f->r == L'δ')
-		return fmtstrcpy(f, buf);
+		return fmtprint(f, "%τ", tmfmt(tm, fmt));
+	snprint(buf, sizeof(buf), "%τ", tmfmt(tm, fmt));
 	return fmtprint(f, "%Z", buf);
 }
--- a/sys/src/cmd/upas/marshal/marshal.c
+++ b/sys/src/cmd/upas/marshal/marshal.c
@@ -140,6 +140,7 @@
 char lastchar;
 char *replymsg;
 
+#define Rfc822fmt	"WW, DD MMM YYYY hh:mm:ss Z"
 enum
 {
 	Ok = 0,
@@ -208,6 +209,7 @@
 	hdrstring = nil;
 	ccargc = bccargc = 0;
 
+	tmfmtinstall();
 	quotefmtinstall();
 	fmtinstall('Z', doublequote);
 	fmtinstall('U', rfc2047fmt);
@@ -792,29 +794,13 @@
 	Bterm(f);
 }
 
-char *ascwday[] =
-{
-	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
-};
-
-char *ascmon[] =
-{
-	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
-	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-};
-
 int
 printdate(Biobuf *b)
 {
-	int tz;
 	Tm *tm;
 
 	tm = localtime(time(0));
-	tz = (tm->tzoff/3600)*100 + (tm->tzoff/60)%60;
-
-	return Bprint(b, "Date: %s, %d %s %d %2.2d:%2.2d:%2.2d %s%.4d\n",
-		ascwday[tm->wday], tm->mday, ascmon[tm->mon], 1900 + tm->year,
-		tm->hour, tm->min, tm->sec, tz>=0?"+":"", tz);
+	return Bprint(b, "Date: %τ\n", tmfmt(tm, Rfc822fmt));
 }
 
 int
@@ -1003,16 +989,10 @@
 int
 printunixfrom(int fd)
 {
-	int tz;
 	Tm *tm;
 
 	tm = localtime(time(0));
-	tz = (tm->tzoff/3600)*100 + (tm->tzoff/60)%60;
-
-	return fprint(fd, "From %s %s %s %d %2.2d:%2.2d:%2.2d %s%.4d %d\n",
-		user,
-		ascwday[tm->wday], ascmon[tm->mon], tm->mday,
-		tm->hour, tm->min, tm->sec, tz>=0?"+":"", tz, 1900 + tm->year);
+	return fprint(fd, "From %s %τ\n", user, tmfmt(tm, Rfc822fmt));
 }
 
 char *specialfile[] =
--- a/sys/src/cmd/upas/pop3/pop3.c
+++ b/sys/src/cmd/upas/pop3/pop3.c
@@ -102,6 +102,8 @@
 	Binit(&in, 0, OREAD);
 	Binit(&out, 1, OWRITE);
 
+	tmfmtinstall();
+
 	ARGBEGIN{
 	case 'a':
 		loggedin = 1;
--- a/sys/src/cmd/upas/scanmail/scanmail.c
+++ b/sys/src/cmd/upas/scanmail/scanmail.c
@@ -400,18 +400,16 @@
 opendump(char *sender)
 {
 	int i;
+	Tm tm;
 	ulong h;
 	char buf[512];
 	Biobuf *b;
-	char *cp;
+	char *cp, mon[8], day[4];
 
-	cp = ctime(time(0));
-	cp[7] = 0;
-	cp[10] = 0;
-	if(cp[8] == ' ')
-		snprint(buf, sizeof buf, "%s/queue.dump/%s%c", SPOOL, cp+4, cp[9]);
-	else
-		snprint(buf, sizeof buf, "%s/queue.dump/%s%c%c", SPOOL, cp+4, cp[8], cp[9]);
+	tmnow(&tm, nil);
+	snprint(mon, sizeof(mon), "%τ", tmfmt(&tm, "MMM"));
+	snprint(day, sizeof(day), "%τ", tmfmt(&tm, "D"));
+	snprint(buf, sizeof buf, "%s/queue.dump/%s%s", SPOOL, mon, day);
 	cp = buf+strlen(buf);
 	if(access(buf, 0) < 0 && sysmkdir(buf, 0777) < 0){
 		syslog(0, "smtpd", "couldn't dump mail from %s: %r", sender);
--- a/sys/src/cmd/upas/send/main.c
+++ b/sys/src/cmd/upas/send/main.c
@@ -66,6 +66,7 @@
 		usage();
 	}ARGEND
 
+	tmfmtinstall();
 	if(*argv == 0)
 		usage();
 	dp = 0;
@@ -404,20 +405,22 @@
 replymsg(String *errstring, message *mp, dest *dp)
 {
 	message *refp = m_new();
+	String *boundary;
 	dest *ndp;
-	char *rcvr;
+	char *rcvr, now[128];
 	int rv;
-	String *boundary;
+	Tm tm;
 
 	boundary = mkboundary();
 
 	refp->bulk = 1;
 	refp->rfc822headers = 1;
+	snprint(now, sizeof(now), "%τ", thedate(&tm));
 	rcvr = dp->status==d_eloop ? "postmaster" : s_to_c(mp->replyaddr);
 	ndp = d_new(s_copy(rcvr));
 	s_append(refp->sender, "postmaster");
 	s_append(refp->replyaddr, "/dev/null");
-	s_append(refp->date, thedate());
+	s_append(refp->date, now);
 	refp->haveto = 1;
 	s_append(refp->body, "To: ");
 	s_append(refp->body, rcvr);
--- a/sys/src/cmd/upas/send/message.c
+++ b/sys/src/cmd/upas/send/message.c
@@ -21,10 +21,12 @@
 int
 default_from(message *mp)
 {
-	char *cp, *lp;
+	char *cp, *lp, now[128];
+	Tm tm;
 
 	cp = getenv("upasname");
 	lp = getlog();
+	snprint(now, sizeof(now), "%τ", thedate(&tm));
 	if(lp == nil){
 		free(cp);
 		return -1;
@@ -34,7 +36,7 @@
 	else
 		s_append(mp->sender, lp);
 	free(cp);
-	s_append(mp->date, thedate());
+	s_append(mp->date, now);
 	return 0;
 }
 
--- a/sys/src/cmd/upas/smtp/smtp.c
+++ b/sys/src/cmd/upas/smtp/smtp.c
@@ -131,8 +131,10 @@
 	int i, ok, rcvrs, bustedmx;
 	String *from, *fromm, *sender;
 	Mx mx;
+	Tm tm;
 
 	alarmscale = 60*1000;	/* minutes */
+	tmfmtinstall();
 	quotefmtinstall();
 	mailfmtinstall();		/* 2047 encoding */
 	fmtinstall('D', Dfmt);
@@ -309,7 +311,7 @@
 	/*
 	 *  here when some but not all rcvrs failed
 	 */
-	fprint(2, "%s connect to %s: %D %s:\n", thedate(), addr, &mx, phase);
+	fprint(2, "%τ connect to %s: %D %s:\n", thedate(&tm), addr, &mx, phase);
 	for(i = 0; i < rcvrs; i++){
 		if(errs[i]){
 			syslog(0, "smtp.fail", "delivery to %s at %s %D %s, failed: %s",
@@ -335,7 +337,7 @@
 	}
 	syslog(0, "smtp.fail", "%s %s at %s %D %s failed: %s",
 		deliverytype(), allrx, addr, &mx, phase, s_to_c(reply));
-	fprint(2, "%s connect to %s %D %s:\n%s\n", thedate(), addr, &mx, phase, s_to_c(reply));
+	fprint(2, "%τ connect to %s %D %s:\n%s\n", thedate(&tm), addr, &mx, phase, s_to_c(reply));
 	if(!filter)
 		quit(rv);
 	exits(rv);
--- a/sys/src/cmd/upas/smtp/smtpd.c
+++ b/sys/src/cmd/upas/smtp/smtpd.c
@@ -92,8 +92,10 @@
 {
 	char *netdir;
 	char buf[1024];
+	Tm tm;
 
 	netdir = nil;
+	tmfmtinstall();
 	quotefmtinstall();
 	fmtinstall('I', eipfmt);
 	fmtinstall('[', encodefmt);
@@ -163,7 +165,7 @@
 		snprint(buf, sizeof(buf), "%s/smtpd.db", UPASLOG);
 		if (open(buf, OWRITE) >= 0) {
 			seek(2, 0, 2);
-			fprint(2, "%d smtpd %s\n", getpid(), thedate());
+			fprint(2, "%d smtpd %τ\n", getpid(), thedate(&tm));
 		} else
 			debug = 0;
 	}
@@ -1169,6 +1171,7 @@
 	char *cp;
 	int n, nbytes, sawdot, status;
 	String *hdr, *line;
+	Tm tm;
 
 	pipesig(&status);	/* set status to 1 on write to closed pipe */
 	sawdot = 0;
@@ -1180,12 +1183,12 @@
 	 *  add a 'From ' line as envelope and Received: stamp
 	 */
 	nbytes = 0;
-	nbytes += Bprint(pp->std[0]->fp, "From %s %s remote from \n",
-		s_to_c(senders.first->p), thedate());
+	nbytes += Bprint(pp->std[0]->fp, "From %s %τ remote from \n",
+		s_to_c(senders.first->p), thedate(&tm));
 	nbytes += Bprint(pp->std[0]->fp, "Received: from %s ", him);
 	if(nci->rsys)
 		nbytes += Bprint(pp->std[0]->fp, "([%s]) ", nci->rsys);
-	nbytes += Bprint(pp->std[0]->fp, "by %s; %s\n", me, thedate());
+	nbytes += Bprint(pp->std[0]->fp, "by %s; %τ\n", me, thedate(&tm));
 
 	/*
 	 *  read first 16k obeying '.' escape.  we're assuming
--- a/sys/src/cmd/upas/smtp/spam.c
+++ b/sys/src/cmd/upas/smtp/spam.c
@@ -417,17 +417,15 @@
 dumpfile(char *sender)
 {
 	int i, fd;
+	Tm tm;
 	ulong h;
 	static char buf[512];
-	char *cp;
+	char *cp, mon[8], day[4];
 
 	if (sflag == 1){
-		cp = ctime(time(0));
-		cp[7] = 0;
-		if(cp[8] == ' ')
-			sprint(buf, "%s/queue.dump/%s%c", SPOOL, cp + 4, cp[9]);
-		else
-			sprint(buf, "%s/queue.dump/%s%c%c", SPOOL, cp + 4, cp[8], cp[9]);
+		snprint(mon, sizeof(mon), "%τ", tmfmt(&tm, "MMM"));
+		snprint(day, sizeof(day), "%τ", tmfmt(&tm, "D"));
+		snprint(buf, sizeof buf, "%s/queue.dump/%s%s", SPOOL, mon, day);
 		cp = buf + strlen(buf);
 		if(access(buf, 0) < 0 && sysmkdir(buf, 0777) < 0)
 			return "/dev/null";
--- a/sys/src/cmd/upas/vf/vf.c
+++ b/sys/src/cmd/upas/vf/vf.c
@@ -372,7 +372,7 @@
 save(Part *p, char *file)
 {
 	int fd;
-	char *cp;
+	Tm tm;
 
 	Bterm(&out);
 	memset(&out, 0, sizeof(out));
@@ -382,9 +382,7 @@
 		return -1;
 	seek(fd, 0, 2);
 	Binit(&out, fd, OWRITE);
-	cp = ctime(time(0));
-	cp[28] = 0;
-	Bprint(&out, "From virusfilter %s\n", cp);
+	Bprint(&out, "From virusfilter %τ\n", thedate(&tm));
 	writeheader(p, 0);
 	bodyoff = Boffset(&out);
 	passbody(p, 1);