Linux kernel -stable discussions
 help / color / mirror / Atom feed
From: Alexandre Belloni <alexandre.belloni@bootlin.com>
To: Cassio Neri <cassio.neri@gmail.com>
Cc: "Uwe Kleine-König" <u.kleine-koenig@baylibre.com>,
	"Alessandro Zummo" <a.zummo@towertech.it>,
	"Alexandre Mergnat" <amergnat@baylibre.com>,
	stable@vger.kernel.org, linux-rtc@vger.kernel.org
Subject: Re: [PATCH 5.10.y 2/3] rtc: Make rtc_time64_to_tm() support dates before 1970
Date: Wed, 11 Jun 2025 09:33:50 +0200	[thread overview]
Message-ID: <20250611073350f9e928ec@mail.local> (raw)
In-Reply-To: <CAOfgUPg0Z6e5+awuqVMa7QUPiJ7aPp-dX6QNk80Y-bhpBYcsoQ@mail.gmail.com>

Hello Cassio,

On 10/06/2025 21:31:48+0100, Cassio Neri wrote:
> Hi all,
> 
> Although untested, I'm pretty sure that with very small changes, the
> previous revision (1d1bb12) can handle dates prior to 1970-01-01 with no
> need to add extra branches or arithmetic operations. Indeed, 1d1bb12
> contains:
> 
> <code>
> /* time must be positive */
> days = div_s64_rem(time, 86400, &secs);
> 
> /* day of the week, 1970-01-01 was a Thursday */
> tm->tm_wday = (days + 4) % 7;
> 
> /* long comments */
> 
> udays = ((u32) days) + 719468;
> </code>
> 
> This could have been changed to:
> 
> <code>
> /* time must be >=  -719468 * 86400 which corresponds to 0000-03-01 */
> udays = div_u64_rem(time + 719468 * 86400, 86400, &secs);
> 
> /* day of the week, 0000-03-01 was a Wednesday (in the proleptic Gregorian
> calendar)  */
> tm->tm_wday = (days + 3) % 7;
> 
> /* long comments */
> </code>
> 
> Indeed, the addition of 719468 * 86400 to `time` makes `days` to be 719468
> more than it should be. Therefore, in the calculation of `udays`, the
> addition of 719468 becomes unnecessary and thus, `udays == days`. Moreover,
> this means that `days` can be removed altogether and replaced by `udays`.
> (Not the other way around because in the remaining code `udays` must be
> u32.)
> 
> Now, 719468 % 7 = 1 and thus tm->wday is 1 day after what it should be and
> we correct that by adding 3 instead of 4.
> 
> Therefore, I suggest these changes on top of 1d1bb12 instead of those made
> in 7df4cfe. Since you're working on this, can I please kindly suggest two
> other changes?
> 
> 1) Change the reference provided in the long comment. It should say, "The
> following algorithm is, basically, Figure 12 of Neri and Schneider [1]" and
> [1] should refer to the published article:
> 
>    Neri C, Schneider L. Euclidean affine functions and their application to
> calendar algorithms. Softw Pract Exper. 2023;53(4):937-970. doi:
> 10.1002/spe.3172
>    https://doi.org/10.1002/spe.3172
> 
> The article is much better written and clearer than the pre-print currently
> referred to.
> 

Thanks for your input, I wanted to look again at your paper and make those
optimizations which is why I took so long to review the original patch.
Unfortunately, I didn't have the time before the merge window.

I would also gladly take patches for this if you are up for the task.

> 2) Function rtc_time64_to_tm_test_date_range in drivers/rtc/lib_test.c, is
> a kunit test that checks the result for everyday in a 160000 years range
> starting at 1970-01-01. It'd be nice if this test is adapted to the new
> code and starts at 1900-01-01 (technically, it could start at 0000-03-01
> but since tm->year counts from 1900, it would be weird to see tm->year ==
> -1900 to mean that the calendar year is 0.) Also 160000 is definitely an
> overkill (my bad!) and a couple of thousands of years, say 3000, should be
> more than safe for anyone. :-)

This is also something on my radar as some have been complaining about the time
it takes to run those tests.

> 
> Many thanks,
> Cassio.
> 
> 
> 
> On Tue, 10 Jun 2025 at 08:35, Uwe Kleine-König <u.kleine-koenig@baylibre.com>
> wrote:
> 
> > From: Alexandre Mergnat <amergnat@baylibre.com>
> >
> > commit 7df4cfef8b351fec3156160bedfc7d6d29de4cce upstream.
> >
> > Conversion of dates before 1970 is still relevant today because these
> > dates are reused on some hardwares to store dates bigger than the
> > maximal date that is representable in the device's native format.
> > This prominently and very soon affects the hardware covered by the
> > rtc-mt6397 driver that can only natively store dates in the interval
> > 1900-01-01 up to 2027-12-31. So to store the date 2028-01-01 00:00:00
> > to such a device, rtc_time64_to_tm() must do the right thing for
> > time=-2208988800.
> >
> > Signed-off-by: Alexandre Mergnat <amergnat@baylibre.com>
> > Reviewed-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
> > Link:
> > https://lore.kernel.org/r/20250428-enable-rtc-v4-1-2b2f7e3f9349@baylibre.com
> > Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
> > Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
> > ---
> >  drivers/rtc/lib.c | 24 +++++++++++++++++++-----
> >  1 file changed, 19 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/rtc/lib.c b/drivers/rtc/lib.c
> > index fe361652727a..13b5b1f20465 100644
> > --- a/drivers/rtc/lib.c
> > +++ b/drivers/rtc/lib.c
> > @@ -46,24 +46,38 @@ EXPORT_SYMBOL(rtc_year_days);
> >   * rtc_time64_to_tm - converts time64_t to rtc_time.
> >   *
> >   * @time:      The number of seconds since 01-01-1970 00:00:00.
> > - *             (Must be positive.)
> > + *             Works for values since at least 1900
> >   * @tm:                Pointer to the struct rtc_time.
> >   */
> >  void rtc_time64_to_tm(time64_t time, struct rtc_time *tm)
> >  {
> > -       unsigned int secs;
> > -       int days;
> > +       int days, secs;
> >
> >         u64 u64tmp;
> >         u32 u32tmp, udays, century, day_of_century, year_of_century, year,
> >                 day_of_year, month, day;
> >         bool is_Jan_or_Feb, is_leap_year;
> >
> > -       /* time must be positive */
> > +       /*
> > +        * Get days and seconds while preserving the sign to
> > +        * handle negative time values (dates before 1970-01-01)
> > +        */
> >         days = div_s64_rem(time, 86400, &secs);
> >
> > +       /*
> > +        * We need 0 <= secs < 86400 which isn't given for negative
> > +        * values of time. Fixup accordingly.
> > +        */
> > +       if (secs < 0) {
> > +               days -= 1;
> > +               secs += 86400;
> > +       }
> > +
> >         /* day of the week, 1970-01-01 was a Thursday */
> >         tm->tm_wday = (days + 4) % 7;
> > +       /* Ensure tm_wday is always positive */
> > +       if (tm->tm_wday < 0)
> > +               tm->tm_wday += 7;
> >
> >         /*
> >          * The following algorithm is, basically, Proposition 6.3 of Neri
> > @@ -93,7 +107,7 @@ void rtc_time64_to_tm(time64_t time, struct rtc_time
> > *tm)
> >          * thus, is slightly different from [1].
> >          */
> >
> > -       udays           = ((u32) days) + 719468;
> > +       udays           = days + 719468;
> >
> >         u32tmp          = 4 * udays + 3;
> >         century         = u32tmp / 146097;
> > --
> > 2.49.0
> >
> >

  parent reply	other threads:[~2025-06-11  7:33 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-06-10  7:34 [PATCH 5.10.y 0/3] rtc: backport support for handling dates before 1970 Uwe Kleine-König
2025-06-10  7:34 ` [PATCH 5.10.y 1/3] rtc: Improve performance of rtc_time64_to_tm(). Add tests Uwe Kleine-König
2025-06-11 13:24   ` Sasha Levin
2025-06-10  7:34 ` [PATCH 5.10.y 2/3] rtc: Make rtc_time64_to_tm() support dates before 1970 Uwe Kleine-König
2025-06-10 20:33   ` Cassio Neri
     [not found]   ` <CAOfgUPg0Z6e5+awuqVMa7QUPiJ7aPp-dX6QNk80Y-bhpBYcsoQ@mail.gmail.com>
2025-06-11  6:08     ` Uwe Kleine-König
2025-06-11  7:33     ` Alexandre Belloni [this message]
2025-06-11 18:32       ` Cassio Neri
2025-06-11 13:16   ` Sasha Levin
2025-06-10  7:35 ` [PATCH 5.10.y 3/3] rtc: Fix offset calculation for .start_secs < 0 Uwe Kleine-König
2025-06-11 13:24   ` Sasha Levin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250611073350f9e928ec@mail.local \
    --to=alexandre.belloni@bootlin.com \
    --cc=a.zummo@towertech.it \
    --cc=amergnat@baylibre.com \
    --cc=cassio.neri@gmail.com \
    --cc=linux-rtc@vger.kernel.org \
    --cc=stable@vger.kernel.org \
    --cc=u.kleine-koenig@baylibre.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox