]> git.sur5r.net Git - u-boot/blob - drivers/rtc/date.c
dm: core: Update of_read_fmap_entry() for livetree
[u-boot] / drivers / rtc / date.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2001
4  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5  */
6
7 #include <common.h>
8 #include <command.h>
9 #include <errno.h>
10 #include <rtc.h>
11
12 #if defined(CONFIG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
13
14 #define FEBRUARY                2
15 #define STARTOFTIME             1970
16 #define SECDAY                  86400L
17 #define SECYR                   (SECDAY * 365)
18 #define leapyear(year)          ((year) % 4 == 0)
19 #define days_in_year(a)         (leapyear(a) ? 366 : 365)
20 #define days_in_month(a)        (month_days[(a) - 1])
21
22 static int month_days[12] = {
23         31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
24 };
25
26 static int month_offset[] = {
27         0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
28 };
29
30 /*
31  * This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
32  */
33 int rtc_calc_weekday(struct rtc_time *tm)
34 {
35         int leaps_to_date;
36         int last_year;
37         int day;
38
39         if (tm->tm_year < 1753)
40                 return -1;
41         last_year = tm->tm_year - 1;
42
43         /* Number of leap corrections to apply up to end of last year */
44         leaps_to_date = last_year / 4 - last_year / 100 + last_year / 400;
45
46         /*
47          * This year is a leap year if it is divisible by 4 except when it is
48          * divisible by 100 unless it is divisible by 400
49          *
50          * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 is.
51          */
52         if (tm->tm_year % 4 == 0 &&
53             ((tm->tm_year % 100 != 0) || (tm->tm_year % 400 == 0)) &&
54             tm->tm_mon > 2) {
55                 /* We are past Feb. 29 in a leap year */
56                 day = 1;
57         } else {
58                 day = 0;
59         }
60
61         day += last_year * 365 + leaps_to_date + month_offset[tm->tm_mon - 1] +
62                         tm->tm_mday;
63         tm->tm_wday = day % 7;
64
65         return 0;
66 }
67
68 int rtc_to_tm(int tim, struct rtc_time *tm)
69 {
70         register int i;
71         register long hms, day;
72
73         day = tim / SECDAY;
74         hms = tim % SECDAY;
75
76         /* Hours, minutes, seconds are easy */
77         tm->tm_hour = hms / 3600;
78         tm->tm_min = (hms % 3600) / 60;
79         tm->tm_sec = (hms % 3600) % 60;
80
81         /* Number of years in days */
82         for (i = STARTOFTIME; day >= days_in_year(i); i++)
83                 day -= days_in_year(i);
84         tm->tm_year = i;
85
86         /* Number of months in days left */
87         if (leapyear(tm->tm_year))
88                 days_in_month(FEBRUARY) = 29;
89         for (i = 1; day >= days_in_month(i); i++)
90                 day -= days_in_month(i);
91         days_in_month(FEBRUARY) = 28;
92         tm->tm_mon = i;
93
94         /* Days are what is left over (+1) from all that */
95         tm->tm_mday = day + 1;
96
97         /* Zero unused fields */
98         tm->tm_yday = 0;
99         tm->tm_isdst = 0;
100
101         /*
102          * Determine the day of week
103          */
104         return rtc_calc_weekday(tm);
105 }
106
107 /*
108  * Converts Gregorian date to seconds since 1970-01-01 00:00:00.
109  * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
110  * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
111  *
112  * [For the Julian calendar (which was used in Russia before 1917,
113  * Britain & colonies before 1752, anywhere else before 1582,
114  * and is still in use by some communities) leave out the
115  * -year / 100 + year / 400 terms, and add 10.]
116  *
117  * This algorithm was first published by Gauss (I think).
118  *
119  * WARNING: this function will overflow on 2106-02-07 06:28:16 on
120  * machines where long is 32-bit! (However, as time_t is signed, we
121  * will already get problems at other places on 2038-01-19 03:14:08)
122  */
123 unsigned long rtc_mktime(const struct rtc_time *tm)
124 {
125         int mon = tm->tm_mon;
126         int year = tm->tm_year;
127         int days, hours;
128
129         mon -= 2;
130         if (0 >= (int)mon) {    /* 1..12 -> 11, 12, 1..10 */
131                 mon += 12;      /* Puts Feb last since it has leap day */
132                 year -= 1;
133         }
134
135         days = (unsigned long)(year / 4 - year / 100 + year / 400 +
136                         367 * mon / 12 + tm->tm_mday) +
137                         year * 365 - 719499;
138         hours = days * 24 + tm->tm_hour;
139         return (hours * 60 + tm->tm_min) * 60 + tm->tm_sec;
140 }
141
142 #endif