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)
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
)
28 /* In Zeller's rule, January and February are treated as if they
29 are months 13 and 14 of the previous year (March is still month 3) */
30 const int zyear
= ((tm
->mon
< 3) ? tm
->year
- 1 : tm
->year
);
31 const int q
= tm
->mday
;
32 const int m
= (tm
->mon
< 3) ? tm
->mon
+ 12 : tm
->mon
;
33 const int K
= zyear
% 100;
34 const int J
= zyear
/ 100;
37 * Because of the way the modulo operator works with negative numbers,
38 * the traditional formulation of Zeller's rule must be modified
39 * slightly to make the numerator positive (i.e., add 5J instead of
40 * subtracting 2J). Also subtract 1 so that Sunday is day 0.
42 const int h
= (q
+ (13 * (m
+ 1)) / 5
43 + K
+ (K
/ 4) + (J
/ 4) + (5 * J
) - 1) % 7;
49 int rtc_to_tm(int tim
, struct rtc_time
*tm
)
51 int month_days
[12] = {
52 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
55 register long hms
, day
;
60 /* Hours, minutes, seconds are easy */
61 tm
->hour
= hms
/ 3600;
62 tm
->min
= (hms
% 3600) / 60;
63 tm
->sec
= (hms
% 3600) % 60;
65 /* Number of years in days */
66 for (i
= STARTOFTIME
; day
>= DAYS_IN_YEAR(i
); i
++)
67 day
-= DAYS_IN_YEAR(i
);
70 /* Number of months in days left */
71 if (LEAP_YEAR(tm
->year
))
72 DAYS_IN_MONTH(FEBRUARY
) = 29;
73 for (i
= 1; day
>= DAYS_IN_MONTH(i
); i
++)
74 day
-= DAYS_IN_MONTH(i
);
75 DAYS_IN_MONTH(FEBRUARY
) = 28;
78 /* Days are what is left over (+1) from all that */
81 /* Determine the day of week */
82 return rtc_calc_weekday(tm
);
86 * Converts Gregorian date to seconds since 1970-01-01 00:00:00.
87 * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
88 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
90 * [For the Julian calendar (which was used in Russia before 1917,
91 * Britain & colonies before 1752, anywhere else before 1582,
92 * and is still in use by some communities) leave out the
93 * -year / 100 + year / 400 terms, and add 10.]
95 * This algorithm was first published by Gauss (I think).
97 * WARNING: this function will overflow on 2106-02-07 06:28:16 on
98 * machines where long is 32-bit! (However, as time_t is signed, we
99 * will already get problems at other places on 2038-01-19 03:14:08)
101 unsigned long rtc_mktime(const struct rtc_time
*tm
)
108 if (0 >= (int)mon
) { /* 1..12 -> 11, 12, 1..10 */
109 mon
+= 12; /* Puts Feb last since it has leap day */
113 days
= (unsigned long)(year
/ 4 - year
/ 100 + year
/ 400 +
114 367 * mon
/ 12 + tm
->mday
) +
116 hours
= days
* 24 + tm
->hour
;
117 return (hours
* 60 + tm
->min
) * 60 + tm
->sec
;
120 void rtc_display(const struct rtc_time
*tm
)
122 printk(BIOS_INFO
, "Date: %5d-%02d-%02d (%sday) Time: %2d:%02d:%02d\n",
123 tm
->year
, tm
->mon
, tm
->mday
,
124 (tm
->wday
< 0 || tm
->wday
> 6) ? "unknown " : weekdays
[tm
->wday
],
125 tm
->hour
, tm
->min
, tm
->sec
);