Skip to content

Commit 7df4cfe

Browse files
amergnatalexandrebelloni
authored andcommitted
rtc: Make rtc_time64_to_tm() support dates before 1970
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 <[email protected]> Reviewed-by: Uwe Kleine-König <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexandre Belloni <[email protected]>
1 parent 1e15a68 commit 7df4cfe

File tree

1 file changed

+19
-5
lines changed

1 file changed

+19
-5
lines changed

drivers/rtc/lib.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,24 +46,38 @@ EXPORT_SYMBOL(rtc_year_days);
4646
* rtc_time64_to_tm - converts time64_t to rtc_time.
4747
*
4848
* @time: The number of seconds since 01-01-1970 00:00:00.
49-
* (Must be positive.)
49+
* Works for values since at least 1900
5050
* @tm: Pointer to the struct rtc_time.
5151
*/
5252
void rtc_time64_to_tm(time64_t time, struct rtc_time *tm)
5353
{
54-
unsigned int secs;
55-
int days;
54+
int days, secs;
5655

5756
u64 u64tmp;
5857
u32 u32tmp, udays, century, day_of_century, year_of_century, year,
5958
day_of_year, month, day;
6059
bool is_Jan_or_Feb, is_leap_year;
6160

62-
/* time must be positive */
61+
/*
62+
* Get days and seconds while preserving the sign to
63+
* handle negative time values (dates before 1970-01-01)
64+
*/
6365
days = div_s64_rem(time, 86400, &secs);
6466

67+
/*
68+
* We need 0 <= secs < 86400 which isn't given for negative
69+
* values of time. Fixup accordingly.
70+
*/
71+
if (secs < 0) {
72+
days -= 1;
73+
secs += 86400;
74+
}
75+
6576
/* day of the week, 1970-01-01 was a Thursday */
6677
tm->tm_wday = (days + 4) % 7;
78+
/* Ensure tm_wday is always positive */
79+
if (tm->tm_wday < 0)
80+
tm->tm_wday += 7;
6781

6882
/*
6983
* 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)
93107
* thus, is slightly different from [1].
94108
*/
95109

96-
udays = ((u32) days) + 719468;
110+
udays = days + 719468;
97111

98112
u32tmp = 4 * udays + 3;
99113
century = u32tmp / 146097;

0 commit comments

Comments
 (0)