From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id B2083CA0EFA for ; Tue, 26 Aug 2025 15:29:16 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uqvbJ-000432-8z; Tue, 26 Aug 2025 11:28:47 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uqvbD-00041t-BF for grub-devel@gnu.org; Tue, 26 Aug 2025 11:28:40 -0400 Received: from mail-ej1-x636.google.com ([2a00:1450:4864:20::636]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1uqvb5-0007UZ-K4 for grub-devel@gnu.org; Tue, 26 Aug 2025 11:28:38 -0400 Received: by mail-ej1-x636.google.com with SMTP id a640c23a62f3a-afcb7a0550cso1002783266b.2 for ; Tue, 26 Aug 2025 08:28:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1756222101; x=1756826901; darn=gnu.org; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=JpHy20NZVnKhP1AeWTHnhXIYzEpS8C6A7orCNzcebjw=; b=FK23+Sc3na3uNO0kNXUhTlX3b5VvzmRq/h5rY/+96a6x26k8jHjLEWFnNTWMuG0h2l F1miOidhvS+Z7YiLsx7xq2/+lFlsRUS7wOG3r+kMtCz492ja+MmoI1QHwpQpOAL+cvsr BrP1M70RXIreyekiyPP/JdK0CIDBHMmb70GAkD2m8oCj2mauIyAh8sgik2EPOcv8fyv1 gnl0TWGPNTeiK6J4EcsBYrr1c6Erx0V0x18P7iQVT+LWlj4pHBXRI2/MVfbM+fZooaFx rpAll8oJFYeFYZgtBM8G2nCXzn7FxTcIeABrrxVDdCmeznfPD26Pf27IC+Osg3hYOwr4 JOJQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756222101; x=1756826901; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=JpHy20NZVnKhP1AeWTHnhXIYzEpS8C6A7orCNzcebjw=; b=sn8FTuYUWj/sRPMUrCGE+2PhHdbk0vj5s6toJJZ4DVxG90pGHulbl9zM7lVnWxVy2l is8Se1HY1XwYQwmDJnOGT1f+a/GtX7ln2O5/eEUgsr/aouNm/q77AwAS/ujWE6xgXnVm Fa8j03Wig6W7Fx2tTC43aIwyaxpE+it3dgN0mM7fp7+bCk7MW4l9Bog+Nq5z3mL5D4db /luS13aGw/6qnF3dK7NpwnsbmNiVMcR1x5BkLwCvHymTCQg0mutEM1Njvk354d9qoGYz bsM+wUstuEdJvJ33mqKg7Ns+J8/qZGLZkZ60iPExDqW41Y6YMwyW4SJO6UUVBwQr3ijC TZUQ== X-Gm-Message-State: AOJu0YyHHwTTZk7erEeXJSXZ4GbCoDoa5M8BBjG0d1DwsbaCUePCblSf rdGAI9PjOiTOPbpbqGplt0syPNc2DJ7/GHvTg7ne9yO86frQWJEDNul4jmsrrrWv+DxxI+t6yMS mOUeO90Z1NT3ckEgl4oX+j2cp4EWs9WKboe8+ X-Gm-Gg: ASbGncufdI8oE7rqh+6puXbpr9UyaDB8A4pg3OMjBkxT0tcSlJ4LthKftTtsRVroBoE cyZaSndRFP90qJk0kcWukX9FU43SOe2tbNh1aZpJsIYgKS26sfLmnoU+4qifYrJ44AXJyGXtXrr fuydJuj0KPWB+Xk4QXnde1/BOClMdcG85dDBoVxaNtCZssqpxCJZhlnbo1rXujBnOByY9taJr6V 7uDQUHRzB9ypxtaug== X-Google-Smtp-Source: AGHT+IFvOE1cgYsR5n5U5NiUwL0gdF1+lKfQ4lnoX3zXpYqQ42j74ktrbroYxy0xsBkVjnCNZ1XpkURbMX5YDk9/IyU= X-Received: by 2002:a17:907:86a3:b0:afe:8b53:449c with SMTP id a640c23a62f3a-afe8b535789mr595552266b.34.1756222101158; Tue, 26 Aug 2025 08:28:21 -0700 (PDT) MIME-Version: 1.0 References: <20250826031738.86977-1-adhamilt@gmail.com> <20250826031738.86977-2-adhamilt@gmail.com> In-Reply-To: From: Andrew Hamilton Date: Tue, 26 Aug 2025 10:28:08 -0500 X-Gm-Features: Ac12FXyWSMPzV9PAPkGH6jTRicJ_Ir8wxjcid3ID50lTcP7ULMTXGXoFDYwP-34 Message-ID: Subject: Re: [PATCH v4 1/2] datetime: Support dates outside of 1901..2038 range To: Daniel Kiper Cc: grub-devel@gnu.org, masayuki.moriyama@miraclelinux.com, andrea.biardi@viavisolutions.com, phcoder@gmail.com Received-SPF: pass client-ip=2a00:1450:4864:20::636; envelope-from=adhamilt@gmail.com; helo=mail-ej1-x636.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: The development of GNU GRUB Content-Type: multipart/mixed; boundary="===============4209367889758609628==" Errors-To: grub-devel-bounces+grub-devel=archiver.kernel.org@gnu.org Sender: grub-devel-bounces+grub-devel=archiver.kernel.org@gnu.org --===============4209367889758609628== Content-Type: multipart/alternative; boundary="0000000000007c81eb063d46523e" --0000000000007c81eb063d46523e Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable 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=E2=80=AFAM Daniel Kiper 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 > > Signed-off-by: Andrew Hamilton > > --- > > 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 *datetim= e) > > #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 =3D grub_divmod64 (nix, SECPERDAY, NULL); > > > > secs_in_day =3D nix - days_epoch * SECPERDAY; > > - days =3D 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 =3D days_epoch + 369 * DAYSPERYEAR + 17 + 24 * 3 + 4 * > DAYSPER400YEARS; > > + > > + datetime->year =3D 1 + 400 * (days / DAYSPER400YEARS); > > + days %=3D DAYSPER400YEARS; > > > > - datetime->year =3D 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 =3D=3D 4) > > + { > > + datetime->year +=3D 396; > > + days -=3D 396 * DAYSPERYEAR + 96; > > + } > > + else > > + { > > + datetime->year +=3D 100 * (days / DAYSPER100YEARS); > > + days %=3D DAYSPER100YEARS; > > + } > > + > > + datetime->year +=3D 4 * (days / DAYSPER4YEARS); > > days %=3D 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 =3D=3D 4) > > { > > datetime->year +=3D 3; > > - days -=3D 3*DAYSPERYEAR; > > + days -=3D 3 * DAYSPERYEAR; > > } > > else > > { > > datetime->year +=3D days / DAYSPERYEAR; > > days %=3D DAYSPERYEAR; > > } > > - for (i =3D 0; i < 12 > > - && days >=3D (i=3D=3D1 && datetime->year % 4 =3D=3D 0 > > - ? 29 : months[i]); i++) > > - days -=3D (i=3D=3D1 && datetime->year % 4 =3D=3D 0 > > - ? 29 : months[i]); > > + > > + is_bisextile =3D datetime->year % 4 =3D=3D 0 > > + && (datetime->year % 100 !=3D 0 || datetime->year % 4= 00 > =3D=3D 0); > > Even if it works it is not fully correct... > > is_bisextile =3D (datetime->year % 4 =3D=3D 0 && > (datetime->year % 100 !=3D 0 || datetime->year % 400 =3D= =3D 0)) > ? true : false; > > > + for (i =3D 0; > > + i < 12 && days >=3D ((i =3D=3D 1 && is_bisextile =3D=3D true) ?= 29 : > months[i]); > > + i++) > > + days -=3D ((i =3D=3D 1 && is_bisextile =3D=3D true) ? 29 : months[= i]); > > datetime->month =3D i + 1; > > datetime->day =3D 1 + days; > > datetime->hour =3D (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] > > =3D { 0, > > 31, > > @@ -75,15 +76,11 @@ grub_datetime2unixtime (const struct grub_datetime > *datetime, grub_int64_t *nix) > > const int SECPERHOUR =3D 60 * SECPERMIN; > > const int SECPERDAY =3D 24 * SECPERHOUR; > > const int SECPERYEAR =3D 365 * SECPERDAY; > > - const int SECPER4YEARS =3D 4 * SECPERYEAR + SECPERDAY; > > + const grub_int64_t SECPER4YEARS =3D 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 =3D 3 * SECPERYEAR + SECPERDAY; > > @@ -94,13 +91,27 @@ grub_datetime2unixtime (const struct grub_datetime > *datetime, grub_int64_t *nix) > > ret +=3D y4 * SECPER4YEARS; > > ret +=3D 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 =3D 19 (floor due to integer math) > > + * - (1973 - 1) / 400 =3D 4 (floor due to integer math) > > + * - 19 - 4 - 15 =3D 0 (we want to start with no "false leap years"= at > time > > + * zero of 1973) > > + */ > > + ret -=3D ((datetime->year - 1) / 100 - (datetime->year - 1) / 400 - = 15) > > + * SECPERDAY; > > + > > ret +=3D monthssum[datetime->month - 1] * SECPERDAY; > > - if (ay =3D=3D 3 && datetime->month >=3D 3) > > + is_bisextile =3D ay =3D=3D 3 > > + && (datetime->year % 100 !=3D 0 || datetime->year % 4= 00 > =3D=3D 0); > > Again... > > is_bisextile =3D (ay =3D=3D 3 && (datetime->year % 100 !=3D 0 || datetime= ->year % > 400 =3D=3D 0)) ? true : false; > > > + if (is_bisextile && datetime->month >=3D 3) > > is_bisextile =3D=3D true && ... > > > ret +=3D SECPERDAY; > > > > ret +=3D (datetime->day - 1) * SECPERDAY; > > if ((datetime->day > months[datetime->month - 1] > > - && (!ay || datetime->month !=3D 2 || datetime->day !=3D 29)) > > + && !(is_bisextile && datetime->month =3D=3D 2 && datetime->day = =3D=3D > 29)) > > is_bisextile =3D=3D true && ... > > ... and I would drop "is_" from variable name... > > Daniel > --0000000000007c81eb063d46523e Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
I will make the requested changes tonight in a v5.
<= div dir=3D"auto">
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=E2=80=AFAM Daniel Kiper <= daniel.kiper@oracle.com> 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 <phcoder@gmail.com>
> Signed-off-by: Andrew Hamilton <adhamilt@gmail.com>
> ---
>=C2=A0 grub-core/lib/datetime.c | 64 ++++++++++++++++++++++++++++++++--= ------
>=C2=A0 include/grub/datetime.h=C2=A0 | 27 ++++++++++++-----
>=C2=A0 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 *dateti= me)
>=C2=A0 #define SECPERDAY (24*SECPERHOUR)
>=C2=A0 #define DAYSPERYEAR 365
>=C2=A0 #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)
>
>=C2=A0 void
>=C2=A0 grub_unixtime2datetime (grub_int64_t nix, struct grub_datetime *= datetime)
> @@ -76,10 +79,12 @@ grub_unixtime2datetime (grub_int64_t nix, struct g= rub_datetime *datetime)
>=C2=A0 =C2=A0 /* Convenience: let's have 3 consecutive non-bissexti= le years
>=C2=A0 =C2=A0 =C2=A0 =C2=A0at the beginning of the counting date. So co= unt from 1901. */
>=C2=A0 =C2=A0 int days_epoch;
> -=C2=A0 /* Number of days since 1st Januar, 1901.=C2=A0 */
> +=C2=A0 /* Number of days since 1st January, 1 (proleptic). */
>=C2=A0 =C2=A0 unsigned days;
>=C2=A0 =C2=A0 /* Seconds into current day.=C2=A0 */
>=C2=A0 =C2=A0 unsigned secs_in_day;
> +=C2=A0 /* Tracks whether this is a leap year. */
> +=C2=A0 bool is_bisextile;
>
>=C2=A0 =C2=A0 /* Transform C divisions and modulos to mathematical ones= */
>=C2=A0 =C2=A0 if (nix < 0)
> @@ -92,27 +97,62 @@ grub_unixtime2datetime (grub_int64_t nix, struct g= rub_datetime *datetime)
>=C2=A0 =C2=A0 =C2=A0 days_epoch =3D grub_divmod64 (nix, SECPERDAY, NULL= );
>
>=C2=A0 =C2=A0 secs_in_day =3D nix - days_epoch * SECPERDAY;
> -=C2=A0 days =3D days_epoch + 69 * DAYSPERYEAR + 17;
> +=C2=A0 /*
> +=C2=A0 =C2=A0* 1970 is Unix Epoch. Adjust to a year 1 epoch:
> +=C2=A0 =C2=A0*=C2=A0 Leap year logic:
> +=C2=A0 =C2=A0*=C2=A0 =C2=A0- Years evenly divisible by 400 are leap y= ears
> +=C2=A0 =C2=A0*=C2=A0 =C2=A0- Otherwise, if divisible by 100 are not l= eap years
> +=C2=A0 =C2=A0*=C2=A0 =C2=A0- Otherwise, if divisible by 4 are leap ye= ars
> +=C2=A0 =C2=A0*=C2=A0 There are four 400-year periods (1600 years wort= h of days with leap days)
> +=C2=A0 =C2=A0*=C2=A0 There are three 100-year periods worth of leap d= ays (3*24)
> +=C2=A0 =C2=A0*=C2=A0 There are 369 years in addition to the four 400 = year periods
> +=C2=A0 =C2=A0*=C2=A0 There are 17 leap days in 69 years (beyond the t= hree 100 year periods)
> +=C2=A0 =C2=A0*/
> +=C2=A0 days =3D days_epoch + 369 * DAYSPERYEAR + 17 + 24 * 3 + 4 * DA= YSPER400YEARS;
> +
> +=C2=A0 datetime->year =3D 1 + 400 * (days / DAYSPER400YEARS);
> +=C2=A0 days %=3D DAYSPER400YEARS;
>
> -=C2=A0 datetime->year =3D 1901 + 4 * (days / DAYSPER4YEARS);
> +=C2=A0 /*
> +=C2=A0 =C2=A0* On 31st December of bissextile (leap) years 365 days f= rom the beginning
> +=C2=A0 =C2=A0* of the year elapsed but year isn't finished yet - = every 400 years
> +=C2=A0 =C2=A0* 396 is 4 years less than 400 year leap cycle
> +=C2=A0 =C2=A0* 96 is 1 day less than number of leap days in 400 years=
> +=C2=A0 =C2=A0*/
> +=C2=A0 if (days / DAYSPER100YEARS =3D=3D 4)
> +=C2=A0 =C2=A0 {
> +=C2=A0 =C2=A0 =C2=A0 datetime->year +=3D 396;
> +=C2=A0 =C2=A0 =C2=A0 days -=3D 396 * DAYSPERYEAR + 96;
> +=C2=A0 =C2=A0 }
> +=C2=A0 else
> +=C2=A0 =C2=A0 {
> +=C2=A0 =C2=A0 =C2=A0 datetime->year +=3D 100 * (days / DAYSPER100Y= EARS);
> +=C2=A0 =C2=A0 =C2=A0 days %=3D DAYSPER100YEARS;
> +=C2=A0 =C2=A0 }
> +
> +=C2=A0 datetime->year +=3D 4 * (days / DAYSPER4YEARS);
>=C2=A0 =C2=A0 days %=3D DAYSPER4YEARS;
> -=C2=A0 /* On 31st December of bissextile years 365 days from the begi= nning
> -=C2=A0 =C2=A0 =C2=A0of the year elapsed but year isn't finished y= et */
> +=C2=A0 /*
> +=C2=A0 =C2=A0* On 31st December of bissextile (leap) years 365 days f= rom the beginning
> +=C2=A0 =C2=A0* of the year elapsed but year isn't finished yet - = every 4 years
> +=C2=A0 =C2=A0*/
>=C2=A0 =C2=A0 if (days / DAYSPERYEAR =3D=3D 4)
>=C2=A0 =C2=A0 =C2=A0 {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 datetime->year +=3D 3;
> -=C2=A0 =C2=A0 =C2=A0 days -=3D 3*DAYSPERYEAR;
> +=C2=A0 =C2=A0 =C2=A0 days -=3D 3 * DAYSPERYEAR;
>=C2=A0 =C2=A0 =C2=A0 }
>=C2=A0 =C2=A0 else
>=C2=A0 =C2=A0 =C2=A0 {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 datetime->year +=3D days / DAYSPERYEAR;<= br> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 days %=3D DAYSPERYEAR;
>=C2=A0 =C2=A0 =C2=A0 }
> -=C2=A0 for (i =3D 0; i < 12
> -=C2=A0 =C2=A0 =C2=A0 && days >=3D (i=3D=3D1 && dat= etime->year % 4 =3D=3D 0
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= ? 29 : months[i]); i++)
> -=C2=A0 =C2=A0 days -=3D (i=3D=3D1 && datetime->year % 4 = =3D=3D 0
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0? 29 : months[i]);
> +
> +=C2=A0 is_bisextile =3D datetime->year % 4 =3D=3D 0
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&&a= mp; (datetime->year % 100 !=3D 0 || datetime->year % 400 =3D=3D 0);
Even if it works it is not fully correct...

is_bisextile =3D (datetime->year % 4 =3D=3D 0 &&
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (datetime->year = % 100 !=3D 0 || datetime->year % 400 =3D=3D 0)) ? true : false;

> +=C2=A0 for (i =3D 0;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0i < 12 && days >=3D ((i =3D= =3D 1 && is_bisextile =3D=3D true) ? 29 : months[i]);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0i++)
> +=C2=A0 =C2=A0 days -=3D ((i =3D=3D 1 && is_bisextile =3D=3D t= rue) ? 29 : months[i]);
>=C2=A0 =C2=A0 datetime->month =3D i + 1;
>=C2=A0 =C2=A0 datetime->day =3D 1 + days;
>=C2=A0 =C2=A0 datetime->hour =3D (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,
>=C2=A0 static inline int
>=C2=A0 grub_datetime2unixtime (const struct grub_datetime *datetime, gr= ub_int64_t *nix)
>=C2=A0 {
> -=C2=A0 grub_int32_t ret;
> +=C2=A0 grub_int64_t ret;
>=C2=A0 =C2=A0 int y4, ay;
> +=C2=A0 bool is_bisextile;
>=C2=A0 =C2=A0 const grub_uint16_t monthssum[12]
>=C2=A0 =C2=A0 =C2=A0 =3D { 0,
>=C2=A0 =C2=A0 =C2=A0 =C2=A031,
> @@ -75,15 +76,11 @@ grub_datetime2unixtime (const struct grub_datetime= *datetime, grub_int64_t *nix)
>=C2=A0 =C2=A0 const int SECPERHOUR =3D 60 * SECPERMIN;
>=C2=A0 =C2=A0 const int SECPERDAY =3D 24 * SECPERHOUR;
>=C2=A0 =C2=A0 const int SECPERYEAR =3D 365 * SECPERDAY;
> -=C2=A0 const int SECPER4YEARS =3D 4 * SECPERYEAR + SECPERDAY;
> +=C2=A0 const grub_int64_t SECPER4YEARS =3D 4 * SECPERYEAR + SECPERDAY= ;
>
> -=C2=A0 if (datetime->year > 2038 || datetime->year < 1901= )
> -=C2=A0 =C2=A0 return 0;
>=C2=A0 =C2=A0 if (datetime->month > 12 || datetime->month <= 1)
>=C2=A0 =C2=A0 =C2=A0 return 0;
>
> -=C2=A0 /* In the period of validity of unixtime all years divisible b= y 4
> -=C2=A0 =C2=A0 =C2=A0are bissextile*/
>=C2=A0 =C2=A0 /* Convenience: let's have 3 consecutive non-bissexti= le years
>=C2=A0 =C2=A0 =C2=A0 =C2=A0at the beginning of the epoch. So count from= 1973 instead of 1970 */
>=C2=A0 =C2=A0 ret =3D 3 * SECPERYEAR + SECPERDAY;
> @@ -94,13 +91,27 @@ grub_datetime2unixtime (const struct grub_datetime= *datetime, grub_int64_t *nix)
>=C2=A0 =C2=A0 ret +=3D y4 * SECPER4YEARS;
>=C2=A0 =C2=A0 ret +=3D ay * SECPERYEAR;
>
> +=C2=A0 /*
> +=C2=A0 =C2=A0* Correct above calculation (which assumes every 4 years= is a leap year)
> +=C2=A0 =C2=A0* to remove those "false leap years" that are = divisible by 100 but not 400.
> +=C2=A0 =C2=A0* Since this logic starts with seconds since 1973, 15 is= used because:
> +=C2=A0 =C2=A0*=C2=A0 - (1973 - 1) / 100 =3D 19 (floor due to integer = math)
> +=C2=A0 =C2=A0*=C2=A0 - (1973 - 1) / 400 =3D 4 (floor due to integer m= ath)
> +=C2=A0 =C2=A0*=C2=A0 - 19 - 4 - 15 =3D 0 (we want to start with no &q= uot;false leap years" at time
> +=C2=A0 =C2=A0*=C2=A0 =C2=A0 =C2=A0zero of 1973)
> +=C2=A0 =C2=A0*/
> +=C2=A0 ret -=3D ((datetime->year - 1) / 100 - (datetime->year -= 1) / 400 - 15)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0* SECPERDAY;
> +
>=C2=A0 =C2=A0 ret +=3D monthssum[datetime->month - 1] * SECPERDAY; > -=C2=A0 if (ay =3D=3D 3 && datetime->month >=3D 3)
> +=C2=A0 is_bisextile =3D ay =3D=3D 3
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&&a= mp; (datetime->year % 100 !=3D 0 || datetime->year % 400 =3D=3D 0);
Again...

is_bisextile =3D (ay =3D=3D 3 && (datetime->year % 100 !=3D 0 ||= datetime->year % 400 =3D=3D 0)) ? true : false;

> +=C2=A0 if (is_bisextile && datetime->month >=3D 3)

is_bisextile =3D=3D true && ...

>=C2=A0 =C2=A0 =C2=A0 ret +=3D SECPERDAY;
>
>=C2=A0 =C2=A0 ret +=3D (datetime->day - 1) * SECPERDAY;
>=C2=A0 =C2=A0 if ((datetime->day > months[datetime->month - 1]=
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0&& (!ay || datetime->month !=3D= 2 || datetime->day !=3D 29))
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0&& !(is_bisextile && datet= ime->month =3D=3D 2 && datetime->day =3D=3D 29))

is_bisextile =3D=3D true && ...

... and I would drop "is_" from variable name...

Daniel
--0000000000007c81eb063d46523e-- --===============4209367889758609628== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Content-Disposition: inline X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KR3J1Yi1kZXZl bCBtYWlsaW5nIGxpc3QKR3J1Yi1kZXZlbEBnbnUub3JnCmh0dHBzOi8vbGlzdHMuZ251Lm9yZy9t YWlsbWFuL2xpc3RpbmZvL2dydWItZGV2ZWwK --===============4209367889758609628==--