1use crate::Dt;
8
9pub struct LeapSecond {
10 pub ntp_timestamp: i64,
11 pub leap_seconds_after: i64,
12 pub utc_sec: i64,
13 pub tai_sec: i64,
14}
15
16pub const LEAP_SECS: &[LeapSecond] = &[
17 LeapSecond {
18 ntp_timestamp: 2272060800,
19 leap_seconds_after: 10,
20 utc_sec: -883656000,
21 tai_sec: -883655991, }, LeapSecond {
24 ntp_timestamp: 2287785600,
25 leap_seconds_after: 11,
26 utc_sec: -867931200,
27 tai_sec: -867931190, }, LeapSecond {
30 ntp_timestamp: 2303683200,
31 leap_seconds_after: 12,
32 utc_sec: -852033600,
33 tai_sec: -852033589, }, LeapSecond {
36 ntp_timestamp: 2335219200,
37 leap_seconds_after: 13,
38 utc_sec: -820497600,
39 tai_sec: -820497588, }, LeapSecond {
42 ntp_timestamp: 2366755200,
43 leap_seconds_after: 14,
44 utc_sec: -788961600,
45 tai_sec: -788961587, }, LeapSecond {
48 ntp_timestamp: 2398291200,
49 leap_seconds_after: 15,
50 utc_sec: -757425600,
51 tai_sec: -757425586, }, LeapSecond {
54 ntp_timestamp: 2429913600,
55 leap_seconds_after: 16,
56 utc_sec: -725803200,
57 tai_sec: -725803185, }, LeapSecond {
60 ntp_timestamp: 2461449600,
61 leap_seconds_after: 17,
62 utc_sec: -694267200,
63 tai_sec: -694267184, }, LeapSecond {
66 ntp_timestamp: 2492985600,
67 leap_seconds_after: 18,
68 utc_sec: -662731200,
69 tai_sec: -662731183, }, LeapSecond {
72 ntp_timestamp: 2524521600,
73 leap_seconds_after: 19,
74 utc_sec: -631195200,
75 tai_sec: -631195182, }, LeapSecond {
78 ntp_timestamp: 2571782400,
79 leap_seconds_after: 20,
80 utc_sec: -583934400,
81 tai_sec: -583934381, }, LeapSecond {
84 ntp_timestamp: 2603318400,
85 leap_seconds_after: 21,
86 utc_sec: -552398400,
87 tai_sec: -552398380, }, LeapSecond {
90 ntp_timestamp: 2634854400,
91 leap_seconds_after: 22,
92 utc_sec: -520862400,
93 tai_sec: -520862379, }, LeapSecond {
96 ntp_timestamp: 2698012800,
97 leap_seconds_after: 23,
98 utc_sec: -457704000,
99 tai_sec: -457703978, }, LeapSecond {
102 ntp_timestamp: 2776982400,
103 leap_seconds_after: 24,
104 utc_sec: -378734400,
105 tai_sec: -378734377, }, LeapSecond {
108 ntp_timestamp: 2840140800,
109 leap_seconds_after: 25,
110 utc_sec: -315576000,
111 tai_sec: -315575976, }, LeapSecond {
114 ntp_timestamp: 2871676800,
115 leap_seconds_after: 26,
116 utc_sec: -284040000,
117 tai_sec: -284039975, }, LeapSecond {
120 ntp_timestamp: 2918937600,
121 leap_seconds_after: 27,
122 utc_sec: -236779200,
123 tai_sec: -236779174, }, LeapSecond {
126 ntp_timestamp: 2950473600,
127 leap_seconds_after: 28,
128 utc_sec: -205243200,
129 tai_sec: -205243173, }, LeapSecond {
132 ntp_timestamp: 2982009600,
133 leap_seconds_after: 29,
134 utc_sec: -173707200,
135 tai_sec: -173707172, }, LeapSecond {
138 ntp_timestamp: 3029443200,
139 leap_seconds_after: 30,
140 utc_sec: -126273600,
141 tai_sec: -126273571, }, LeapSecond {
144 ntp_timestamp: 3076704000,
145 leap_seconds_after: 31,
146 utc_sec: -79012800,
147 tai_sec: -79012770, }, LeapSecond {
150 ntp_timestamp: 3124137600,
151 leap_seconds_after: 32,
152 utc_sec: -31579200,
153 tai_sec: -31579169, }, LeapSecond {
156 ntp_timestamp: 3345062400,
157 leap_seconds_after: 33,
158 utc_sec: 189345600,
159 tai_sec: 189345632, }, LeapSecond {
162 ntp_timestamp: 3439756800,
163 leap_seconds_after: 34,
164 utc_sec: 284040000,
165 tai_sec: 284040033, }, LeapSecond {
168 ntp_timestamp: 3550089600,
169 leap_seconds_after: 35,
170 utc_sec: 394372800,
171 tai_sec: 394372834, }, LeapSecond {
174 ntp_timestamp: 3644697600,
175 leap_seconds_after: 36,
176 utc_sec: 488980800,
177 tai_sec: 488980835, }, LeapSecond {
180 ntp_timestamp: 3692217600,
181 leap_seconds_after: 37,
182 utc_sec: 536500800,
183 tai_sec: 536500836, }, ];
186
187#[derive(Copy, Clone, Debug)]
188pub struct LeapInfo {
189 pub offset: i64,
190 pub leaps_inserted: i64,
191 pub is_leap_second: bool,
192}
193
194impl Dt {
195 #[inline]
196 pub const fn leap_seconds(&self, from_civil: bool) -> LeapInfo {
197 get_leap_seconds(self, from_civil)
198 }
199
200 #[inline]
201 pub const fn leap_seconds_using(&self, from_civil: bool, table: &[LeapSecond]) -> LeapInfo {
202 get_leap_seconds_with_table(self, from_civil, table)
203 }
204}
205
206#[inline]
207pub const fn get_leap_seconds(dt: &Dt, from_civil: bool) -> LeapInfo {
208 get_leap_seconds_with_table(dt, from_civil, &LEAP_SECS)
209}
210
211pub const fn get_leap_seconds_with_table(
212 dt: &Dt,
213 from_civil: bool,
214 table: &[LeapSecond],
215) -> LeapInfo {
216 let len = table.len();
217 if len == 0 {
218 return LeapInfo {
219 offset: 0,
220 leaps_inserted: 0,
221 is_leap_second: false,
222 };
223 }
224
225 let target = dt.sec();
226
227 let mut low = 0usize;
229 let mut high = len;
230
231 while low < high {
232 let mid = low + (high - low) / 2;
233 let entry_sec = if from_civil {
234 table[mid].utc_sec
235 } else {
236 table[mid].tai_sec
237 };
238
239 if entry_sec <= target {
240 low = mid + 1;
241 } else {
242 high = mid;
243 }
244 }
245
246 if low == 0 {
248 return LeapInfo {
249 offset: 0,
250 leaps_inserted: 0,
251 is_leap_second: false,
252 };
253 }
254
255 let idx = low - 1;
256 let entry = &table[idx];
257 let entry_sec = if from_civil {
258 entry.utc_sec
259 } else {
260 entry.tai_sec
261 };
262
263 let is_leap = target == entry_sec;
264
265 LeapInfo {
266 offset: entry.leap_seconds_after,
267 leaps_inserted: (idx + 1) as i64,
268 is_leap_second: is_leap,
269 }
270}