2 * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
4 * This file is released under the GPLv2. See the COPYING file for more
10 #define LS_NONE 0x00 /* non-leap second entry */
11 #define LS_LS 0x10 /* previous second was leap */
13 #define LS_MASK (LS_LS)
15 #define LS_YM2DATE(y, m, f) ((y) << 8 | (f) | (m))
16 #define LS_DATE2Y(d) ((d) >> 8)
17 #define LS_DATE2M(d) ((d) & 0xf)
18 #define LS_DATE2F(d) ((d) & LS_MASK)
20 struct leap_sec_info
{
26 * List of TOD clocks for each of the leap seconds
28 static struct leap_sec_info leap_secs
[] = {
29 { 0xC3870CB9BB600000ULL
, LS_YM2DATE(2009, 1, LS_LS
), },
30 { 0xBE251097973C0000ULL
, LS_YM2DATE(2006, 1, LS_LS
), },
31 { 0xB1962F9305180000ULL
, LS_YM2DATE(1999, 1, LS_LS
), },
32 { 0xAEE3EFA402F40000ULL
, LS_YM2DATE(1997, 7, LS_LS
), },
33 { 0xAC34336FECD00000ULL
, LS_YM2DATE(1996, 1, LS_LS
), },
34 { 0xA981F380EAAC0000ULL
, LS_YM2DATE(1994, 7, LS_LS
), },
35 { 0xA7B70ABEB8880000ULL
, LS_YM2DATE(1993, 7, LS_LS
), },
36 { 0xA5EC21FC86640000ULL
, LS_YM2DATE(1992, 7, LS_LS
), },
37 { 0xA33C65C870400000ULL
, LS_YM2DATE(1991, 1, LS_LS
), },
38 { 0xA1717D063E1C0000ULL
, LS_YM2DATE(1990, 1, LS_LS
), },
39 { 0x9DDA69A557F80000ULL
, LS_YM2DATE(1988, 1, LS_LS
), },
40 { 0x995D40F517D40000ULL
, LS_YM2DATE(1985, 7, LS_LS
), },
41 { 0x95C62D9431B00000ULL
, LS_YM2DATE(1983, 7, LS_LS
), },
42 { 0x93FB44D1FF8C0000ULL
, LS_YM2DATE(1982, 7, LS_LS
), },
43 { 0x92305C0FCD680000ULL
, LS_YM2DATE(1981, 7, LS_LS
), },
44 { 0x8F809FDBB7440000ULL
, LS_YM2DATE(1980, 1, LS_LS
), },
45 { 0x8DB5B71985200000ULL
, LS_YM2DATE(1979, 1, LS_LS
), },
46 { 0x8BEACE5752FC0000ULL
, LS_YM2DATE(1978, 1, LS_LS
), },
47 { 0x8A1FE59520D80000ULL
, LS_YM2DATE(1977, 1, LS_LS
), },
48 { 0x8853BAF578B40000ULL
, LS_YM2DATE(1976, 1, LS_LS
), },
49 { 0x8688D23346900000ULL
, LS_YM2DATE(1975, 1, LS_LS
), },
50 { 0x84BDE971146C0000ULL
, LS_YM2DATE(1974, 1, LS_LS
), },
51 { 0x82F300AEE2480000ULL
, LS_YM2DATE(1973, 1, LS_LS
), },
52 { 0x820BA9811E240000ULL
, LS_YM2DATE(1972, 7, LS_LS
), },
53 { 0x8126D60E46000000ULL
, LS_YM2DATE(1972, 1, LS_NONE
), }, /* UTC begins */
54 { 0x0000000000000000ULL
, LS_YM2DATE(1900, 1, LS_NONE
), }, /* TOD begins */
58 * Number of days passed since the beginning of the year
60 static const short int month_offsets
[2][12] = {
61 /* J F M A M J J A S O N D */
62 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
63 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335},
66 struct datetime
*parse_tod(struct datetime
*dt
, u64 tod
)
74 * find the most recent info for this tod (i), as well as for one
75 * that's one second ahead (j)
77 for (i
=0; leap_secs
[i
].tod
> tod
; i
++)
79 for (j
=0; leap_secs
[j
].tod
> (tod
+ CLK_SEC
); j
++)
82 tod
-= leap_secs
[i
].tod
;
84 dt
->dy
= LS_DATE2Y(leap_secs
[i
].date
);
85 dt
->dm
= LS_DATE2M(leap_secs
[i
].date
);
88 * If we're in the leap second, let's pretend we're a second
89 * earlier, and then add it back in at the end of the function
93 if ((i
!= j
) && (LS_DATE2F(leap_secs
[j
].date
) == LS_LS
)) {
98 /* The month should be 1 or 7! */
99 if ((dt
->dm
!= 1) && (dt
->dm
!= 7))
103 * At this point, we have a TOD value to add to a struct datetime.
104 * We don't have to worry about leap seconds. Life is good.
108 if (leap_year((dt
->dm
== 1) ? dt
->dy
: (dt
->dy
+1)))
109 done
= tod
< (CLK_YEAR
+ CLK_DAY
);
111 done
= tod
< CLK_YEAR
;
116 if ((dt
->dm
== 1 && leap_year(dt
->dy
)) ||
117 (dt
->dm
== 7 && leap_year(dt
->dy
+1)))
118 tod
-= (CLK_YEAR
+ CLK_DAY
);
126 * At this point, we have the year and we know the month is either Jan
127 * or Jul; let's get an actual month
130 dt
->dd
= tod
/ CLK_DAY
;
131 tod
-= dt
->dd
* CLK_DAY
;
134 leap
= leap_year(dt
->dy
);
135 i
= month_offsets
[leap
][dt
->dm
- 1];
137 while((dt
->dm
< 12) &&
138 ((i
+ dt
->dd
) >= month_offsets
[leap
][dt
->dm
]))
141 dt
->dd
= dt
->dd
+ i
- month_offsets
[leap
][dt
->dm
-1];
143 if ((dt
->dm
< 12) || (dt
->dd
< 31))
154 * At this point, we have the year, the month, and even the day;
155 * let's get the hours, minutes and seconds
158 dt
->th
= tod
/ CLK_HOUR
;
159 tod
-= dt
->th
* CLK_HOUR
;
161 dt
->tm
= tod
/ CLK_MIN
;
162 tod
-= dt
->tm
* CLK_MIN
;
164 dt
->ts
= tod
/ CLK_SEC
;
165 tod
-= dt
->ts
* CLK_SEC
;
168 * If we borrowed a second before, then add it back! (We borrow only
169 * for leap seconds in progress.)
173 dt
->tmicro
= (u32
) (tod
>> 12);