> On Fri, Apr 18, 2025 at 09:53:59AM -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 <phco...@gmail.com>
> > Signed-off-by: Andrew Hamilton <adham...@gmail.com>
> > ---
> >  grub-core/lib/datetime.c | 48 ++++++++++++++++++++++++++++++++--------
> >  include/grub/datetime.h  | 15 ++++++-------
> >  2 files changed, 46 insertions(+), 17 deletions(-)
> >
> > diff --git a/grub-core/lib/datetime.c b/grub-core/lib/datetime.c
> > index 8f0922fb0..4e68eabc6 100644
> > --- a/grub-core/lib/datetime.c
> > +++ b/grub-core/lib/datetime.c
> > @@ -64,6 +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
> > @@ -76,7 +80,7 @@ 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;
> > @@ -92,12 +96,39 @@ 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) */
>
> May I ask you to stick to comments coding style [1]?
>
> > +  days = days_epoch + 369 * DAYSPERYEAR + 17 + 24 * 3 + 4 * 
> > DAYSPER400YEARS;
> >
> > -  datetime->year = 1901 + 4 * (days / DAYSPER4YEARS);
> > +  datetime->year = 1 + 400 * (days / DAYSPER400YEARS);
> > +  days %= DAYSPER400YEARS;
> > +
> > +  /* 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 */
>
> Ditto... Here and below please...

Will do, I will fix the comment formatting in the next version.


> > +  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;
> > @@ -108,11 +139,10 @@ grub_unixtime2datetime (grub_int64_t nix, struct 
> > grub_datetime *datetime)
> >        datetime->year += days / DAYSPERYEAR;
> >        days %= DAYSPERYEAR;
> >      }
> > +  int isbisextile = datetime->year % 4 == 0 && (datetime->year % 100 != 0 
> > || datetime->year % 400 == 0);
>
> Please do not define variables in random places. I prefer if it is done
> at the beginning of the function or block.
>
> And I think this should be a bool set with ternary operator...
>
> ... and s/isbisextile/is_bisextile/
>
I will correct the variable declaration location and change to bool /
changing naming as well in the next version.

> >    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]);
> > +        && days >= (i==1 && isbisextile ? 29 : months[i]); i++)
> > +    days -= (i==1 && isbisextile ? 29 : months[i]);
>
> If you touch the code then please fix its coding style, e.g.:
>
>   days -= (i == 1 && is_bisextile == true) ? 29 : months[i]
>
> On the occasion it seems more readable...

I will correct this in the next version.


>
> >    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..9289b0d00 100644
> > --- a/include/grub/datetime.h
> > +++ b/include/grub/datetime.h
> > @@ -54,7 +54,7 @@ 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;
> >    const grub_uint16_t monthssum[12]
> >      = { 0,
> > @@ -75,15 +75,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 +90,16 @@ grub_datetime2unixtime (const struct grub_datetime 
> > *datetime, grub_int64_t *nix)
> >    ret += y4 * SECPER4YEARS;
> >    ret += ay * SECPERYEAR;
> >
> > +  ret -= ((datetime->year - 1) / 100 - (datetime->year - 1) / 400 - 15) * 
> > SECPERDAY;
>
> What does this line do? And where 15 comes from?

I will investigate the origin / meaning of "15" here and add comments
to explain this in the next version.


Thank you for the comments, I will try to get a V4 out tonight.

Thanks!
Andrew


On Mon, Aug 25, 2025 at 12:08 PM Daniel Kiper <daniel.ki...@oracle.com> wrote:
>
> On Fri, Apr 18, 2025 at 09:53:59AM -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 <phco...@gmail.com>
> > Signed-off-by: Andrew Hamilton <adham...@gmail.com>
> > ---
> >  grub-core/lib/datetime.c | 48 ++++++++++++++++++++++++++++++++--------
> >  include/grub/datetime.h  | 15 ++++++-------
> >  2 files changed, 46 insertions(+), 17 deletions(-)
> >
> > diff --git a/grub-core/lib/datetime.c b/grub-core/lib/datetime.c
> > index 8f0922fb0..4e68eabc6 100644
> > --- a/grub-core/lib/datetime.c
> > +++ b/grub-core/lib/datetime.c
> > @@ -64,6 +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
> > @@ -76,7 +80,7 @@ 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;
> > @@ -92,12 +96,39 @@ 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) */
>
> May I ask you to stick to comments coding style [1]?
>
> > +  days = days_epoch + 369 * DAYSPERYEAR + 17 + 24 * 3 + 4 * 
> > DAYSPER400YEARS;
> >
> > -  datetime->year = 1901 + 4 * (days / DAYSPER4YEARS);
> > +  datetime->year = 1 + 400 * (days / DAYSPER400YEARS);
> > +  days %= DAYSPER400YEARS;
> > +
> > +  /* 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 */
>
> Ditto... Here and below please...
>
> > +  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;
> > @@ -108,11 +139,10 @@ grub_unixtime2datetime (grub_int64_t nix, struct 
> > grub_datetime *datetime)
> >        datetime->year += days / DAYSPERYEAR;
> >        days %= DAYSPERYEAR;
> >      }
> > +  int isbisextile = datetime->year % 4 == 0 && (datetime->year % 100 != 0 
> > || datetime->year % 400 == 0);
>
> Please do not define variables in random places. I prefer if it is done
> at the beginning of the function or block.
>
> And I think this should be a bool set with ternary operator...
>
> ... and s/isbisextile/is_bisextile/
>
> >    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]);
> > +        && days >= (i==1 && isbisextile ? 29 : months[i]); i++)
> > +    days -= (i==1 && isbisextile ? 29 : months[i]);
>
> If you touch the code then please fix its coding style, e.g.:
>
>   days -= (i == 1 && is_bisextile == true) ? 29 : months[i]
>
> On the occasion it seems more readable...
>
> >    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..9289b0d00 100644
> > --- a/include/grub/datetime.h
> > +++ b/include/grub/datetime.h
> > @@ -54,7 +54,7 @@ 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;
> >    const grub_uint16_t monthssum[12]
> >      = { 0,
> > @@ -75,15 +75,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 +90,16 @@ grub_datetime2unixtime (const struct grub_datetime 
> > *datetime, grub_int64_t *nix)
> >    ret += y4 * SECPER4YEARS;
> >    ret += ay * SECPERYEAR;
> >
> > +  ret -= ((datetime->year - 1) / 100 - (datetime->year - 1) / 400 - 15) * 
> > SECPERDAY;
>
> What does this line do? And where 15 comes from?
>
> Daniel

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to