shithub: regress

ref: a36bb18853d22d68fbead016756a23bb6be87431
dir: /libc/date.c/

View raw version
#include <u.h>
#include <libc.h>

int failed;

/*
 * For debugging
 */
void
printtm(Tm *tm)
{
	fprint(2, "abs=%lld sec=%d min=%d hour=%d mday=%d mon=%d"
		" year=%d day=%d yday=%d zone=%s tzoff=%d\n",
		tm->abs, /* milliseconds since Jan 1 1970, GMT */
		tm->sec, /* seconds (range 0..59) */
		tm->min, /* minutes (0..59) */
		tm->hour,     /* hours (0..23) */
		tm->mday,     /* day of the month (1..31) */
		tm->mon, /* month of the year (0..11) */
		tm->year,     /* year A.D. - 1900 */
		tm->wday,     /* day of week (0..6, Sunday = 0) */
		tm->yday,     /* day of year (0..365) */
		tm->zone,   /* time zone name */
		tm->tzoff);    /* time   zone delta from GMT */
}

void
fail(char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	fprint(2, "failed: ");
	vfprint(2, fmt, ap);
	va_end(ap);
	failed++;
}

void
testtm(int i, int year, int mon, int mday, int hour, int min, int sec, Tm *tm){
	if(tm->year != year-1900) fail("%d wrong year expected=%d actual=%d\n", i, year, tm->year);
	if(tm->mon != mon)	fail("%d wrong month expected=%d actual=%d\n", i, mon, tm->mon);
	if(tm->mday != mday)	fail("%d wrong mday expected=%d actual=%d\n", i, mday, tm->mday);
	if(tm->hour != hour)	fail("%d wrong hour expected=%d actual=%d\n", i, hour, tm->hour);
	if(tm->min != min)	fail("%d wrong min expected=%d actual=%d\n", i, min, tm->min);
	if(tm->sec != sec)	fail("%d wrong sec expected=%d actual=%d\n", i, sec, tm->sec);
}

void
main(int, char **)
{
	Tm tm, tt;
	Tzone *gmt, *us_arizona, *us_eastern, *us_central;
	Tm here, there;
	Tzone *zl, *zp;
	char buf[128], buf1[128];
	int i, h;

	tmfmtinstall();
	if((gmt = tzload("GMT")) == nil)
		sysfatal("nil gmt: %r\n");
	if((us_arizona = tzload("US_Arizona")) == nil)
		sysfatal("nil us_arizona: %r\n");
	if((us_eastern = tzload("US_Eastern")) == nil)
		sysfatal("nil us_eastern: %r\n");
	if((us_central = tzload("US_Central")) == nil)
		sysfatal("get zone: %r\n");

	if((zl = tzload("local")) == nil)
	     sysfatal("load zone: %r\n");
	if((zp = tzload("US_Pacific")) == nil)
	     sysfatal("load zone: %r\n");
	if(tmnow(&here, zl) == nil)
	     sysfatal("get time: %r\n");
	if(tmtime(&there, here.abs, zp) == nil)
	     sysfatal("shift time: %r\n");

	tmtime(&tm, 1586574870, gmt);
	testtm(1, 2020, 3, 11, 3, 14, 30, &tm);
	tmtime(&tm, 1586574870, us_arizona);
	testtm(1, 2020, 3, 10, 20, 14, 30, &tm);

	tmtime(&tm, 0, gmt);
	testtm(3, 1970, 0, 1, 0, 0, 0, &tm);
	tmnorm(&tm);
	testtm(4, 1970, 0, 1, 0, 0, 0, &tm);

	tmtime(&tm, 84061, gmt);
	testtm(5, 1970, 0, 1, 23, 21, 1, &tm);
	tmnorm(&tm);
	testtm(6, 1970, 0, 1, 23, 21, 1, &tm);

	tmtime(&tm, 1586574870, us_arizona);
	testtm(7, 2020, 3, 10, 20, 14, 30, &tm);
	tmnorm(&tm);
	testtm(8, 2020, 3, 10, 20, 14, 30, &tm);

	tmtime(&tm, 1586574870, us_eastern);
	testtm(9, 2020, 3, 10, 23, 14, 30, &tm);
	tmnorm(&tm);
	testtm(10, 2020, 3, 10, 23, 14, 30, &tm);

	if(tmparse(&tm, "hhmm", "1600", gmt) == nil)
		sysfatal("failed parse: %r\n");
	testtm(99, 1970, 0, 1, 16, 0, 0, &tm);

	if(tmparse(&tm, "YYYY-MM-DD hh:mm:ss Z", "1969-12-31 16:00:00 -0800", nil) == nil)
		fail("parse failed: %r\n");
	if(tm.abs != 0)
		fail("wrong result: %lld != 0\n", tm.abs);

	if(tmparse(&tm, "YYYY MM DD", "1990,01,03", nil) == nil)
		fail("comma parse failed");
	if(tm.abs != 631324800)
		fail("wrong result");
	if(tmparse(&tm, "YYYY MM DD", "1990 ,\t01,03", nil) == nil)
		fail("comma parse failed");
	if(tm.abs != 631324800)
		fail("wrong result");

	if(tmparse(&tm, "YYYY MM DD hh:mm:ss", "1969 12 31 16:00:00", gmt) == nil)
		sysfatal("failed parse: %r\n");
	testtm(100, 1969, 11, 31, 16, 0, 0, &tm);

	if(tmparse(&tm, "YYYY MM DD hh:mm:ss", "1970 01 01 04:00:00", gmt) == nil)
	fail("failed parse: %r\n");
	testtm(101, 1970, 0, 1, 4, 0, 0, &tm);

	if(tmparse(&tm, "YYYY MM DD", "1970 01 01", gmt) == nil)
	fail("failed parse: %r\n");
	testtm(102, 1970, 0, 1, 0, 0, 0, &tm);

	if(tmparse(&tm, "YYYY MMMM DD WW hh:mm:ss",	 "2020 April 10 Friday 16:04:00", gmt) == nil)
		sysfatal("failed parse: %r\n");
	testtm(103, 2020, 3, 10, 16, 4, 0, &tm);

	if(tmparse(&tm, "MM DD hh:mm:ss", "12 31 16:00:00", gmt) == nil)
		sysfatal("failed parse: %r\n");
	testtm(104, 1970, 11, 31, 16, 0, 0, &tm);

	if(tmparse(&tm, "MM DD h:mm:ss", "12 31 4:00:00", gmt) == nil)
		sysfatal("failed parse: %r\n");
	testtm(105, 1970, 11, 31, 4, 0, 0, &tm);
	if(tm.tzoff != 0) print("%d wrong tzoff expected=%d actual=%d\n", 6, 0, tm.tzoff);

	if(tmparse(&tm, "YYYY MM DD hh:mm:ss", "2020 04 10 23:14:30", us_eastern) == nil)
	fail("failed parse: %r\n");
	testtm(106, 2020, 3, 10, 23, 14, 30, &tm);
	tmtime(&tm, tm.abs, nil);

	if(tmparse(&tm, "YYYY MM DD hh:mm:ss", "2020 04 10 20:14:30", us_arizona) == nil)
		fail("failed parse: %r\n");
	testtm(108, 2020, 3, 10, 20, 14, 30, &tm);

	if(tmparse(&tm, "YYYY MM DD hh:mm:ss ZZZ", "2020 04 10 20:14:30 EST", us_arizona) == nil)
		fail("failed parse: %r\n");
	testtm(108, 2020, 3, 10, 17, 14, 30, &tm);

	if(tmparse(&tm, "YYYY MM DD hh:mm:ss ZZZ", "2020 04 10 20:14:30 -0400", nil) == nil)
		fail("failed parse: %r\n");
	testtm(108, 2020, 3, 10, 20, 14, 30, &tm);
	snprint(buf, sizeof(buf), "%τ", tmfmt(&tm, "YYYY MM DD hh:mm:ss Z"));
	if(strcmp(buf, "2020 04 10 20:14:30 -0400") != 0)
		fail("failed format: %s != 2020 04 10 20:14:30 -0400", buf);

	/* edge case: leap year feb 29 */
	if(tmparse(&tm, "YYYY MM DD hh:mm:ss ZZZ", "2020 02 29 20:14:30 -0400", nil) == nil)
		fail("failed leap year feb 29: %r\n");
	testtm(109, 2020, 1, 29, 20, 14, 30, &tm);
	if(tmparse(&tm, "YYYY MM DD hh:mm:ss ZZZ", "2021 02 29 20:14:30 -0400", nil) != nil)
		fail("incorrectly accepted non-leap year feb 29\n");

	/* lots of round trips: Jan 1960 => Jun 2020, in almost-11 day increments */
	for(i = -315619200; i < 1592179806; i += 23*3600 + 1732){
		if(tmtime(&tm, i, nil) == nil)
			fail("load time %d\n", i);
		if(tm.abs != i)
			fail("wrong load time: %d\n", i);
		if(snprint(buf, sizeof(buf), "%τ", tmfmt(&tm, "W MMM DD hh:mm:ss Z YYYY")) == -1)
			fail("format: %r\n");
		if(tmparse(&tt, "W MMM DD hh:mm:ss Z YYYY", buf, nil) == nil)
			fail("parse: %r\n");
		if(tm.abs != tt.abs)
			fail("parse: wrong time (%lld != %lld)\n", tm.abs, tt.abs);
	}

	/* lots of round trips: Jan 1960 => Jun 2020, in almost-dailyincrements, now with timezone */
	for(i = -315619200; i < 1592179806; i += 23*3600 + 1732){
		if(tmtime(&tm, i, us_eastern) == nil)
			fail("load time %d\n", i);
		if(tm.abs != i)
			fail("wrong load time: %d\n", i);
		if(snprint(buf, sizeof(buf), "%τ", tmfmt(&tm, "W MMM DD hh:mm:ss Z YYYY")) == -1)
			fail("format: %r\n");
		if(tmparse(&tt, "W MMM DD hh:mm:ss Z YYYY", buf, us_arizona) == nil)
			fail("parse: %r\n");
		if(tm.abs != tt.abs)
			fail("parse: wrong time (%lld != %lld)\n", tm.abs, tt.abs);
	}

	if(tmtime(&tm, -624623143, nil) == nil)
		fail("tmtime: %r");
	if(snprint(buf, sizeof(buf), "%τ", tmfmt(&tm, "W, DD MMM YYYY hh:mm:ss Z")) == -1)
		fail("format: %r");
	if(strcmp(buf, "Fri, 17 Mar 1950 13:34:17 +0000") != 0)
		fail("wrong output: %s\n", buf);
	if(tmtime(&tm, -624623143, us_eastern) == nil)
		fail("tmtime: %r");
	if(snprint(buf, sizeof(buf), "%τ", tmfmt(&tm, "W, DD MMM YYYY hh:mm:ss Z")) == -1)
		fail("format: %r");
	if(strcmp(buf, "Fri, 17 Mar 1950 08:34:17 -0500") != 0)
		fail("wrong output: %s\n", buf);

	/* AM and PM parsing */
	for(i = 0; i < 24; i++){
		h = i % 12;
		if(h == 0)
			h = 12;
		snprint(buf, sizeof(buf), "2021 02 01 %d:14:30 -0400", i);
		snprint(buf1, sizeof(buf1), "2021 02 01 %d:14:30 -0400 %s", h, (i < 12) ? "AM" : "PM");
		if(tmparse(&tm, "YYYY MM DD hh:mm:ss ZZZ", buf, nil) == nil)
			fail("parse: %r\n");
		if(tmparse(&tt, "YYYY MM DD hh:mm:ss ZZZ A", buf1, nil) == nil)
			fail("parse: %r\n");
		if(tm.abs != tt.abs)
			print("bad am/pm parsed: %s != %s (%lld != %lld)\n", buf, buf1, tm.abs, tt.abs);
	}

	/* Time zone boundaries: entering DST */
	if(tmtime(&tm, 1520733600, us_eastern) == nil)
		fail("tmtime: tz boundary");
	if(snprint(buf, sizeof(buf), "%τ", tmfmt(&tm, nil)) == -1)
		fail("format: %r");
	memset(&tm, 0, sizeof(tm));
	if(tmparse(&tm, "W MMM D hh:mm:ss ZZZ YYYY", buf, nil) == nil)
		fail("parse: %r\n");
	if(tm.abs != 1520733600)
		fail("round trip timezone: %lld != 1520733600\n", tm.abs);

	/* Time zone boundaries: leaving DST */
	if(tmtime(&tm, 1541296800, us_eastern) == nil)
		fail("tmtime: tz boundary");
	if(snprint(buf, sizeof(buf), "%τ", tmfmt(&tm, nil)) == -1)
		fail("format: %r\n");
	memset(&tm, 0, sizeof(tm));
	if(tmparse(&tm, "W MMM D hh:mm:ss ZZZ YYYY", buf, nil) == nil)
		fail("parse: %r");
	if(tm.abs != 1541296800)
		fail("round trip timezone: %lld != 1541296800\n", tm.abs);
	

	/* flexible date parsing */
	if(tmparse(&tm, "?YYYY ?MM DD hh:mm:ss ?ZZZ", "89 04 10 20:14:30 -0400", nil) == nil)
		fail("failed parse: %r\n");
	testtm(200, 1989, 3, 10, 20, 14, 30, &tm);
	char **d, *flexdates[] = {
		"1920 4 10 20:14:30 -0400",
		"1920 04 10 20:14:30 -0400",
		"1920 Apr 10 20:14:30 -0400",
		"1920 Apr 10 20:14:30 -04:00",
		"1920 Apr 10 20:14:30 -04:00",
		"1920 Apr 10 20:14:30 -04:00",
		"1920 April 10 20:14:30 EDT",
		"20 April 10 20:14:30 EDT",
		nil,
	};
	for(d = flexdates; *d; d++){
		if(tmparse(&tm, "?YYYY ?MM DD hh:mm:ss ?ZZZ", *d, nil) == nil)
			fail("failed parse: %r\n");
		testtm(201, 1920, 3, 10, 20, 14, 30, &tm);
	}

	/* Fuzzy zone */
	if(tmparse(&tm, "?YYYY ?MM DD hh:mm:ss ?ZZZ", "2020 04 10 20:14:30 NOPE", nil) == nil)
		fail("failed parse: %r\n");
	testtm(201, 2020, 3, 10, 20, 14, 30, &tm);

	/* test tmnorm() offset */
	memset(&tm, 0, sizeof(Tm));
	tm.year = 120;
	tm.sec=0;
	tm.min=0;
	tm.hour=0;
	tm.mday=22;
	tm.mon=5;
	tm.tz=us_central;
	tmnorm(&tm);
	if(tm.abs != 1592802000)
		fail("tmnorm is not using the daylight savings time offset. %lld != 1592809200\n", tm.abs);

	if(failed)
		exits("test failed");
	exits(nil);
}