linux-rtc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Alexandre Mergnat <amergnat@baylibre.com>
To: Alexandre Belloni <alexandre.belloni@bootlin.com>,
	 Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: "Uwe Kleine-König" <u.kleine-koenig@baylibre.com>,
	linux-rtc@vger.kernel.org, linux-kernel@vger.kernel.org,
	"Alexandre Mergnat" <amergnat@baylibre.com>
Subject: [PATCH v4 1/5] rtc: Make rtc_time64_to_tm() support dates before 1970
Date: Mon, 28 Apr 2025 12:06:47 +0200	[thread overview]
Message-ID: <20250428-enable-rtc-v4-1-2b2f7e3f9349@baylibre.com> (raw)
In-Reply-To: <20250428-enable-rtc-v4-0-2b2f7e3f9349@baylibre.com>

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(-)

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;

-- 
2.25.1


  reply	other threads:[~2025-04-28 10:07 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-04-28 10:06 [PATCH v4 0/5] Fix pre-1970 date handling Alexandre Mergnat
2025-04-28 10:06 ` Alexandre Mergnat [this message]
2025-04-28 16:59   ` [PATCH v4 1/5] rtc: Make rtc_time64_to_tm() support dates before 1970 Uwe Kleine-König
2025-05-06  7:58     ` Uwe Kleine-König
2025-05-28 10:33       ` Uwe Kleine-König
2025-04-28 10:06 ` [PATCH v4 2/5] rtc: Fix offset calculation for .start_secs < 0 Alexandre Mergnat
2025-04-28 17:00   ` Uwe Kleine-König
2025-04-28 10:06 ` [PATCH v4 3/5] rtc: test: Emit the seconds-since-1970 value instead of days-since-1970 amergnat
2025-04-28 10:06 ` [PATCH v4 4/5] rtc: test: Also test time and wday outcome of rtc_time64_to_tm() amergnat
2025-04-28 10:06 ` [PATCH v4 5/5] rtc: test: Test date conversion for dates starting in 1900 amergnat
2025-04-28 10:55 ` [PATCH v4 0/5] Fix pre-1970 date handling Alexandre Mergnat
2025-06-01 22:14 ` Alexandre Belloni

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=20250428-enable-rtc-v4-1-2b2f7e3f9349@baylibre.com \
    --to=amergnat@baylibre.com \
    --cc=alexandre.belloni@bootlin.com \
    --cc=baolin.wang@linux.alibaba.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rtc@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;
as well as URLs for NNTP newsgroup(s).