* [PATCH v5 0/2] Support dates outside of 1901..2038 range
@ 2025-08-27 2:11 Andrew Hamilton
2025-08-27 2:11 ` [PATCH v5 1/2] datetime: " Andrew Hamilton
2025-08-27 2:11 ` [PATCH v5 2/2] date_unit_test: test dates outside of 32-bit unix range Andrew Hamilton
0 siblings, 2 replies; 7+ messages in thread
From: Andrew Hamilton @ 2025-08-27 2:11 UTC (permalink / raw)
To: grub-devel
Cc: daniel.kiper, masayuki.moriyama, andrea.biardi, phcoder,
Andrew Hamilton
Support dates outside of 1901..2038.
Add tests for dates outside this range.
Vast majority of the work was done by Vladimir Serbinenko
Fixes: https://savannah.gnu.org/bugs/?63894
Fixes: https://savannah.gnu.org/bugs/?66301
V4 -> V5:
datetime.c / h:
Rename variables "is_bisextile" to "bisextile".
Change some boolean assignments to use ternary operator.
Compare booleans to true instead of checking "if(boolean)".
date_unit_test.c:
Add additional commentary to the tests array for meaning of numbers.
Rework test ranges to cover from years 0001 to 9999 and add specific
min/max tests for min 0001 date and max 9999 date.
V3 -> V4: Add additional commentary for a few magic numbers
and fix some coding standard issues.
V2 -> V3: Added additional commentary to datetime.c to describe
the origin of some of the numbers used in calculations.
Andrew Hamilton (2):
datetime: Support dates outside of 1901..2038 range
date_unit_test: test dates outside of 32-bit unix range
grub-core/lib/datetime.c | 65 +++++++++++++++++++++++++++-------
include/grub/datetime.h | 28 ++++++++++-----
tests/date_unit_test.c | 75 +++++++++++++++++++++++++++++++++++-----
3 files changed, 139 insertions(+), 29 deletions(-)
--
2.39.5
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v5 1/2] datetime: Support dates outside of 1901..2038 range
2025-08-27 2:11 [PATCH v5 0/2] Support dates outside of 1901..2038 range Andrew Hamilton
@ 2025-08-27 2:11 ` Andrew Hamilton
2025-08-27 13:46 ` Daniel Kiper via Grub-devel
2025-08-27 2:11 ` [PATCH v5 2/2] date_unit_test: test dates outside of 32-bit unix range Andrew Hamilton
1 sibling, 1 reply; 7+ messages in thread
From: Andrew Hamilton @ 2025-08-27 2:11 UTC (permalink / raw)
To: grub-devel
Cc: daniel.kiper, masayuki.moriyama, andrea.biardi, phcoder,
Andrew Hamilton
Support dates outside of 1901..2038.
Fixes: https://savannah.gnu.org/bugs/?63894
Fixes: https://savannah.gnu.org/bugs/?66301
Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
Signed-off-by: Andrew Hamilton <adhamilt@gmail.com>
---
grub-core/lib/datetime.c | 65 ++++++++++++++++++++++++++++++++--------
include/grub/datetime.h | 28 ++++++++++++-----
2 files changed, 73 insertions(+), 20 deletions(-)
diff --git a/grub-core/lib/datetime.c b/grub-core/lib/datetime.c
index 8f0922fb0..eb9a8d9c9 100644
--- a/grub-core/lib/datetime.c
+++ b/grub-core/lib/datetime.c
@@ -64,7 +64,10 @@ grub_get_weekday_name (struct grub_datetime *datetime)
#define SECPERDAY (24*SECPERHOUR)
#define DAYSPERYEAR 365
#define DAYSPER4YEARS (4*DAYSPERYEAR+1)
-
+/* 24 leap years in 100 years */
+#define DAYSPER100YEARS (100 * DAYSPERYEAR + 24)
+/* 97 leap years in 400 years */
+#define DAYSPER400YEARS (400 * DAYSPERYEAR + 97)
void
grub_unixtime2datetime (grub_int64_t nix, struct grub_datetime *datetime)
@@ -76,10 +79,12 @@ grub_unixtime2datetime (grub_int64_t nix, struct grub_datetime *datetime)
/* Convenience: let's have 3 consecutive non-bissextile years
at the beginning of the counting date. So count from 1901. */
int days_epoch;
- /* Number of days since 1st Januar, 1901. */
+ /* Number of days since 1st January, 1 (proleptic). */
unsigned days;
/* Seconds into current day. */
unsigned secs_in_day;
+ /* Tracks whether this is a leap year. */
+ bool bisextile;
/* Transform C divisions and modulos to mathematical ones */
if (nix < 0)
@@ -92,27 +97,63 @@ grub_unixtime2datetime (grub_int64_t nix, struct grub_datetime *datetime)
days_epoch = grub_divmod64 (nix, SECPERDAY, NULL);
secs_in_day = nix - days_epoch * SECPERDAY;
- days = days_epoch + 69 * DAYSPERYEAR + 17;
+ /*
+ * 1970 is Unix Epoch. Adjust to a year 1 epoch:
+ * Leap year logic:
+ * - Years evenly divisible by 400 are leap years
+ * - Otherwise, if divisible by 100 are not leap years
+ * - Otherwise, if divisible by 4 are leap years
+ * There are four 400-year periods (1600 years worth of days with leap days)
+ * There are three 100-year periods worth of leap days (3*24)
+ * There are 369 years in addition to the four 400 year periods
+ * There are 17 leap days in 69 years (beyond the three 100 year periods)
+ */
+ days = days_epoch + 369 * DAYSPERYEAR + 17 + 24 * 3 + 4 * DAYSPER400YEARS;
+
+ datetime->year = 1 + 400 * (days / DAYSPER400YEARS);
+ days %= DAYSPER400YEARS;
- datetime->year = 1901 + 4 * (days / DAYSPER4YEARS);
+ /*
+ * On 31st December of bissextile (leap) years 365 days from the beginning
+ * of the year elapsed but year isn't finished yet - every 400 years
+ * 396 is 4 years less than 400 year leap cycle
+ * 96 is 1 day less than number of leap days in 400 years
+ */
+ if (days / DAYSPER100YEARS == 4)
+ {
+ datetime->year += 396;
+ days -= 396 * DAYSPERYEAR + 96;
+ }
+ else
+ {
+ datetime->year += 100 * (days / DAYSPER100YEARS);
+ days %= DAYSPER100YEARS;
+ }
+
+ datetime->year += 4 * (days / DAYSPER4YEARS);
days %= DAYSPER4YEARS;
- /* On 31st December of bissextile years 365 days from the beginning
- of the year elapsed but year isn't finished yet */
+ /*
+ * On 31st December of bissextile (leap) years 365 days from the beginning
+ * of the year elapsed but year isn't finished yet - every 4 years
+ */
if (days / DAYSPERYEAR == 4)
{
datetime->year += 3;
- days -= 3*DAYSPERYEAR;
+ days -= 3 * DAYSPERYEAR;
}
else
{
datetime->year += days / DAYSPERYEAR;
days %= DAYSPERYEAR;
}
- for (i = 0; i < 12
- && days >= (i==1 && datetime->year % 4 == 0
- ? 29 : months[i]); i++)
- days -= (i==1 && datetime->year % 4 == 0
- ? 29 : months[i]);
+
+ bisextile = (datetime->year % 4 == 0
+ && (datetime->year % 100 != 0
+ || datetime->year % 400 == 0)) ? true : false;
+ for (i = 0;
+ i < 12 && days >= ((i == 1 && bisextile == true) ? 29 : months[i]);
+ i++)
+ days -= ((i == 1 && bisextile == true) ? 29 : months[i]);
datetime->month = i + 1;
datetime->day = 1 + days;
datetime->hour = (secs_in_day / SECPERHOUR);
diff --git a/include/grub/datetime.h b/include/grub/datetime.h
index bcec636f0..425c015fc 100644
--- a/include/grub/datetime.h
+++ b/include/grub/datetime.h
@@ -54,8 +54,9 @@ void grub_unixtime2datetime (grub_int64_t nix,
static inline int
grub_datetime2unixtime (const struct grub_datetime *datetime, grub_int64_t *nix)
{
- grub_int32_t ret;
+ grub_int64_t ret;
int y4, ay;
+ bool bisextile;
const grub_uint16_t monthssum[12]
= { 0,
31,
@@ -75,15 +76,11 @@ grub_datetime2unixtime (const struct grub_datetime *datetime, grub_int64_t *nix)
const int SECPERHOUR = 60 * SECPERMIN;
const int SECPERDAY = 24 * SECPERHOUR;
const int SECPERYEAR = 365 * SECPERDAY;
- const int SECPER4YEARS = 4 * SECPERYEAR + SECPERDAY;
+ const grub_int64_t SECPER4YEARS = 4 * SECPERYEAR + SECPERDAY;
- if (datetime->year > 2038 || datetime->year < 1901)
- return 0;
if (datetime->month > 12 || datetime->month < 1)
return 0;
- /* In the period of validity of unixtime all years divisible by 4
- are bissextile*/
/* Convenience: let's have 3 consecutive non-bissextile years
at the beginning of the epoch. So count from 1973 instead of 1970 */
ret = 3 * SECPERYEAR + SECPERDAY;
@@ -94,13 +91,28 @@ grub_datetime2unixtime (const struct grub_datetime *datetime, grub_int64_t *nix)
ret += y4 * SECPER4YEARS;
ret += ay * SECPERYEAR;
+ /*
+ * Correct above calculation (which assumes every 4 years is a leap year)
+ * to remove those "false leap years" that are divisible by 100 but not 400.
+ * Since this logic starts with seconds since 1973, 15 is used because:
+ * - (1973 - 1) / 100 = 19 (floor due to integer math)
+ * - (1973 - 1) / 400 = 4 (floor due to integer math)
+ * - 19 - 4 - 15 = 0 (we want to start with no "false leap years" at time
+ * zero of 1973)
+ */
+ ret -= ((datetime->year - 1) / 100 - (datetime->year - 1) / 400 - 15)
+ * SECPERDAY;
+
ret += monthssum[datetime->month - 1] * SECPERDAY;
- if (ay == 3 && datetime->month >= 3)
+ bisextile = (ay == 3
+ && (datetime->year % 100 != 0
+ || datetime->year % 400 == 0)) ? true : false;
+ if (bisextile == true && datetime->month >= 3)
ret += SECPERDAY;
ret += (datetime->day - 1) * SECPERDAY;
if ((datetime->day > months[datetime->month - 1]
- && (!ay || datetime->month != 2 || datetime->day != 29))
+ && !(bisextile == true && datetime->month == 2 && datetime->day == 29))
|| datetime->day < 1)
return 0;
--
2.39.5
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v5 2/2] date_unit_test: test dates outside of 32-bit unix range
2025-08-27 2:11 [PATCH v5 0/2] Support dates outside of 1901..2038 range Andrew Hamilton
2025-08-27 2:11 ` [PATCH v5 1/2] datetime: " Andrew Hamilton
@ 2025-08-27 2:11 ` Andrew Hamilton
2025-08-27 13:51 ` Daniel Kiper via Grub-devel
1 sibling, 1 reply; 7+ messages in thread
From: Andrew Hamilton @ 2025-08-27 2:11 UTC (permalink / raw)
To: grub-devel
Cc: daniel.kiper, masayuki.moriyama, andrea.biardi, phcoder,
Andrew Hamilton
Add tests outside the date range possible with 32-bit time
calculation. Also add a few more nominal date/time test values
to the 32-bit "tests" array. Add min / max tests for years 0001
and 9999.
Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
Signed-off-by: Andrew Hamilton <adhamilt@gmail.com>
---
tests/date_unit_test.c | 75 +++++++++++++++++++++++++++++++++++++-----
1 file changed, 66 insertions(+), 9 deletions(-)
diff --git a/tests/date_unit_test.c b/tests/date_unit_test.c
index 99774f199..d3bf5a712 100644
--- a/tests/date_unit_test.c
+++ b/tests/date_unit_test.c
@@ -25,12 +25,13 @@
#include <grub/test.h>
static void
-date_test (grub_int32_t v)
+date_test (grub_int64_t v)
{
struct grub_datetime dt;
time_t t = v;
struct tm *g;
int w;
+ grub_int64_t back = 0;
g = gmtime (&t);
@@ -38,28 +39,56 @@ date_test (grub_int32_t v)
w = grub_get_weekday (&dt);
- grub_test_assert (g->tm_sec == dt.second, "time %d bad second: %d vs %d", v,
+ grub_datetime2unixtime (&dt, &back);
+
+ grub_test_assert (g->tm_sec == dt.second, "time %lld bad second: %d vs %d", (long long) v,
g->tm_sec, dt.second);
- grub_test_assert (g->tm_min == dt.minute, "time %d bad minute: %d vs %d", v,
+ grub_test_assert (g->tm_min == dt.minute, "time %lld bad minute: %d vs %d", (long long) v,
g->tm_min, dt.minute);
- grub_test_assert (g->tm_hour == dt.hour, "time %d bad hour: %d vs %d", v,
+ grub_test_assert (g->tm_hour == dt.hour, "time %lld bad hour: %d vs %d", (long long) v,
g->tm_hour, dt.hour);
- grub_test_assert (g->tm_mday == dt.day, "time %d bad day: %d vs %d", v,
+ grub_test_assert (g->tm_mday == dt.day, "time %lld bad day: %d vs %d", (long long) v,
g->tm_mday, dt.day);
- grub_test_assert (g->tm_mon + 1 == dt.month, "time %d bad month: %d vs %d", v,
+ grub_test_assert (g->tm_mon + 1 == dt.month, "time %lld bad month: %d vs %d",(long long) v,
g->tm_mon + 1, dt.month);
grub_test_assert (g->tm_year + 1900 == dt.year,
- "time %d bad year: %d vs %d", v,
+ "time %lld bad year: %d vs %d", (long long) v,
g->tm_year + 1900, dt.year);
- grub_test_assert (g->tm_wday == w, "time %d bad week day: %d vs %d", v,
+ grub_test_assert (g->tm_wday == w, "time %lld bad week day: %d vs %d", (long long) v,
g->tm_wday, w);
+ grub_test_assert (back == v, "time %lld bad back transform: %lld", (long long) v,
+ (long long) back);
}
static void
date_test_iter (void)
{
- grub_int32_t tests[] = { -1, 0, +1, -2133156255, GRUB_INT32_MIN,
+ /*
+ * Test several interesting UNIX timestamps in 32-bit time:
+ * 1. -1: 1969-12-31 23:59:59 - Just before EPOCH
+ * 2. 0: 1970-01-01 00:00:00 - EPOCH
+ * 3. +1: 1970-01-01 00:00:01 - Just after EPOCH
+ * 4. 978224552: 2000-12-31 01:02:32 - Leap year, prior to Feb
+ * 5. -2133156255: 1902-05-28 16:35:45 - Nominal value
+ * 6. -2110094321: 1903-02-19 14:41:19 - Nominal value
+ * 7. GRUB_INT32_MIN: 1901-12-13 20:45:52 - 32-bit Min value
+ * 8. GRUB_INT32_MAX: 2038-01-19 03:14:07 - 32-bit Max value
+ */
+ grub_int32_t tests[] = { -1, 0, +1, 978224552, -2133156255, -2110094321, GRUB_INT32_MIN,
GRUB_INT32_MAX };
+ /*
+ * Test several known UNIX timestamps outside 32-bit time:
+ * 1. 5774965200: 2152-12-31 21:00:00 - Leap year
+ * 2. 4108700725: 2100-03-14 09:45:25 - Not a leap year
+ * 3. -5029179792: 1810-08-19 21:36:48 - Not a leap year
+ * 4. -62135596799: 0001-01-01 00:00:00 - Minimum AD
+ * 5. 253402300799: 9999-12-31 23:59:59 - Maximum 4 digit year
+ */
+ grub_int64_t tests64[] = { (grub_int64_t) 5774965200,
+ (grub_int64_t) 4108700725,
+ (grub_int64_t) -5029179792,
+ (grub_int64_t) -62135596799,
+ (grub_int64_t) 253402300799 };
unsigned i;
for (i = 0; i < ARRAY_SIZE (tests); i++)
@@ -71,6 +100,34 @@ date_test_iter (void)
date_test (x);
date_test (-x);
}
+
+ if (sizeof (time_t) > 4)
+ {
+ for (i = 0; i < ARRAY_SIZE (tests64); i++)
+ date_test (tests64[i]);
+ for (i = 0; i < 5000000; i++)
+ {
+ /*
+ * Test some pseudo-random dates/times between 1970 and 9999
+ * "117" is used to scale the random 32-bit int from range
+ * 0..2147483648 to 0..251255586816. This is reasonably
+ * close to max 9999 date represented by 253402300799.
+ */
+ grub_int64_t x = (grub_int64_t) rand () * (grub_int64_t) 117;
+ date_test (x);
+ }
+ for (i = 0; i < 5000000; i++)
+ {
+ /*
+ * Test some pseudo-random dates/times between 0001 and 1969
+ * "-28" is used to scale the random 32-bit int from range
+ * 0..2147483648 to -60129542144..0. This is reasonably
+ * close to min 0001 date represented by -62135596799.
+ */
+ grub_int64_t x = (grub_int64_t) rand () * (grub_int64_t) -28;
+ date_test (x);
+ }
+ }
}
GRUB_UNIT_TEST ("date_unit_test", date_test_iter);
--
2.39.5
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v5 1/2] datetime: Support dates outside of 1901..2038 range
2025-08-27 2:11 ` [PATCH v5 1/2] datetime: " Andrew Hamilton
@ 2025-08-27 13:46 ` Daniel Kiper via Grub-devel
2025-08-27 14:24 ` Andrew Hamilton
0 siblings, 1 reply; 7+ messages in thread
From: Daniel Kiper via Grub-devel @ 2025-08-27 13:46 UTC (permalink / raw)
To: Andrew Hamilton
Cc: Daniel Kiper, grub-devel, masayuki.moriyama, andrea.biardi,
phcoder
On Tue, Aug 26, 2025 at 09:11:09PM -0500, Andrew Hamilton wrote:
> Support dates outside of 1901..2038.
>
> Fixes: https://savannah.gnu.org/bugs/?63894
> Fixes: https://savannah.gnu.org/bugs/?66301
>
> Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
> Signed-off-by: Andrew Hamilton <adhamilt@gmail.com>
> ---
> grub-core/lib/datetime.c | 65 ++++++++++++++++++++++++++++++++--------
> include/grub/datetime.h | 28 ++++++++++++-----
> 2 files changed, 73 insertions(+), 20 deletions(-)
>
> diff --git a/grub-core/lib/datetime.c b/grub-core/lib/datetime.c
> index 8f0922fb0..eb9a8d9c9 100644
> --- a/grub-core/lib/datetime.c
> +++ b/grub-core/lib/datetime.c
> @@ -64,7 +64,10 @@ grub_get_weekday_name (struct grub_datetime *datetime)
> #define SECPERDAY (24*SECPERHOUR)
> #define DAYSPERYEAR 365
> #define DAYSPER4YEARS (4*DAYSPERYEAR+1)
> -
> +/* 24 leap years in 100 years */
> +#define DAYSPER100YEARS (100 * DAYSPERYEAR + 24)
> +/* 97 leap years in 400 years */
> +#define DAYSPER400YEARS (400 * DAYSPERYEAR + 97)
>
> void
> grub_unixtime2datetime (grub_int64_t nix, struct grub_datetime *datetime)
> @@ -76,10 +79,12 @@ grub_unixtime2datetime (grub_int64_t nix, struct grub_datetime *datetime)
> /* Convenience: let's have 3 consecutive non-bissextile years
> at the beginning of the counting date. So count from 1901. */
> int days_epoch;
> - /* Number of days since 1st Januar, 1901. */
> + /* Number of days since 1st January, 1 (proleptic). */
> unsigned days;
> /* Seconds into current day. */
> unsigned secs_in_day;
> + /* Tracks whether this is a leap year. */
> + bool bisextile;
>
> /* Transform C divisions and modulos to mathematical ones */
> if (nix < 0)
> @@ -92,27 +97,63 @@ grub_unixtime2datetime (grub_int64_t nix, struct grub_datetime *datetime)
> days_epoch = grub_divmod64 (nix, SECPERDAY, NULL);
>
> secs_in_day = nix - days_epoch * SECPERDAY;
> - days = days_epoch + 69 * DAYSPERYEAR + 17;
> + /*
> + * 1970 is Unix Epoch. Adjust to a year 1 epoch:
> + * Leap year logic:
> + * - Years evenly divisible by 400 are leap years
> + * - Otherwise, if divisible by 100 are not leap years
> + * - Otherwise, if divisible by 4 are leap years
> + * There are four 400-year periods (1600 years worth of days with leap days)
> + * There are three 100-year periods worth of leap days (3*24)
Please move this line one line below...
> + * There are 369 years in addition to the four 400 year periods
> + * There are 17 leap days in 69 years (beyond the three 100 year periods)
> + */
> + days = days_epoch + 369 * DAYSPERYEAR + 17 + 24 * 3 + 4 * DAYSPER400YEARS;
days = 4 * DAYSPER400YEARS + 369 * DAYSPERYEAR + 3 * 24 + 17 + days_epoch;
Then it is more readable...
If you fix all these minor issues you can add my RB...
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v5 2/2] date_unit_test: test dates outside of 32-bit unix range
2025-08-27 2:11 ` [PATCH v5 2/2] date_unit_test: test dates outside of 32-bit unix range Andrew Hamilton
@ 2025-08-27 13:51 ` Daniel Kiper via Grub-devel
2025-08-27 14:24 ` Andrew Hamilton
0 siblings, 1 reply; 7+ messages in thread
From: Daniel Kiper via Grub-devel @ 2025-08-27 13:51 UTC (permalink / raw)
To: Andrew Hamilton
Cc: Daniel Kiper, grub-devel, masayuki.moriyama, andrea.biardi,
phcoder
On Tue, Aug 26, 2025 at 09:11:10PM -0500, Andrew Hamilton wrote:
> Add tests outside the date range possible with 32-bit time
> calculation. Also add a few more nominal date/time test values
> to the 32-bit "tests" array. Add min / max tests for years 0001
> and 9999.
>
> Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
> Signed-off-by: Andrew Hamilton <adhamilt@gmail.com>
> ---
> tests/date_unit_test.c | 75 +++++++++++++++++++++++++++++++++++++-----
> 1 file changed, 66 insertions(+), 9 deletions(-)
>
> diff --git a/tests/date_unit_test.c b/tests/date_unit_test.c
> index 99774f199..d3bf5a712 100644
> --- a/tests/date_unit_test.c
> +++ b/tests/date_unit_test.c
> @@ -25,12 +25,13 @@
> #include <grub/test.h>
>
> static void
> -date_test (grub_int32_t v)
> +date_test (grub_int64_t v)
> {
> struct grub_datetime dt;
> time_t t = v;
> struct tm *g;
> int w;
> + grub_int64_t back = 0;
>
> g = gmtime (&t);
>
> @@ -38,28 +39,56 @@ date_test (grub_int32_t v)
>
> w = grub_get_weekday (&dt);
>
> - grub_test_assert (g->tm_sec == dt.second, "time %d bad second: %d vs %d", v,
> + grub_datetime2unixtime (&dt, &back);
> +
> + grub_test_assert (g->tm_sec == dt.second, "time %lld bad second: %d vs %d", (long long) v,
> g->tm_sec, dt.second);
> - grub_test_assert (g->tm_min == dt.minute, "time %d bad minute: %d vs %d", v,
> + grub_test_assert (g->tm_min == dt.minute, "time %lld bad minute: %d vs %d", (long long) v,
> g->tm_min, dt.minute);
> - grub_test_assert (g->tm_hour == dt.hour, "time %d bad hour: %d vs %d", v,
> + grub_test_assert (g->tm_hour == dt.hour, "time %lld bad hour: %d vs %d", (long long) v,
> g->tm_hour, dt.hour);
> - grub_test_assert (g->tm_mday == dt.day, "time %d bad day: %d vs %d", v,
> + grub_test_assert (g->tm_mday == dt.day, "time %lld bad day: %d vs %d", (long long) v,
> g->tm_mday, dt.day);
> - grub_test_assert (g->tm_mon + 1 == dt.month, "time %d bad month: %d vs %d", v,
> + grub_test_assert (g->tm_mon + 1 == dt.month, "time %lld bad month: %d vs %d",(long long) v,
> g->tm_mon + 1, dt.month);
> grub_test_assert (g->tm_year + 1900 == dt.year,
> - "time %d bad year: %d vs %d", v,
> + "time %lld bad year: %d vs %d", (long long) v,
> g->tm_year + 1900, dt.year);
> - grub_test_assert (g->tm_wday == w, "time %d bad week day: %d vs %d", v,
> + grub_test_assert (g->tm_wday == w, "time %lld bad week day: %d vs %d", (long long) v,
> g->tm_wday, w);
> + grub_test_assert (back == v, "time %lld bad back transform: %lld", (long long) v,
> + (long long) back);
> }
>
> static void
> date_test_iter (void)
> {
> - grub_int32_t tests[] = { -1, 0, +1, -2133156255, GRUB_INT32_MIN,
> + /*
> + * Test several interesting UNIX timestamps in 32-bit time:
> + * 1. -1: 1969-12-31 23:59:59 - Just before EPOCH
> + * 2. 0: 1970-01-01 00:00:00 - EPOCH
> + * 3. +1: 1970-01-01 00:00:01 - Just after EPOCH
> + * 4. 978224552: 2000-12-31 01:02:32 - Leap year, prior to Feb
s/prior/after/?
> + * 5. -2133156255: 1902-05-28 16:35:45 - Nominal value
> + * 6. -2110094321: 1903-02-19 14:41:19 - Nominal value
> + * 7. GRUB_INT32_MIN: 1901-12-13 20:45:52 - 32-bit Min value
> + * 8. GRUB_INT32_MAX: 2038-01-19 03:14:07 - 32-bit Max value
> + */
> + grub_int32_t tests[] = { -1, 0, +1, 978224552, -2133156255, -2110094321, GRUB_INT32_MIN,
> GRUB_INT32_MAX };
Otherwise LGTM...
When you fix the issue above you can add my RB...
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v5 1/2] datetime: Support dates outside of 1901..2038 range
2025-08-27 13:46 ` Daniel Kiper via Grub-devel
@ 2025-08-27 14:24 ` Andrew Hamilton
0 siblings, 0 replies; 7+ messages in thread
From: Andrew Hamilton @ 2025-08-27 14:24 UTC (permalink / raw)
To: Daniel Kiper; +Cc: grub-devel, masayuki.moriyama, andrea.biardi, phcoder
[-- Attachment #1.1: Type: text/plain, Size: 3218 bytes --]
Will do, I’ll send out a v6 this evening, thank you!
Andrew
On Wed, Aug 27, 2025 at 8:46 AM Daniel Kiper <daniel.kiper@oracle.com>
wrote:
> On Tue, Aug 26, 2025 at 09:11:09PM -0500, Andrew Hamilton wrote:
> > Support dates outside of 1901..2038.
> >
> > Fixes: https://savannah.gnu.org/bugs/?63894
> > Fixes: https://savannah.gnu.org/bugs/?66301
> >
> > Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
> > Signed-off-by: Andrew Hamilton <adhamilt@gmail.com>
> > ---
> > grub-core/lib/datetime.c | 65 ++++++++++++++++++++++++++++++++--------
> > include/grub/datetime.h | 28 ++++++++++++-----
> > 2 files changed, 73 insertions(+), 20 deletions(-)
> >
> > diff --git a/grub-core/lib/datetime.c b/grub-core/lib/datetime.c
> > index 8f0922fb0..eb9a8d9c9 100644
> > --- a/grub-core/lib/datetime.c
> > +++ b/grub-core/lib/datetime.c
> > @@ -64,7 +64,10 @@ grub_get_weekday_name (struct grub_datetime *datetime)
> > #define SECPERDAY (24*SECPERHOUR)
> > #define DAYSPERYEAR 365
> > #define DAYSPER4YEARS (4*DAYSPERYEAR+1)
> > -
> > +/* 24 leap years in 100 years */
> > +#define DAYSPER100YEARS (100 * DAYSPERYEAR + 24)
> > +/* 97 leap years in 400 years */
> > +#define DAYSPER400YEARS (400 * DAYSPERYEAR + 97)
> >
> > void
> > grub_unixtime2datetime (grub_int64_t nix, struct grub_datetime
> *datetime)
> > @@ -76,10 +79,12 @@ grub_unixtime2datetime (grub_int64_t nix, struct
> grub_datetime *datetime)
> > /* Convenience: let's have 3 consecutive non-bissextile years
> > at the beginning of the counting date. So count from 1901. */
> > int days_epoch;
> > - /* Number of days since 1st Januar, 1901. */
> > + /* Number of days since 1st January, 1 (proleptic). */
> > unsigned days;
> > /* Seconds into current day. */
> > unsigned secs_in_day;
> > + /* Tracks whether this is a leap year. */
> > + bool bisextile;
> >
> > /* Transform C divisions and modulos to mathematical ones */
> > if (nix < 0)
> > @@ -92,27 +97,63 @@ grub_unixtime2datetime (grub_int64_t nix, struct
> grub_datetime *datetime)
> > days_epoch = grub_divmod64 (nix, SECPERDAY, NULL);
> >
> > secs_in_day = nix - days_epoch * SECPERDAY;
> > - days = days_epoch + 69 * DAYSPERYEAR + 17;
> > + /*
> > + * 1970 is Unix Epoch. Adjust to a year 1 epoch:
> > + * Leap year logic:
> > + * - Years evenly divisible by 400 are leap years
> > + * - Otherwise, if divisible by 100 are not leap years
> > + * - Otherwise, if divisible by 4 are leap years
> > + * There are four 400-year periods (1600 years worth of days with
> leap days)
> > + * There are three 100-year periods worth of leap days (3*24)
>
> Please move this line one line below...
>
> > + * There are 369 years in addition to the four 400 year periods
> > + * There are 17 leap days in 69 years (beyond the three 100 year
> periods)
> > + */
> > + days = days_epoch + 369 * DAYSPERYEAR + 17 + 24 * 3 + 4 *
> DAYSPER400YEARS;
>
> days = 4 * DAYSPER400YEARS + 369 * DAYSPERYEAR + 3 * 24 + 17 + days_epoch;
>
> Then it is more readable...
>
> If you fix all these minor issues you can add my RB...
>
> Daniel
>
[-- Attachment #1.2: Type: text/html, Size: 4229 bytes --]
[-- Attachment #2: Type: text/plain, Size: 141 bytes --]
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v5 2/2] date_unit_test: test dates outside of 32-bit unix range
2025-08-27 13:51 ` Daniel Kiper via Grub-devel
@ 2025-08-27 14:24 ` Andrew Hamilton
0 siblings, 0 replies; 7+ messages in thread
From: Andrew Hamilton @ 2025-08-27 14:24 UTC (permalink / raw)
To: Daniel Kiper; +Cc: grub-devel, masayuki.moriyama, andrea.biardi, phcoder
[-- Attachment #1.1: Type: text/plain, Size: 4156 bytes --]
Will do, I’ll send out a v6 this evening, thank you!
Andrew
On Wed, Aug 27, 2025 at 8:51 AM Daniel Kiper <daniel.kiper@oracle.com>
wrote:
> On Tue, Aug 26, 2025 at 09:11:10PM -0500, Andrew Hamilton wrote:
> > Add tests outside the date range possible with 32-bit time
> > calculation. Also add a few more nominal date/time test values
> > to the 32-bit "tests" array. Add min / max tests for years 0001
> > and 9999.
> >
> > Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
> > Signed-off-by: Andrew Hamilton <adhamilt@gmail.com>
> > ---
> > tests/date_unit_test.c | 75 +++++++++++++++++++++++++++++++++++++-----
> > 1 file changed, 66 insertions(+), 9 deletions(-)
> >
> > diff --git a/tests/date_unit_test.c b/tests/date_unit_test.c
> > index 99774f199..d3bf5a712 100644
> > --- a/tests/date_unit_test.c
> > +++ b/tests/date_unit_test.c
> > @@ -25,12 +25,13 @@
> > #include <grub/test.h>
> >
> > static void
> > -date_test (grub_int32_t v)
> > +date_test (grub_int64_t v)
> > {
> > struct grub_datetime dt;
> > time_t t = v;
> > struct tm *g;
> > int w;
> > + grub_int64_t back = 0;
> >
> > g = gmtime (&t);
> >
> > @@ -38,28 +39,56 @@ date_test (grub_int32_t v)
> >
> > w = grub_get_weekday (&dt);
> >
> > - grub_test_assert (g->tm_sec == dt.second, "time %d bad second: %d vs
> %d", v,
> > + grub_datetime2unixtime (&dt, &back);
> > +
> > + grub_test_assert (g->tm_sec == dt.second, "time %lld bad second: %d
> vs %d", (long long) v,
> > g->tm_sec, dt.second);
> > - grub_test_assert (g->tm_min == dt.minute, "time %d bad minute: %d vs
> %d", v,
> > + grub_test_assert (g->tm_min == dt.minute, "time %lld bad minute: %d
> vs %d", (long long) v,
> > g->tm_min, dt.minute);
> > - grub_test_assert (g->tm_hour == dt.hour, "time %d bad hour: %d vs
> %d", v,
> > + grub_test_assert (g->tm_hour == dt.hour, "time %lld bad hour: %d vs
> %d", (long long) v,
> > g->tm_hour, dt.hour);
> > - grub_test_assert (g->tm_mday == dt.day, "time %d bad day: %d vs %d",
> v,
> > + grub_test_assert (g->tm_mday == dt.day, "time %lld bad day: %d vs
> %d", (long long) v,
> > g->tm_mday, dt.day);
> > - grub_test_assert (g->tm_mon + 1 == dt.month, "time %d bad month: %d
> vs %d", v,
> > + grub_test_assert (g->tm_mon + 1 == dt.month, "time %lld bad month: %d
> vs %d",(long long) v,
> > g->tm_mon + 1, dt.month);
> > grub_test_assert (g->tm_year + 1900 == dt.year,
> > - "time %d bad year: %d vs %d", v,
> > + "time %lld bad year: %d vs %d", (long long) v,
> > g->tm_year + 1900, dt.year);
> > - grub_test_assert (g->tm_wday == w, "time %d bad week day: %d vs %d",
> v,
> > + grub_test_assert (g->tm_wday == w, "time %lld bad week day: %d vs
> %d", (long long) v,
> > g->tm_wday, w);
> > + grub_test_assert (back == v, "time %lld bad back transform: %lld",
> (long long) v,
> > + (long long) back);
> > }
> >
> > static void
> > date_test_iter (void)
> > {
> > - grub_int32_t tests[] = { -1, 0, +1, -2133156255, GRUB_INT32_MIN,
> > + /*
> > + * Test several interesting UNIX timestamps in 32-bit time:
> > + * 1. -1: 1969-12-31 23:59:59 - Just before EPOCH
> > + * 2. 0: 1970-01-01 00:00:00 - EPOCH
> > + * 3. +1: 1970-01-01 00:00:01 - Just after EPOCH
> > + * 4. 978224552: 2000-12-31 01:02:32 - Leap year, prior to Feb
>
> s/prior/after/?
>
> > + * 5. -2133156255: 1902-05-28 16:35:45 - Nominal value
> > + * 6. -2110094321: 1903-02-19 14:41:19 - Nominal value
> > + * 7. GRUB_INT32_MIN: 1901-12-13 20:45:52 - 32-bit Min value
> > + * 8. GRUB_INT32_MAX: 2038-01-19 03:14:07 - 32-bit Max value
> > + */
> > + grub_int32_t tests[] = { -1, 0, +1, 978224552, -2133156255,
> -2110094321, GRUB_INT32_MIN,
> > GRUB_INT32_MAX };
>
> Otherwise LGTM...
>
> When you fix the issue above you can add my RB...
>
> Daniel
>
[-- Attachment #1.2: Type: text/html, Size: 6182 bytes --]
[-- Attachment #2: Type: text/plain, Size: 141 bytes --]
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2025-08-27 14:25 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-27 2:11 [PATCH v5 0/2] Support dates outside of 1901..2038 range Andrew Hamilton
2025-08-27 2:11 ` [PATCH v5 1/2] datetime: " Andrew Hamilton
2025-08-27 13:46 ` Daniel Kiper via Grub-devel
2025-08-27 14:24 ` Andrew Hamilton
2025-08-27 2:11 ` [PATCH v5 2/2] date_unit_test: test dates outside of 32-bit unix range Andrew Hamilton
2025-08-27 13:51 ` Daniel Kiper via Grub-devel
2025-08-27 14:24 ` Andrew Hamilton
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).