Blame src/functional/strptime.c

Rafał Miłecki 2ec494
// SPDX-License-Identifier: MIT
Rafał Miłecki 2ec494
Rafał Miłecki 2ec494
#define _GNU_SOURCE	/* For tm_gmtoff */
Rafał Miłecki 2ec494
#include <stddef.h>
Rafał Miłecki 2ec494
#include <stdlib.h>
Rafał Miłecki 2ec494
#include <string.h>
Rafał Miłecki 2ec494
#include <time.h>
Rafał Miłecki 2ec494
#include "test.h"
Rafał Miłecki 2ec494
Rafał Miłecki 2ec494
/**
Rafał Miłecki 2ec494
 * checkStrptime - parse time and check if it matches expected value
Rafał Miłecki 2ec494
 *
Rafał Miłecki 2ec494
 * This function compares time and date fields of tm structure only.
Rafał Miłecki 2ec494
 * It's because tm_wday and tm_yday may - but don't have to - be set
Rafał Miłecki 2ec494
 * while parsing a date.
Rafał Miłecki 2ec494
 */
Rafał Miłecki 2ec494
static void checkStrptime(const char *s, const char *format, const struct tm *expected) {
Rafał Miłecki 2ec494
	struct tm tm = { };
Rafał Miłecki 2ec494
	const char *ret;
Rafał Miłecki 2ec494
Rafał Miłecki 2ec494
	ret = strptime(s, format, &tm;;
Rafał Miłecki 2ec494
	if (!ret || *ret != '\0') {
Rafał Miłecki 2ec494
		t_error("\"%s\": failed to parse \"%s\"\n", format, s);
Rafał Miłecki 2ec494
	} else if (tm.tm_sec != expected->tm_sec ||
Rafał Miłecki 2ec494
		   tm.tm_min != expected->tm_min ||
Rafał Miłecki 2ec494
		   tm.tm_hour != expected->tm_hour ||
Rafał Miłecki 2ec494
		   tm.tm_mday != expected->tm_mday ||
Rafał Miłecki 2ec494
		   tm.tm_mon != expected->tm_mon ||
Rafał Miłecki 2ec494
		   tm.tm_year != expected->tm_year) {
Rafał Miłecki 2ec494
		char buf1[64];
Rafał Miłecki 2ec494
		char buf2[64];
Rafał Miłecki 2ec494
Rafał Miłecki 2ec494
		strftime(buf1, sizeof(buf1), "%FT%H:%M:%S%Z", expected);
Rafał Miłecki 2ec494
		strftime(buf2, sizeof(buf2), "%FT%H:%M:%S%Z", &tm;;
Rafał Miłecki 2ec494
Rafał Miłecki 2ec494
		t_error("\"%s\": for \"%s\" expected %s but got %s\n", format, s, buf1, buf2);
Rafał Miłecki 2ec494
	}
Rafał Miłecki 2ec494
}
Rafał Miłecki 2ec494
Rafał Miłecki 2ec494
static void checkStrptimeTz(const char *s, int h, int m) {
Rafał Miłecki 2ec494
	long int expected = h * 3600 + m * 60;
Rafał Miłecki 2ec494
	struct tm tm = { };
Rafał Miłecki 2ec494
	const char *ret;
Rafał Miłecki 2ec494
Rafał Miłecki 2ec494
	ret = strptime(s, "%z", &tm;;
Rafał Miłecki 2ec494
	if (!ret || *ret != '\0') {
Rafał Miłecki 2ec494
		t_error("\"%%z\": failed to parse \"%s\"\n", s);
Rafał Miłecki 2ec494
	} else if (tm.tm_gmtoff != expected) {
Rafał Miłecki 2ec494
		t_error("\"%%z\": for \"%s\" expected tm_gmtoff %ld but got %ld\n", s, tm.tm_gmtoff, expected);
Rafał Miłecki 2ec494
	}
Rafał Miłecki 2ec494
}
Rafał Miłecki 2ec494
Rafał Miłecki 2ec494
static struct tm tm1 = {
Rafał Miłecki 2ec494
	.tm_sec = 8,
Rafał Miłecki 2ec494
	.tm_min = 57,
Rafał Miłecki 2ec494
	.tm_hour = 20,
Rafał Miłecki 2ec494
	.tm_mday = 0,
Rafał Miłecki 2ec494
	.tm_mon = 0,
Rafał Miłecki 2ec494
	.tm_year = 0,
Rafał Miłecki 2ec494
};
Rafał Miłecki 2ec494
Rafał Miłecki 2ec494
static struct tm tm2 = {
Rafał Miłecki 2ec494
	.tm_sec = 0,
Rafał Miłecki 2ec494
	.tm_min = 0,
Rafał Miłecki 2ec494
	.tm_hour = 0,
Rafał Miłecki 2ec494
	.tm_mday = 25,
Rafał Miłecki 2ec494
	.tm_mon = 8 - 1,
Rafał Miłecki 2ec494
	.tm_year = 1991 - 1900,
Rafał Miłecki 2ec494
};
Rafał Miłecki 2ec494
Rafał Miłecki 2ec494
static struct tm tm3 = {
Rafał Miłecki 2ec494
	.tm_sec = 0,
Rafał Miłecki 2ec494
	.tm_min = 0,
Rafał Miłecki 2ec494
	.tm_hour = 0,
Rafał Miłecki 2ec494
	.tm_mday = 21,
Rafał Miłecki 2ec494
	.tm_mon = 10 - 1,
Rafał Miłecki 2ec494
	.tm_year = 2015 - 1900,
Rafał Miłecki 2ec494
};
Rafał Miłecki 2ec494
Rafał Miłecki 2ec494
static struct tm tm4 = {
Rafał Miłecki 2ec494
	.tm_sec = 0,
Rafał Miłecki 2ec494
	.tm_min = 0,
Rafał Miłecki 2ec494
	.tm_hour = 0,
Rafał Miłecki 2ec494
	.tm_mday = 10,
Rafał Miłecki 2ec494
	.tm_mon = 7 - 1,
Rafał Miłecki 2ec494
	.tm_year = 1856 - 1900,
Rafał Miłecki 2ec494
};
Rafał Miłecki 2ec494
Rafał Miłecki 2ec494
int main() {
Rafał Miłecki 2ec494
	setenv("TZ", "UTC0", 1);
Rafał Miłecki 2ec494
Rafał Miłecki 2ec494
	/* Time */
Rafał Miłecki 2ec494
	checkStrptime("20:57:08", "%H:%M:%S", &tm1);
Rafał Miłecki 2ec494
	checkStrptime("20:57:8", "%R:%S", &tm1);
Rafał Miłecki 2ec494
	checkStrptime("20:57:08", "%T", &tm1);
Rafał Miłecki 2ec494
Rafał Miłecki 2ec494
	/* Format */
Rafał Miłecki 2ec494
	checkStrptime("20:57:08", "%H : %M  :  %S", &tm1);
Rafał Miłecki 2ec494
	checkStrptime("20 57  08", "%H %M %S", &tm1);
Rafał Miłecki 2ec494
	checkStrptime("20%57%08", "%H %% %M%%%S", &tm1);
Rafał Miłecki 2ec494
	checkStrptime("foo20bar57qux08      ", "foo %Hbar %M qux%S ", &tm1);
Rafał Miłecki 2ec494
Rafał Miłecki 2ec494
	/* Date */
Rafał Miłecki 2ec494
	checkStrptime("1991-08-25", "%Y-%m-%d", &tm2);
Rafał Miłecki 2ec494
	checkStrptime("25.08.91", "%d.%m.%y", &tm2);
Rafał Miłecki 2ec494
	checkStrptime("08/25/91", "%D", &tm2);
Rafał Miłecki 2ec494
	checkStrptime("21.10.15", "%d.%m.%y", &tm3);
Rafał Miłecki 2ec494
	checkStrptime("10.7.56 in 18th", "%d.%m.%y in %C th", &tm4);
Rafał Miłecki 2ec494
Rafał Miłecki 2ec494
	/* Glibc */
Rafał Miłecki 2ec494
	checkStrptime("1856-07-10", "%F", &tm4);
Rafał Miłecki 2ec494
	checkStrptime("683078400", "%s", &tm2);
Rafał Miłecki 2ec494
	checkStrptimeTz("+0200", 2, 0);
Rafał Miłecki 2ec494
	checkStrptimeTz("-0530", -5, -30);
Rafał Miłecki 2ec494
	checkStrptimeTz("-06", -6, 0);
Rafał Miłecki 2ec494
Rafał Miłecki 2ec494
	return t_status;
Rafał Miłecki 2ec494
}