diff mbox series

[v4,1/5] rtc: Make rtc_time64_to_tm() support dates before 1970

Message ID 20250428-enable-rtc-v4-1-2b2f7e3f9349@baylibre.com
State Accepted
Headers show
Series Fix pre-1970 date handling | expand

Commit Message

Alexandre Mergnat April 28, 2025, 10:06 a.m. UTC
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>
---
 drivers/rtc/lib.c | 24 +++++++++++++++++++-----
 1 file changed, 19 insertions(+), 5 deletions(-)

Comments

Uwe Kleine-König April 28, 2025, 4:59 p.m. UTC | #1
Hello Alexandre,

On Mon, Apr 28, 2025 at 12:06:47PM +0200, Alexandre Mergnat wrote:
> 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>

Given this problem starts to bite in 2028 I'd like to see this (and the
next) patch backported to stable. If you want a Fixes: line, maybe
34bbdc12d04e ("rtc: mt6359: Add RTC hardware range and add support for
start-year") is sensible here as this is the commit that introduced the
requirement to handle negative timestamps. (The drivers that made use
of the offset feature already before that commit all had
.range_min >= 0, and so are not affected by this problem.)

With my Debian kernel team member hat on, I even welcome
34bbdc12d04e2f18a2ca96351c59e40b62da3314 being backported to 6.12.y
given that the next Debian stable release ("trixie") will use 6.12.y and
will likely matter longer than 2027.

Apart from that:

Reviewed-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>

Best regards
Uwe
Uwe Kleine-König May 6, 2025, 7:58 a.m. UTC | #2
Hello Alexandre,

On Mon, Apr 28, 2025 at 06:59:33PM +0200, Uwe Kleine-König wrote:
> On Mon, Apr 28, 2025 at 12:06:47PM +0200, Alexandre Mergnat wrote:
> > 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>
> 
> Given this problem starts to bite in 2028 I'd like to see this (and the
> next) patch backported to stable. If you want a Fixes: line, maybe
> 34bbdc12d04e ("rtc: mt6359: Add RTC hardware range and add support for
> start-year") is sensible here as this is the commit that introduced the
> requirement to handle negative timestamps. (The drivers that made use
> of the offset feature already before that commit all had
> .range_min >= 0, and so are not affected by this problem.)

Given that we're already at v6.15-rc5 I wonder if there is a chance to
get these changes reviewed and applied before v6.15. Would a pull
request help you? If yes, should it only contain the fixes, or also the
updated tests?

Best regards
Uwe
Uwe Kleine-König May 28, 2025, 10:33 a.m. UTC | #3
Hello Alexandre,

On Tue, May 06, 2025 at 09:58:32AM +0200, Uwe Kleine-König wrote:
> On Mon, Apr 28, 2025 at 06:59:33PM +0200, Uwe Kleine-König wrote:
> > On Mon, Apr 28, 2025 at 12:06:47PM +0200, Alexandre Mergnat wrote:
> > > 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>
> > 
> > Given this problem starts to bite in 2028 I'd like to see this (and the
> > next) patch backported to stable. If you want a Fixes: line, maybe
> > 34bbdc12d04e ("rtc: mt6359: Add RTC hardware range and add support for
> > start-year") is sensible here as this is the commit that introduced the
> > requirement to handle negative timestamps. (The drivers that made use
> > of the offset feature already before that commit all had
> > .range_min >= 0, and so are not affected by this problem.)
> 
> Given that we're already at v6.15-rc5 I wonder if there is a chance to
> get these changes reviewed and applied before v6.15. Would a pull
> request help you? If yes, should it only contain the fixes, or also the
> updated tests?

We missed to get the patches in for v6.15 :-\

I see you recently applied some patches in your rtc-next branch, but
this series isn't included. That makes me wonder if you still have it on
your radar.

My offer to provide you a pull request still stands, just tell me if I
should include the tests if you want me to provide such a PR.

Best regards
Uwe
diff mbox series

Patch

diff --git a/drivers/rtc/lib.c b/drivers/rtc/lib.c
index fe361652727a3f8cb116c78b5aeea74eb90080b5..13b5b1f2046510d1a552473c441b89e23faa6793 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;