n_time date formats: HTTP dates (format and strict parse), RFC 2822 for RSS, RFC 3339 (format and parse); expected strings from PHP 8.4
n_time date formats: HTTP dates (format and strict parse), RFC 2822 for RSS, RFC 3339 (format and parse); expected strings from PHP 8.4
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
if (!ok) {
} else {
}
}
int opt = 0;
while ((opt = getopt(argc, argv, "V:")) != -1) {
if (opt == 'V') {
} else {
return -1;
}
}
return 0;
}
typedef struct {
long long t;
const char* http;
const char* rss_utc;
const char* c_utc;
long paris;
const char* rss_paris;
const char* c_paris;
{0, "Thu, 01 Jan 1970 00:00:00 GMT", "Thu, 01 Jan 1970 00:00:00 +0000", "1970-01-01T00:00:00+00:00", 3600,
"Thu, 01 Jan 1970 01:00:00 +0100", "1970-01-01T01:00:00+01:00"},
{784111777, "Sun, 06 Nov 1994 08:49:37 GMT", "Sun, 06 Nov 1994 08:49:37 +0000", "1994-11-06T08:49:37+00:00", 3600,
"Sun, 06 Nov 1994 09:49:37 +0100", "1994-11-06T09:49:37+01:00"},
{951782400, "Tue, 29 Feb 2000 00:00:00 GMT", "Tue, 29 Feb 2000 00:00:00 +0000", "2000-02-29T00:00:00+00:00", 3600,
"Tue, 29 Feb 2000 01:00:00 +0100", "2000-02-29T01:00:00+01:00"},
{1792794600, "Fri, 23 Oct 2026 22:30:00 GMT", "Fri, 23 Oct 2026 22:30:00 +0000", "2026-10-23T22:30:00+00:00", 7200,
"Sat, 24 Oct 2026 00:30:00 +0200", "2026-10-24T00:30:00+02:00"},
{-1, "Wed, 31 Dec 1969 23:59:59 GMT", "Wed, 31 Dec 1969 23:59:59 +0000", "1969-12-31T23:59:59+00:00", 3600,
"Thu, 01 Jan 1970 00:59:59 +0100", "1970-01-01T00:59:59+01:00"},
};
char buf[64];
size_t i;
for (i = 0; i < sizeof(v) / sizeof(v[0]); i++) {
time_t t = (time_t)v[i].t;
}
expect_true(
"negative offset",
n_time_rfc3339(0, -(5 * 3600 + 30 * 60), buf,
sizeof(buf)) && strcmp(buf,
"1969-12-31T18:30:00-05:30") == 0);
expect_true(
"negative offset RFC 2822",
n_time_rfc2822(0, -(5 * 3600 + 30 * 60), buf,
sizeof(buf)) && strcmp(buf,
"Wed, 31 Dec 1969 18:30:00 -0530") == 0);
if (sizeof(time_t) >= 8) {
expect_true(
"year 9999",
n_time_http_date((time_t)253402300799LL, buf,
sizeof(buf)) && strcmp(buf,
"Fri, 31 Dec 9999 23:59:59 GMT") == 0);
expect_true(
"year 1",
n_time_http_date((time_t)-62135596800LL, buf,
sizeof(buf)) && strcmp(buf,
"Mon, 01 Jan 0001 00:00:00 GMT") == 0);
}
}
static int parses(
int http,
const char* s,
int ok,
long long want) {
time_t t = (time_t)12345;
if (!ok)
return r == FALSE && t == (time_t)12345;
return r == TRUE && (long long)t == want;
}
char buf[64];
long long t;
expect_true(
"HTTP date parses",
parses(1,
"Sun, 06 Nov 1994 08:49:37 GMT", 1, 784111777));
expect_true(
"HTTP date, 29 Feb 2000",
parses(1,
"Tue, 29 Feb 2000 00:00:00 GMT", 1, 951782400));
expect_true(
"HTTP date before 1970",
parses(1,
"Wed, 31 Dec 1969 23:59:59 GMT", 1, -1));
expect_true(
"wrong weekday refused",
parses(1,
"Mon, 06 Nov 1994 08:49:37 GMT", 0, 0));
expect_true(
"29 Feb 2100 refused",
parses(1,
"Mon, 29 Feb 2100 00:00:00 GMT", 0, 0));
expect_true(
"leap second refused",
parses(1,
"Sun, 06 Nov 1994 23:59:60 GMT", 0, 0));
expect_true(
"lowercase month refused",
parses(1,
"Sun, 06 nov 1994 08:49:37 GMT", 0, 0));
expect_true(
"RFC 850 form refused",
parses(1,
"Sunday, 06-Nov-94 08:49:37 GMT", 0, 0));
expect_true(
"trailing byte refused",
parses(1,
"Sun, 06 Nov 1994 08:49:37 GMTX", 0, 0));
expect_true(
"sign in a number refused",
parses(1,
"Sun, +6 Nov 1994 08:49:37 GMT", 0, 0));
expect_true(
"RFC 3339 offset",
parses(0,
"2026-10-24T00:30:00+02:00", 1, 1792794600));
expect_true(
"RFC 3339 negative offset",
parses(0,
"1969-12-31T18:30:00-05:30", 1, 0));
for (t = -2000000000LL; t < 4000000000LL; t += 7777777) {
time_t back = 0;
if (sizeof(time_t) < 8 && (t > 2147483647LL || t < -2147483647LL))
continue;
n_log(
LOG_ERR,
"FAIL: HTTP date round trip at %lld (%s)", t, buf);
break;
}
n_log(
LOG_ERR,
"FAIL: RFC 3339 round trip at %lld (%s)", t, buf);
break;
}
}
}
int main(
int argc,
char** argv) {
fprintf(stderr, "usage: %s [-V LOG_LEVEL]\n", argv[0]);
return 1;
}
return 1;
}
return 0;
}
void process_args(int argc, char **argv)
static void expect_true(const char *label, int cond)
static void test_parse(void)
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
#define LOG_ERR
error conditions
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL ).
#define LOG_NOTICE
normal but significant condition
#define LOG_INFO
informational
int n_time_parse_http_date(const char *s, size_t len, time_t *t)
parse an IMF-fixdate HTTP date strictly
int n_time_rfc2822(time_t t, long offset, char *out, size_t size)
format t as an RFC 2822 date at offset seconds east of UTC
int n_time_parse_rfc3339(const char *s, size_t len, time_t *t)
parse "YYYY-MM-DD[T| ]HH:MM:SS[Z|+hh:mm|-hh:mm]" (UTC without a zone)
#define N_TIME_RFC2822_LEN
buffer size for n_time_rfc2822(): "Thu, 01 Jan 1970 00:00:00 +0000" + NUL
#define N_TIME_HTTP_DATE_LEN
buffer size for n_time_http_date(): "Thu, 01 Jan 1970 00:00:00 GMT" + NUL
int n_time_http_date(time_t t, char *out, size_t size)
format t as an HTTP date (RFC 9110 IMF-fixdate, always GMT)
int n_time_rfc3339(time_t t, long offset, char *out, size_t size)
format t as RFC 3339 at offset seconds east of UTC ("+00:00" for UTC)
#define N_TIME_RFC3339_LEN
buffer size for n_time_rfc3339(): "1970-01-01T00:00:00+00:00" + NUL
Common headers and low-level functions & define.