I will make the requested changes tonight in a v5. Just so I understand, is there some coding standard for preferring ternary operators and comparing bools to true?
Thanks, Andrew On Tue, Aug 26, 2025 at 10:06 AM Daniel Kiper <[email protected]> wrote: > On Mon, Aug 25, 2025 at 10:17:37PM -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 <[email protected]> > > Signed-off-by: Andrew Hamilton <[email protected]> > > --- > > grub-core/lib/datetime.c | 64 ++++++++++++++++++++++++++++++++-------- > > include/grub/datetime.h | 27 ++++++++++++----- > > 2 files changed, 71 insertions(+), 20 deletions(-) > > > > diff --git a/grub-core/lib/datetime.c b/grub-core/lib/datetime.c > > index 8f0922fb0..a0f84d989 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 is_bisextile; > > > > /* Transform C divisions and modulos to mathematical ones */ > > if (nix < 0) > > @@ -92,27 +97,62 @@ 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]); > > + > > + is_bisextile = datetime->year % 4 == 0 > > + && (datetime->year % 100 != 0 || datetime->year % 400 > == 0); > > Even if it works it is not fully correct... > > is_bisextile = (datetime->year % 4 == 0 && > (datetime->year % 100 != 0 || datetime->year % 400 == 0)) > ? true : false; > > > + for (i = 0; > > + i < 12 && days >= ((i == 1 && is_bisextile == true) ? 29 : > months[i]); > > + i++) > > + days -= ((i == 1 && is_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..ff847e847 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 is_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,27 @@ 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) > > + is_bisextile = ay == 3 > > + && (datetime->year % 100 != 0 || datetime->year % 400 > == 0); > > Again... > > is_bisextile = (ay == 3 && (datetime->year % 100 != 0 || datetime->year % > 400 == 0)) ? true : false; > > > + if (is_bisextile && datetime->month >= 3) > > is_bisextile == true && ... > > > ret += SECPERDAY; > > > > ret += (datetime->day - 1) * SECPERDAY; > > if ((datetime->day > months[datetime->month - 1] > > - && (!ay || datetime->month != 2 || datetime->day != 29)) > > + && !(is_bisextile && datetime->month == 2 && datetime->day == > 29)) > > is_bisextile == true && ... > > ... and I would drop "is_" from variable name... > > Daniel >
_______________________________________________ Grub-devel mailing list [email protected] https://lists.gnu.org/mailman/listinfo/grub-devel
