From 7980a6d1007a3c561610efd413c1b8436b862c25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Helleu?= Date: Sat, 30 Aug 2025 11:51:20 +0200 Subject: [PATCH] api: add support of date like ISO 8601 but with spaces in function util_parse_time So for example the format "2024-01-04 22:01:02.123456 +0100" is supported in addition to ""2024-01-04T22:01:02.123456+0100". --- CHANGELOG.md | 1 + doc/en/weechat_plugin_api.en.adoc | 2 +- doc/fr/weechat_plugin_api.fr.adoc | 2 +- doc/it/weechat_plugin_api.it.adoc | 2 +- doc/ja/weechat_plugin_api.ja.adoc | 2 +- doc/sr/weechat_plugin_api.sr.adoc | 2 +- src/core/core-util.c | 198 ++++++++++++++++++++++------- tests/unit/core/test-core-util.cpp | 115 +++++++++++++++++ 8 files changed, 275 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01b0e4833..6fdfee9ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ SPDX-License-Identifier: GPL-3.0-or-later ### Changed +- api: add support of date like ISO 8601 but with spaces in function util_parse_time - build: require Curl ≥ 7.68.0 ([#2268](https://github.com/weechat/weechat/issues/2268)) - build: require GnuTLS ≥ 3.6.3 ([#2268](https://github.com/weechat/weechat/issues/2268)) - build: require libgcrypt ≥ 1.8.0 ([#2268](https://github.com/weechat/weechat/issues/2268)) diff --git a/doc/en/weechat_plugin_api.en.adoc b/doc/en/weechat_plugin_api.en.adoc index 0ec146f58..863702d65 100644 --- a/doc/en/weechat_plugin_api.en.adoc +++ b/doc/en/weechat_plugin_api.en.adoc @@ -4847,7 +4847,7 @@ This function is not available in scripting API. ==== util_parse_time -_WeeChat ≥ 4.2.0._ +_WeeChat ≥ 4.2.0, updated in 4.8.0._ Parse date/time with support of microseconds. diff --git a/doc/fr/weechat_plugin_api.fr.adoc b/doc/fr/weechat_plugin_api.fr.adoc index 9217ca5b4..85386d884 100644 --- a/doc/fr/weechat_plugin_api.fr.adoc +++ b/doc/fr/weechat_plugin_api.fr.adoc @@ -4928,7 +4928,7 @@ Cette fonction n'est pas disponible dans l'API script. ==== util_parse_time -_WeeChat ≥ 4.2.0._ +_WeeChat ≥ 4.2.0, mis à jour dans la 4.8.0._ Analyser la date/heure avec le support des microsecondes. diff --git a/doc/it/weechat_plugin_api.it.adoc b/doc/it/weechat_plugin_api.it.adoc index 10410d44c..282f7a4f0 100644 --- a/doc/it/weechat_plugin_api.it.adoc +++ b/doc/it/weechat_plugin_api.it.adoc @@ -5068,7 +5068,7 @@ Questa funzione non è disponibile nelle API per lo scripting. // TRANSLATION MISSING ==== util_parse_time -_WeeChat ≥ 4.2.0._ +_WeeChat ≥ 4.2.0, updated in 4.8.0._ Parse date/time with support of microseconds. diff --git a/doc/ja/weechat_plugin_api.ja.adoc b/doc/ja/weechat_plugin_api.ja.adoc index 51c6a71b1..63606fb7d 100644 --- a/doc/ja/weechat_plugin_api.ja.adoc +++ b/doc/ja/weechat_plugin_api.ja.adoc @@ -4982,7 +4982,7 @@ weechat_util_strftimeval (time, sizeof (time), "%@%FT%T.%fZ", &tv); // TRANSLATION MISSING ==== util_parse_time -_WeeChat ≥ 4.2.0._ +_WeeChat ≥ 4.2.0, updated in 4.8.0._ Parse date/time with support of microseconds. diff --git a/doc/sr/weechat_plugin_api.sr.adoc b/doc/sr/weechat_plugin_api.sr.adoc index cb7bd2f71..073533495 100644 --- a/doc/sr/weechat_plugin_api.sr.adoc +++ b/doc/sr/weechat_plugin_api.sr.adoc @@ -4706,7 +4706,7 @@ weechat_util_strftimeval (time, sizeof (time), "%@%FT%T.%fZ", &tv); ==== util_parse_time -_WeeChat ≥ 4.2.0._ +_WeeChat ≥ 4.2.0, ажурирано у верзији 4.8.0._ Парсира датум/време са подршком за милисекунде. diff --git a/src/core/core-util.c b/src/core/core-util.c index eead38db0..574b67dcc 100644 --- a/src/core/core-util.c +++ b/src/core/core-util.c @@ -271,24 +271,75 @@ util_strftimeval (char *string, int max, const char *format, struct timeval *tv) /* * Parses a date/time string, which can be one of these formats: - * "2024-01-04" -> date at midnight - * "2024-01-04T22:01:02" -> ISO 8601, local time - * "2024-01-04T22:01:02.123" -> ISO 8601, local time, with milliseconds - * "2024-01-04T22:01:02.123456" -> ISO 8601, local time, with microseconds - * "2024-01-04T21:01:02Z" -> ISO 8601, UTC - * "2024-01-04T21:01:02.123Z" -> ISO 8601, UTC, with milliseconds - * "2024-01-04T21:01:02.123456Z" -> ISO 8601, UTC, with microseconds - * "22:01:02" -> current date, local time - * "22:01:02.123" -> current date, local time with milliseconds - * "22.01:02.123456" -> current date, local time with microseconds - * "21:01:02Z" -> current date, UTC - * "21:01:02.123Z" -> current date, UTC, with milliseconds - * "21.01:02.123456Z" -> current date, UTC, with microseconds - * "1704402062" -> timestamp date - * "1704402062.123" -> timestamp date, with milliseconds - * "1704402062,123" -> timestamp date, with milliseconds - * "1704402062.123456" -> timestamp date, with microseconds - * "1704402062,123456" -> timestamp date, with microseconds + * + * "2024-01-04" -> date at midnight + * + * "2024-01-04T22:01:02" -> ISO 8601, local time + * "2024-01-04T22:01:02.123" -> ISO 8601, local time, milliseconds + * "2024-01-04T22:01:02.123456" -> ISO 8601, local time, microseconds + * + * "2024-01-04T22:01:02+0100" -> ISO 8601, local time + offset + * "2024-01-04T22:01:02+01:00" -> ISO 8601, local time + offset + * "2024-01-04T22:01:02.123+0100" -> ISO 8601, local time + offset, milliseconds + * "2024-01-04T22:01:02.123+01:00" -> ISO 8601, local time + offset, milliseconds + * "2024-01-04T22:01:02.123456+0100" -> ISO 8601, local time + offset, microseconds + * "2024-01-04T22:01:02.123456+01:00" -> ISO 8601, local time + offset, microseconds + * + * "2024-01-04T21:01:02Z" -> ISO 8601, UTC + * "2024-01-04T21:01:02.123Z" -> ISO 8601, UTC, milliseconds + * "2024-01-04T21:01:02.123456Z" -> ISO 8601, UTC, microseconds + * + * "2024-01-04 22:01:02" -> ~ISO 8601 (space), local time + * "2024-01-04 22:01:02.123" -> ~ISO 8601 (space), local time, milliseconds + * "2024-01-04 22:01:02.123456" -> ~ISO 8601 (space), local time, microseconds + * + * "2024-01-04 22:01:02+0100" -> ~ISO 8601 (space), local time + offset + * "2024-01-04 22:01:02+01:00" -> ~ISO 8601 (space), local time + offset + * "2024-01-04 22:01:02 +0100" -> ~ISO 8601 (space), local time + offset + * "2024-01-04 22:01:02 +01:00" -> ~ISO 8601 (space), local time + offset + * "2024-01-04 22:01:02.123" -> ~ISO 8601 (space), local time + offset, milliseconds + * "2024-01-04 22:01:02.123+0100" -> ~ISO 8601 (space), local time + offset, milliseconds + * "2024-01-04 22:01:02.123+01:00" -> ~ISO 8601 (space), local time + offset, milliseconds + * "2024-01-04 22:01:02.123 +0100" -> ~ISO 8601 (space), local time + offset, milliseconds + * "2024-01-04 22:01:02.123 +01:00" -> ~ISO 8601 (space), local time + offset, milliseconds + * "2024-01-04 22:01:02.123456" -> ~ISO 8601 (space), local time + offset, microseconds + * "2024-01-04 22:01:02.123456+0100" -> ~ISO 8601 (space), local time + offset, microseconds + * "2024-01-04 22:01:02.123456+01:00" -> ~ISO 8601 (space), local time + offset, microseconds + * "2024-01-04 22:01:02.123456 +0100" -> ~ISO 8601 (space), local time + offset, microseconds + * "2024-01-04 22:01:02.123456 +01:00" -> ~ISO 8601 (space), local time + offset, microseconds + * + * "2024-01-04 21:01:02Z" -> ~ISO 8601 (space), UTC + * "2024-01-04 21:01:02.123Z" -> ~ISO 8601 (space), UTC, milliseconds + * "2024-01-04 21:01:02.123456Z" -> ~ISO 8601 (space), UTC, microseconds + * + * "22:01:02" -> current date, local time + * "22:01:02.123" -> current date, local time, milliseconds + * "22:01:02.123456" -> current date, local time, microseconds + * + * "22:01:02+0100" -> current date, local time + offset + * "22:01:02+01:00" -> current date, local time + offset + * "22:01:02 +0100" -> current date, local time + offset + * "22:01:02 +01:00" -> current date, local time + offset + * "22:01:02.123" -> current date, local time + offset, milliseconds + * "22:01:02.123+0100" -> current date, local time + offset, milliseconds + * "22:01:02.123+01:00" -> current date, local time + offset, milliseconds + * "22:01:02.123 +0100" -> current date, local time + offset, milliseconds + * "22:01:02.123 +01:00" -> current date, local time + offset, milliseconds + * "22:01:02.123456" -> current date, local time + offset, microseconds + * "22:01:02.123456+0100" -> current date, local time + offset, microseconds + * "22:01:02.123456+01:00" -> current date, local time + offset, microseconds + * "22:01:02.123456 +0100" -> current date, local time + offset, microseconds + * "22:01:02.123456 +01:00" -> current date, local time + offset, microseconds + * + * "21:01:02Z" -> current date, UTC + * "21:01:02.123Z" -> current date, UTC, milliseconds + * "21:01:02.123456Z" -> current date, UTC, microseconds + * + * "1704402062" -> timestamp date + * "1704402062.123" -> timestamp date, milliseconds + * "1704402062,123" -> timestamp date, milliseconds + * "1704402062.123456" -> timestamp date, microseconds + * "1704402062,123456" -> timestamp date, microseconds * * Returns: * 1: OK @@ -298,7 +349,7 @@ util_strftimeval (char *string, int max, const char *format, struct timeval *tv) int util_parse_time (const char *datetime, struct timeval *tv) { - char *string, *pos, *pos2, str_usec[16], *error; + char *string, *pos, *pos2, *pos_colon, *pos_hyphen, str_usec[16], *error; char str_date[128], str_date2[256]; struct tm tm_date, tm_date_gm, tm_date_local, *local_time; time_t time_now, time_gm, time_local; @@ -317,11 +368,35 @@ util_parse_time (const char *datetime, struct timeval *tv) timezone_offset = 0; offset_factor = 1; - string = strdup (datetime); - if (!string) - return 0; + pos_colon = strchr (datetime, ':'); + pos_hyphen = strchr (datetime, '-'); + if (pos_colon && !pos_hyphen) + { + /* add current date: "21:01:02" -> "2024-01-04T21:01:02" */ + string = malloc (strlen (datetime) + 16 + 1); + if (!string) + return 0; + time_now = time (NULL); + local_time = localtime (&time_now); + strftime (str_date, sizeof (str_date), "%Y-%m-%dT", local_time); + snprintf (string, sizeof (str_date2), "%s%s", str_date, datetime); + } + else if (!pos_colon && pos_hyphen) + { + /* add time (midnight): "2024-01-04" -> "2024-01-04T00:00:00" */ + string = malloc (strlen (datetime) + 16 + 1); + if (!string) + return 0; + snprintf (string, sizeof (str_date2), "%sT00:00:00", datetime); + } + else + { + string = strdup (datetime); + if (!string) + return 0; + } - /* extract microseconds and remove them from string2 */ + /* extract microseconds and remove them from string */ pos = strchr (string, '.'); if (!pos) pos = strchr (string, ','); @@ -347,6 +422,10 @@ util_parse_time (const char *datetime, struct timeval *tv) value = strtoll (str_usec, &error, 10); if (error && !error[0]) { + /* + * just in case: this should not happen as minus is not + * supported and we truncate at 6 digits + */ if (value < 0) value = 0; else if (value > 999999) @@ -358,7 +437,7 @@ util_parse_time (const char *datetime, struct timeval *tv) } /* extract timezone and remove it from string2 */ - pos = strchr (string, 'Z'); + pos = strrchr (string, 'Z'); if (pos) { pos[0] = '\0'; @@ -368,6 +447,8 @@ util_parse_time (const char *datetime, struct timeval *tv) else { pos = strchr (string, 'T'); + if (!pos) + pos = strchr (string, ' '); if (pos) { pos2 = strchr (pos, '+'); @@ -414,29 +495,59 @@ util_parse_time (const char *datetime, struct timeval *tv) { if (strchr (string, ':')) { - /* ISO 8601 format like: "2024-01-04T21:01:02.123Z" */ - /* initialize structure, because strptime does not do it */ - memset (&tm_date, 0, sizeof (struct tm)); - pos = strptime (string, "%Y-%m-%dT%H:%M:%S", &tm_date); - if (pos && (tm_date.tm_year > 0)) + if (strchr (string, 'T')) { - if (use_local_time) + /* ISO 8601 format like: "2024-01-04T21:01:02.123Z" */ + /* initialize structure, because strptime does not do it */ + memset (&tm_date, 0, sizeof (struct tm)); + pos = strptime (string, "%Y-%m-%dT%H:%M:%S", &tm_date); + if (pos && (tm_date.tm_year > 0)) { - tv->tv_sec = mktime (&tm_date); + if (use_local_time) + { + tv->tv_sec = mktime (&tm_date); + } + else + { + /* convert to UTC and add timezone_offset */ + time_now = mktime (&tm_date); + gmtime_r (&time_now, &tm_date_gm); + localtime_r (&time_now, &tm_date_local); + time_gm = mktime (&tm_date_gm); + time_local = mktime (&tm_date_local); + tv->tv_sec = mktime (&tm_date_local) + + (time_local - time_gm) + + timezone_offset; + } + rc = 1; } - else + } + else + { + /* like ISO 8601 but with space like: "2024-01-04 21:01:02.123Z" */ + /* initialize structure, because strptime does not do it */ + memset (&tm_date, 0, sizeof (struct tm)); + pos = strptime (string, "%Y-%m-%d %H:%M:%S", &tm_date); + if (pos && (tm_date.tm_year > 0)) { - /* convert to UTC and add timezone_offset */ - time_now = mktime (&tm_date); - gmtime_r (&time_now, &tm_date_gm); - localtime_r (&time_now, &tm_date_local); - time_gm = mktime (&tm_date_gm); - time_local = mktime (&tm_date_local); - tv->tv_sec = mktime (&tm_date_local) - + (time_local - time_gm) - + timezone_offset; + if (use_local_time) + { + tv->tv_sec = mktime (&tm_date); + } + else + { + /* convert to UTC and add timezone_offset */ + time_now = mktime (&tm_date); + gmtime_r (&time_now, &tm_date_gm); + localtime_r (&time_now, &tm_date_local); + time_gm = mktime (&tm_date_gm); + time_local = mktime (&tm_date_local); + tv->tv_sec = mktime (&tm_date_local) + + (time_local - time_gm) + + timezone_offset; + } + rc = 1; } - rc = 1; } } else @@ -457,8 +568,7 @@ util_parse_time (const char *datetime, struct timeval *tv) /* hour format like: "21:01:02" */ time_now = time (NULL); local_time = localtime (&time_now); - strftime (str_date, sizeof (str_date), - "%Y-%m-%dT", local_time); + strftime (str_date, sizeof (str_date), "%Y-%m-%dT", local_time); snprintf (str_date2, sizeof (str_date2), "%s%s", str_date, string); /* initialize structure, because strptime does not do it */ memset (&tm_date, 0, sizeof (struct tm)); diff --git a/tests/unit/core/test-core-util.cpp b/tests/unit/core/test-core-util.cpp index 04bb14554..f7c808bdc 100644 --- a/tests/unit/core/test-core-util.cpp +++ b/tests/unit/core/test-core-util.cpp @@ -300,6 +300,9 @@ TEST(CoreUtil, ParseTime) WEE_PARSE_DATE(0, 0, 0, ""); WEE_PARSE_DATE(0, 0, 0, "invalid"); + /* invalid: negative microseconds */ + WEE_PARSE_DATE(0, 0, 0, "1703500149.-456789"); + /* * expected: 2023-12-25T00:00:00Z == 1703462400 * (local timezone UTC+1: 1703466000) @@ -321,6 +324,49 @@ TEST(CoreUtil, ParseTime) CHECK((tv.tv_sec >= date) && (tv.tv_sec <= date + 10)); LONGS_EQUAL(456789, tv.tv_usec); + /* expected: current date with specified local time + timezone offset */ + date = time (NULL); + local_time = localtime (&date); + strftime (str_time, sizeof (str_time), "%H:%M:%S+0100", local_time); + LONGS_EQUAL(1, util_parse_time (str_time, &tv)); + CHECK((tv.tv_sec >= date) && (tv.tv_sec <= date + 10)); + LONGS_EQUAL(0, tv.tv_usec); + + date = time (NULL); + local_time = localtime (&date); + strftime (str_time, sizeof (str_time), "%H:%M:%S +01:00", local_time); + LONGS_EQUAL(1, util_parse_time (str_time, &tv)); + CHECK((tv.tv_sec >= date) && (tv.tv_sec <= date + 10)); + LONGS_EQUAL(0, tv.tv_usec); + + date = time (NULL); + local_time = localtime (&date); + strftime (str_time, sizeof (str_time), "%H:%M:%S +02:00", local_time); + LONGS_EQUAL(1, util_parse_time (str_time, &tv)); + CHECK((tv.tv_sec >= date + 3600) && (tv.tv_sec <= date + 3600 + 10)); + LONGS_EQUAL(0, tv.tv_usec); + + date = time (NULL); + local_time = localtime (&date); + strftime (str_time, sizeof (str_time), "%H:%M:%S.456789+0100", local_time); + LONGS_EQUAL(1, util_parse_time (str_time, &tv)); + CHECK((tv.tv_sec >= date) && (tv.tv_sec <= date + 10)); + LONGS_EQUAL(456789, tv.tv_usec); + + date = time (NULL); + local_time = localtime (&date); + strftime (str_time, sizeof (str_time), "%H:%M:%S.456789 +01:00", local_time); + LONGS_EQUAL(1, util_parse_time (str_time, &tv)); + CHECK((tv.tv_sec >= date) && (tv.tv_sec <= date + 10)); + LONGS_EQUAL(456789, tv.tv_usec); + + date = time (NULL); + local_time = localtime (&date); + strftime (str_time, sizeof (str_time), "%H:%M:%S.456789 +02:00", local_time); + LONGS_EQUAL(1, util_parse_time (str_time, &tv)); + CHECK((tv.tv_sec >= date + 3600) && (tv.tv_sec <= date + 3600 + 10)); + LONGS_EQUAL(456789, tv.tv_usec); + /* expected: current date with specified UTC time */ date = time (NULL); local_time = localtime (&date); @@ -345,6 +391,16 @@ TEST(CoreUtil, ParseTime) WEE_PARSE_DATE(1, 1703500149, 456000, "2023-12-25T10:29:09.456Z"); WEE_PARSE_DATE(1, 1703500149, 456789, "2023-12-25T10:29:09.456789Z"); + /* + * expected: 2023-12-25T10:29:09.456789Z == 1703500149.456789 + * (local timezone UTC+1: 1703503749.456789) + * with space instead of "T" + */ + WEE_PARSE_DATE(1, 1703500149 + 3600, 0, "2023-12-25 10:29:09"); + WEE_PARSE_DATE(1, 1703500149, 0, "2023-12-25 10:29:09Z"); + WEE_PARSE_DATE(1, 1703500149, 456000, "2023-12-25 10:29:09.456Z"); + WEE_PARSE_DATE(1, 1703500149, 456789, "2023-12-25 10:29:09.456789Z"); + /* * expected: 2023-12-25T10:29:09.456789Z == 1703500149.456789 * with timezone offset @@ -372,6 +428,60 @@ TEST(CoreUtil, ParseTime) WEE_PARSE_DATE(1, 1703500149 - 3600 - 1800, 0, "2023-12-25T10:29:09-01:30"); WEE_PARSE_DATE(1, 1703500149 - 3600 - 1800, 456789, "2023-12-25T10:29:09.456789-01:30"); + /* + * expected: 2023-12-25T10:29:09.456789Z == 1703500149.456789 + * with space instead of "T" and timezone offset + */ + WEE_PARSE_DATE(1, 1703500149, 0, "2023-12-25 10:29:09+00"); + WEE_PARSE_DATE(1, 1703500149, 0, "2023-12-25 10:29:09+0000"); + WEE_PARSE_DATE(1, 1703500149, 0, "2023-12-25 10:29:09+00:00"); + WEE_PARSE_DATE(1, 1703500149, 0, "2023-12-25 10:29:09-00"); + WEE_PARSE_DATE(1, 1703500149, 0, "2023-12-25 10:29:09-0000"); + WEE_PARSE_DATE(1, 1703500149, 0, "2023-12-25 10:29:09-00:00"); + WEE_PARSE_DATE(1, 1703500149, 456789, "2023-12-25 10:29:09.456789-00:00"); + + WEE_PARSE_DATE(1, 1703500149 + 7200, 0, "2023-12-25 10:29:09+02"); + WEE_PARSE_DATE(1, 1703500149 + 60, 0, "2023-12-25 10:29:09+0001"); + WEE_PARSE_DATE(1, 1703500149 + 60, 456789, "2023-12-25 10:29:09.456789+0001"); + + WEE_PARSE_DATE(1, 1703500149 + 7200, 0, "2023-12-25 10:29:09+0200"); + WEE_PARSE_DATE(1, 1703500149 + 7200, 0, "2023-12-25 10:29:09+02:00"); + WEE_PARSE_DATE(1, 1703500149 + 3600 + 1800, 0, "2023-12-25 10:29:09+0130"); + WEE_PARSE_DATE(1, 1703500149 + 3600 + 1800, 0, "2023-12-25 10:29:09+01:30"); + WEE_PARSE_DATE(1, 1703500149 + 3600 + 1800, 456789, "2023-12-25 10:29:09.456789+01:30"); + + WEE_PARSE_DATE(1, 1703500149 - 60, 0, "2023-12-25 10:29:09-0001"); + WEE_PARSE_DATE(1, 1703500149 - 3600 - 1800, 0, "2023-12-25 10:29:09-0130"); + WEE_PARSE_DATE(1, 1703500149 - 3600 - 1800, 0, "2023-12-25 10:29:09-01:30"); + WEE_PARSE_DATE(1, 1703500149 - 3600 - 1800, 456789, "2023-12-25 10:29:09.456789-01:30"); + + /* + * expected: 2023-12-25T10:29:09.456789Z == 1703500149.456789 + * with space instead of "T" and timezone offset after a space + */ + WEE_PARSE_DATE(1, 1703500149, 0, "2023-12-25 10:29:09 +00"); + WEE_PARSE_DATE(1, 1703500149, 0, "2023-12-25 10:29:09 +0000"); + WEE_PARSE_DATE(1, 1703500149, 0, "2023-12-25 10:29:09 +00:00"); + WEE_PARSE_DATE(1, 1703500149, 0, "2023-12-25 10:29:09 -00"); + WEE_PARSE_DATE(1, 1703500149, 0, "2023-12-25 10:29:09 -0000"); + WEE_PARSE_DATE(1, 1703500149, 0, "2023-12-25 10:29:09 -00:00"); + WEE_PARSE_DATE(1, 1703500149, 456789, "2023-12-25 10:29:09.456789 -00:00"); + + WEE_PARSE_DATE(1, 1703500149 + 7200, 0, "2023-12-25 10:29:09 +02"); + WEE_PARSE_DATE(1, 1703500149 + 60, 0, "2023-12-25 10:29:09 +0001"); + WEE_PARSE_DATE(1, 1703500149 + 60, 456789, "2023-12-25 10:29:09.456789 +0001"); + + WEE_PARSE_DATE(1, 1703500149 + 7200, 0, "2023-12-25 10:29:09 +0200"); + WEE_PARSE_DATE(1, 1703500149 + 7200, 0, "2023-12-25 10:29:09 +02:00"); + WEE_PARSE_DATE(1, 1703500149 + 3600 + 1800, 0, "2023-12-25 10:29:09 +0130"); + WEE_PARSE_DATE(1, 1703500149 + 3600 + 1800, 0, "2023-12-25 10:29:09 +01:30"); + WEE_PARSE_DATE(1, 1703500149 + 3600 + 1800, 456789, "2023-12-25 10:29:09.456789 +01:30"); + + WEE_PARSE_DATE(1, 1703500149 - 60, 0, "2023-12-25 10:29:09 -0001"); + WEE_PARSE_DATE(1, 1703500149 - 3600 - 1800, 0, "2023-12-25 10:29:09 -0130"); + WEE_PARSE_DATE(1, 1703500149 - 3600 - 1800, 0, "2023-12-25 10:29:09 -01:30"); + WEE_PARSE_DATE(1, 1703500149 - 3600 - 1800, 456789, "2023-12-25 10:29:09.456789 -01:30"); + /* expected: 2023-12-25T10:29:09.456789Z == 1703500149.456789 */ WEE_PARSE_DATE(1, 1703500149, 0, "1703500149"); WEE_PARSE_DATE(1, 1703500149, 456000, "1703500149.456"); @@ -379,6 +489,11 @@ TEST(CoreUtil, ParseTime) WEE_PARSE_DATE(1, 1703500149, 456000, "1703500149,456"); WEE_PARSE_DATE(1, 1703500149, 456789, "1703500149,456789"); + /* expected: 2023-12-25T10:29:09.456789Z == 1703500149.456789 */ + /* with extra digits after microseconds */ + WEE_PARSE_DATE(1, 1703500149, 456789, "1703500149.4567891"); + WEE_PARSE_DATE(1, 1703500149, 456789, "1703500149.456789123456789123456789123456789"); + setenv ("TZ", "", 1); }