Merge pull request #26772 from yuwata/time-util-adjust-formattable-timestamp-max

time-util: adjust formattable timestamp max
This commit is contained in:
Luca Boccassi
2023-03-12 23:06:39 +00:00
committed by GitHub
4 changed files with 50 additions and 16 deletions

View File

@@ -662,6 +662,9 @@ static int parse_timestamp_impl(
* +5min
* -5days
* @2147483647 (seconds since epoch)
*
* Note, on DST change, 00:00:00 may not exist and in that case the time part may be shifted.
* E.g. "Sun 2023-03-13 America/Havana" is parsed as "Sun 2023-03-13 01:00:00 CDT".
*/
assert(t);

View File

@@ -205,13 +205,17 @@ static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) {
return usec_sub_unsigned(timestamp, (usec_t) delta);
}
/* The last second we can format is 31. Dec 9999, 1s before midnight, because otherwise we'd enter 5 digit
* year territory. However, since we want to stay away from this in all timezones we take one day off. */
#define USEC_TIMESTAMP_FORMATTABLE_MAX_64BIT ((usec_t) 253402214399000000) /* Thu 9999-12-30 23:59:59 UTC */
/* With a 32bit time_t we can't go beyond 2038...
* We parse timestamp with RFC-822/ISO 8601 (e.g. +06, or -03:00) as UTC, hence the upper bound must be off
* by USEC_PER_DAY. See parse_timestamp() for more details. */
#define USEC_TIMESTAMP_FORMATTABLE_MAX_32BIT (((usec_t) INT32_MAX) * USEC_PER_SEC - USEC_PER_DAY)
#if SIZEOF_TIME_T == 8
/* The last second we can format is 31. Dec 9999, 1s before midnight, because otherwise we'd enter 5 digit
* year territory. However, since we want to stay away from this in all timezones we take one day off. */
# define USEC_TIMESTAMP_FORMATTABLE_MAX ((usec_t) 253402214399000000)
# define USEC_TIMESTAMP_FORMATTABLE_MAX USEC_TIMESTAMP_FORMATTABLE_MAX_64BIT
#elif SIZEOF_TIME_T == 4
/* With a 32bit time_t we can't go beyond 2038... */
# define USEC_TIMESTAMP_FORMATTABLE_MAX ((usec_t) 2147483647000000)
# define USEC_TIMESTAMP_FORMATTABLE_MAX USEC_TIMESTAMP_FORMATTABLE_MAX_32BIT
#else
# error "Yuck, time_t is neither 4 nor 8 bytes wide?"
#endif

View File

@@ -101,8 +101,8 @@ int main(int argc, char *argv[]) {
test_should_fail("9999-12-31 00:00:00 UTC");
test_should_fail("10000-01-01 00:00:00 UTC");
#elif SIZEOF_TIME_T == 4
test_should_pass("2038-01-19 03:14:07 UTC");
test_should_fail("2038-01-19 03:14:08 UTC");
test_should_pass("2038-01-18 03:14:07 UTC");
test_should_fail("2038-01-18 03:14:08 UTC");
#endif
return 0;

View File

@@ -407,6 +407,10 @@ static void test_format_timestamp_impl(usec_t x) {
static void test_format_timestamp_loop(void) {
test_format_timestamp_impl(USEC_PER_SEC);
test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX_32BIT-1);
test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX_32BIT);
test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX-1);
test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX);
for (unsigned i = 0; i < TRIAL; i++) {
usec_t x;
@@ -617,8 +621,8 @@ TEST(format_timestamp_range) {
test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_US_UTC, "--- XXXX-XX-XX XX:XX:XX.XXXXXX UTC");
test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_DATE, "--- XXXX-XX-XX");
#elif SIZEOF_TIME_T == 4
test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX, TIMESTAMP_UTC, "Tue 2038-01-19 03:14:07 UTC");
test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX, TIMESTAMP_DATE, "Tue 2038-01-19");
test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX, TIMESTAMP_UTC, "Mon 2038-01-18 03:14:07 UTC");
test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX, TIMESTAMP_DATE, "Mon 2038-01-18");
test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_UTC, "--- XXXX-XX-XX XX:XX:XX UTC");
test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_US_UTC, "--- XXXX-XX-XX XX:XX:XX.XXXXXX UTC");
test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_DATE, "--- XXXX-XX-XX");
@@ -632,12 +636,30 @@ static void test_parse_timestamp_one(const char *str, usec_t max_diff, usec_t ex
int r;
r = parse_timestamp(str, &usec);
log_debug("/* %s(%s): max_diff="USEC_FMT", expected="USEC_FMT", result="USEC_FMT"*/", __func__, str, max_diff, expected, usec);
log_debug("/* %s(%s): max_diff="USEC_FMT", expected="USEC_FMT", result="USEC_FMT" */", __func__, str, max_diff, expected, usec);
assert_se(r >= 0);
assert_se(usec >= expected);
assert_se(usec_sub_unsigned(usec, expected) <= max_diff);
}
static bool time_is_zero(usec_t usec) {
const char *s;
s = FORMAT_TIMESTAMP(usec);
return strstr(s, " 00:00:00 ");
}
static bool timezone_equal(usec_t today, usec_t target) {
const char *s, *t, *sz, *tz;
s = FORMAT_TIMESTAMP(today);
t = FORMAT_TIMESTAMP(target);
assert_se(sz = strrchr(s, ' '));
assert_se(tz = strrchr(t, ' '));
log_debug("%s("USEC_FMT", "USEC_FMT") -> %s, %s", __func__, today, target, s, t);
return streq(sz, tz);
}
static void test_parse_timestamp_impl(const char *tz) {
usec_t today, now_usec;
@@ -819,12 +841,17 @@ static void test_parse_timestamp_impl(const char *tz) {
/* without date */
assert_se(parse_timestamp("today", &today) == 0);
test_parse_timestamp_one("00:01", 0, today + USEC_PER_MINUTE);
test_parse_timestamp_one("00:00:01", 0, today + USEC_PER_SEC);
test_parse_timestamp_one("00:00:01.001", 0, today + USEC_PER_SEC + 1000);
test_parse_timestamp_one("00:00:01.0010", 0, today + USEC_PER_SEC + 1000);
test_parse_timestamp_one("tomorrow", 0, today + USEC_PER_DAY);
test_parse_timestamp_one("yesterday", 0, today - USEC_PER_DAY);
if (time_is_zero(today)) {
test_parse_timestamp_one("00:01", 0, today + USEC_PER_MINUTE);
test_parse_timestamp_one("00:00:01", 0, today + USEC_PER_SEC);
test_parse_timestamp_one("00:00:01.001", 0, today + USEC_PER_SEC + 1000);
test_parse_timestamp_one("00:00:01.0010", 0, today + USEC_PER_SEC + 1000);
if (timezone_equal(today, today + USEC_PER_DAY) && time_is_zero(today + USEC_PER_DAY))
test_parse_timestamp_one("tomorrow", 0, today + USEC_PER_DAY);
if (timezone_equal(today, today - USEC_PER_DAY) && time_is_zero(today - USEC_PER_DAY))
test_parse_timestamp_one("yesterday", 0, today - USEC_PER_DAY);
}
/* relative */
assert_se(parse_timestamp("now", &now_usec) == 0);