1 /* SPDX-License-Identifier: GPL-2.0-or-later */
7 #include <console/console.h>
11 #define STARTOFTIME 1970
13 #define SECYR (SECDAY * 365)
14 #define LEAP_YEAR(year) (((year) % 4 == 0 && (year) % 100 != 0) || (year) % 400 == 0)
15 #define DAYS_IN_YEAR(a) (LEAP_YEAR(a) ? 366 : 365)
16 #define DAYS_IN_MONTH(a) (month_days[(a) - 1])
18 static const char *const weekdays
[] = {
19 "Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "Satur"
23 static int rtc_calc_weekday(struct rtc_time
*tm
)
25 /* In Zeller's rule, January and February are treated as if they
26 are months 13 and 14 of the previous year (March is still month 3) */
27 const int zyear
= ((tm
->mon
< 3) ? tm
->year
- 1 : tm
->year
);
28 const int q
= tm
->mday
;
29 const int m
= (tm
->mon
< 3) ? tm
->mon
+ 12 : tm
->mon
;
30 const int K
= zyear
% 100;
31 const int J
= zyear
/ 100;
34 * Because of the way the modulo operator works with negative numbers,
35 * the traditional formulation of Zeller's rule must be modified
36 * slightly to make the numerator positive (i.e., add 5J instead of
37 * subtracting 2J). Also subtract 1 so that Sunday is day 0.
39 const int h
= (q
+ (13 * (m
+ 1)) / 5
40 + K
+ (K
/ 4) + (J
/ 4) + (5 * J
) - 1) % 7;
46 int rtc_to_tm(int tim
, struct rtc_time
*tm
)
48 int month_days
[12] = {
49 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
52 register long hms
, day
;
57 /* Hours, minutes, seconds are easy */
58 tm
->hour
= hms
/ 3600;
59 tm
->min
= (hms
% 3600) / 60;
60 tm
->sec
= (hms
% 3600) % 60;
62 /* Number of years in days */
63 for (i
= STARTOFTIME
; day
>= DAYS_IN_YEAR(i
); i
++)
64 day
-= DAYS_IN_YEAR(i
);
67 /* Number of months in days left */
68 if (LEAP_YEAR(tm
->year
))
69 DAYS_IN_MONTH(FEBRUARY
) = 29;
70 for (i
= 1; day
>= DAYS_IN_MONTH(i
); i
++)
71 day
-= DAYS_IN_MONTH(i
);
72 DAYS_IN_MONTH(FEBRUARY
) = 28;
75 /* Days are what is left over (+1) from all that */
78 /* Determine the day of week */
79 return rtc_calc_weekday(tm
);
83 * Converts Gregorian date to seconds since 1970-01-01 00:00:00.
84 * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
85 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
87 * [For the Julian calendar (which was used in Russia before 1917,
88 * Britain & colonies before 1752, anywhere else before 1582,
89 * and is still in use by some communities) leave out the
90 * -year / 100 + year / 400 terms, and add 10.]
92 * This algorithm was first published by Gauss (I think).
94 * WARNING: this function will overflow on 2106-02-07 06:28:16 on
95 * machines where long is 32-bit! (However, as time_t is signed, we
96 * will already get problems at other places on 2038-01-19 03:14:08)
98 unsigned long rtc_mktime(const struct rtc_time
*tm
)
105 if (0 >= (int)mon
) { /* 1..12 -> 11, 12, 1..10 */
106 mon
+= 12; /* Puts Feb last since it has leap day */
110 days
= (unsigned long)(year
/ 4 - year
/ 100 + year
/ 400 +
111 367 * mon
/ 12 + tm
->mday
) +
113 hours
= days
* 24 + tm
->hour
;
114 return (hours
* 60 + tm
->min
) * 60 + tm
->sec
;
117 void rtc_display(const struct rtc_time
*tm
)
119 printk(BIOS_INFO
, "Date: %5d-%02d-%02d (%sday) Time: %2d:%02d:%02d\n",
120 tm
->year
, tm
->mon
, tm
->mday
,
121 (tm
->wday
< 0 || tm
->wday
> 6) ? "unknown " : weekdays
[tm
->wday
],
122 tm
->hour
, tm
->min
, tm
->sec
);
125 static int rtc_month_days(unsigned int month
, unsigned int year
)
127 int month_days
[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
129 return month_days
[month
] + (LEAP_YEAR(year
) && month
== 1);
132 int rtc_invalid(const struct rtc_time
*tm
)
134 if (tm
->sec
> 59 || tm
->min
> 59 || tm
->hour
> 23 || tm
->mon
== 0 || tm
->mon
> 12 ||
135 tm
->year
< 1970 || tm
->mday
> rtc_month_days(tm
->mon
- 1, tm
->year
))