time/formatting/
component_provider.rs1use core::mem::MaybeUninit;
2use core::num::NonZero;
3
4use num_conv::prelude::*;
5
6use crate::format_description::Period;
7use crate::{
8 Date, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcDateTime, UtcOffset, Weekday,
9};
10
11#[derive(Debug)]
16pub(crate) struct DateState {
17 day: Option<NonZero<u8>>,
18 month: Option<Month>,
19 iso_week: Option<NonZero<u8>>,
20 iso_year_is_initialized: bool,
21 iso_year: MaybeUninit<i32>,
22}
23
24impl Default for DateState {
25 fn default() -> Self {
26 Self {
27 day: Default::default(),
28 month: Default::default(),
29 iso_week: Default::default(),
30 iso_year_is_initialized: Default::default(),
31 iso_year: MaybeUninit::uninit(),
32 }
33 }
34}
35
36macro_rules! unimplemented_methods {
37 ($(
38 $(#[$meta:meta])*
39 ($component:literal) $name:ident => $ret:ty;
40 )*) => {
41 $(
42 $(#[$meta])*
43 #[track_caller]
44 #[expect(unused_variables, reason = "better for auto-generation of method stubs")]
45 fn $name(&self, state: &mut Self::State) -> $ret {
46 unimplemented!(concat!("type does not supply ", $component, " components"))
47 }
48 )*
49 };
50}
51
52macro_rules! delegate_providers {
53 (
54 $target:ident {
55 $($method:ident -> $return:ty)*
56 }
57 ) => {$(
58 #[inline]
59 fn $method(&self, state: &mut Self::State) -> $return {
60 ComponentProvider::$method(&self.$target(), state)
61 }
62 )*};
63 (
64 $target:ident ($state:expr) {
65 $($method:ident -> $return:ty)*
66 }
67 ) => {$(
68 #[inline]
69 fn $method(&self, _: &mut Self::State) -> $return {
70 ComponentProvider::$method(&self.$target(), $state)
71 }
72 )*};
73}
74
75pub(crate) trait ComponentProvider {
81 type State: Default;
83
84 const SUPPLIES_DATE: bool = false;
87 const SUPPLIES_TIME: bool = false;
90 const SUPPLIES_OFFSET: bool = false;
93 const SUPPLIES_TIMESTAMP: bool = false;
96
97 unimplemented_methods! {
98 ("date") day => u8;
100 ("date") month => Month;
102 ("date") ordinal => u16;
104 ("date") weekday => Weekday;
106 ("date") iso_week_number => u8;
108 ("date") monday_based_week => u8;
110 ("date") sunday_based_week => u8;
112 ("date") calendar_year => i32;
114 ("date") iso_year => i32;
116 ("time") hour => u8;
118 ("time") minute => u8;
120 ("time") period => Period;
122 ("time") second => u8;
124 ("time") nanosecond => u32;
126 ("offset") offset_is_negative => bool;
128 ("offset") offset_is_utc => bool;
130 ("offset") offset_hour => i8;
132 ("offset") offset_minute => i8;
134 ("offset") offset_second => i8;
136 ("timestamp") unix_timestamp_seconds => i64;
138 ("timestamp") unix_timestamp_milliseconds => i64;
140 ("timestamp") unix_timestamp_microseconds => i128;
142 ("timestamp") unix_timestamp_nanoseconds => i128;
144 }
145}
146
147impl ComponentProvider for Time {
148 type State = ();
149
150 const SUPPLIES_TIME: bool = true;
151
152 #[inline]
153 fn hour(&self, _: &mut Self::State) -> u8 {
154 (*self).hour()
155 }
156
157 #[inline]
158 fn minute(&self, _: &mut Self::State) -> u8 {
159 (*self).minute()
160 }
161
162 #[inline]
163 fn period(&self, _: &mut Self::State) -> Period {
164 if (*self).hour() < 12 {
165 Period::Am
166 } else {
167 Period::Pm
168 }
169 }
170
171 #[inline]
172 fn second(&self, _: &mut Self::State) -> u8 {
173 (*self).second()
174 }
175
176 #[inline]
177 fn nanosecond(&self, _: &mut Self::State) -> u32 {
178 (*self).nanosecond()
179 }
180}
181
182impl ComponentProvider for Date {
183 type State = DateState;
184
185 const SUPPLIES_DATE: bool = true;
186
187 #[inline]
188 fn day(&self, state: &mut Self::State) -> u8 {
189 if let Some(day) = state.day {
190 return day.get();
191 }
192
193 let (_, month, day) = (*self).to_calendar_date();
194 state.month = Some(month);
195 state.day = Some(unsafe { NonZero::new_unchecked(day) });
197 day
198 }
199
200 #[inline]
201 fn month(&self, state: &mut Self::State) -> Month {
202 *state.month.get_or_insert_with(|| (*self).month())
203 }
204
205 #[inline]
206 fn ordinal(&self, _: &mut Self::State) -> u16 {
207 (*self).ordinal()
208 }
209
210 #[inline]
211 fn weekday(&self, _: &mut Self::State) -> Weekday {
212 (*self).weekday()
213 }
214
215 #[inline]
216 fn iso_week_number(&self, state: &mut Self::State) -> u8 {
217 if let Some(week) = state.iso_week {
218 return week.get();
219 }
220
221 let (iso_year, iso_week) = (*self).iso_year_week();
222 state.iso_year = MaybeUninit::new(iso_year);
223 state.iso_year_is_initialized = true;
224 state.iso_week = Some(unsafe { NonZero::new_unchecked(iso_week) });
226 iso_week
227 }
228
229 #[inline]
230 fn monday_based_week(&self, _: &mut Self::State) -> u8 {
231 (*self).monday_based_week()
232 }
233
234 #[inline]
235 fn sunday_based_week(&self, _: &mut Self::State) -> u8 {
236 (*self).sunday_based_week()
237 }
238
239 #[inline]
240 fn calendar_year(&self, _: &mut Self::State) -> i32 {
241 (*self).year()
242 }
243
244 #[inline]
245 fn iso_year(&self, state: &mut Self::State) -> i32 {
246 if state.iso_year_is_initialized {
247 return unsafe { state.iso_year.assume_init() };
249 }
250
251 let (iso_year, iso_week) = (*self).iso_year_week();
252 state.iso_year = MaybeUninit::new(iso_year);
253 state.iso_year_is_initialized = true;
254 state.iso_week = Some(unsafe { NonZero::new_unchecked(iso_week) });
256 iso_year
257 }
258}
259
260impl ComponentProvider for PrimitiveDateTime {
261 type State = DateState;
262
263 const SUPPLIES_DATE: bool = true;
264 const SUPPLIES_TIME: bool = true;
265
266 delegate_providers!(date {
267 day -> u8
268 month -> Month
269 ordinal -> u16
270 weekday -> Weekday
271 iso_week_number -> u8
272 monday_based_week -> u8
273 sunday_based_week -> u8
274 calendar_year -> i32
275 iso_year -> i32
276 });
277 delegate_providers!(time (&mut ()) {
278 hour -> u8
279 minute -> u8
280 period -> Period
281 second -> u8
282 nanosecond -> u32
283 });
284}
285
286impl ComponentProvider for UtcOffset {
287 type State = ();
288
289 const SUPPLIES_OFFSET: bool = true;
290
291 #[inline]
292 fn offset_is_negative(&self, _: &mut Self::State) -> bool {
293 (*self).is_negative()
294 }
295
296 #[inline]
297 fn offset_is_utc(&self, _state: &mut Self::State) -> bool {
298 (*self).is_utc()
299 }
300
301 #[inline]
302 fn offset_hour(&self, _: &mut Self::State) -> i8 {
303 (*self).whole_hours()
304 }
305
306 #[inline]
307 fn offset_minute(&self, _: &mut Self::State) -> i8 {
308 (*self).minutes_past_hour()
309 }
310
311 #[inline]
312 fn offset_second(&self, _: &mut Self::State) -> i8 {
313 (*self).seconds_past_minute()
314 }
315}
316
317impl ComponentProvider for UtcDateTime {
318 type State = DateState;
319
320 const SUPPLIES_DATE: bool = true;
321 const SUPPLIES_TIME: bool = true;
322 const SUPPLIES_OFFSET: bool = true;
323 const SUPPLIES_TIMESTAMP: bool = true;
324
325 delegate_providers!(date {
326 day -> u8
327 month -> Month
328 ordinal -> u16
329 weekday -> Weekday
330 iso_week_number -> u8
331 monday_based_week -> u8
332 sunday_based_week -> u8
333 calendar_year -> i32
334 iso_year -> i32
335 });
336 delegate_providers!(time (&mut ()) {
337 hour -> u8
338 minute -> u8
339 period -> Period
340 second -> u8
341 nanosecond -> u32
342 });
343
344 #[inline]
345 fn offset_is_negative(&self, _: &mut Self::State) -> bool {
346 false
347 }
348
349 #[inline]
350 fn offset_is_utc(&self, _state: &mut Self::State) -> bool {
351 true
352 }
353
354 #[inline]
355 fn offset_hour(&self, _: &mut Self::State) -> i8 {
356 0
357 }
358
359 #[inline]
360 fn offset_minute(&self, _: &mut Self::State) -> i8 {
361 0
362 }
363
364 #[inline]
365 fn offset_second(&self, _: &mut Self::State) -> i8 {
366 0
367 }
368
369 #[inline]
370 fn unix_timestamp_seconds(&self, _: &mut Self::State) -> i64 {
371 (*self).unix_timestamp()
372 }
373
374 #[inline]
375 fn unix_timestamp_milliseconds(&self, state: &mut Self::State) -> i64 {
376 (ComponentProvider::unix_timestamp_nanoseconds(self, state) / 1_000_000).truncate()
377 }
378
379 #[inline]
380 fn unix_timestamp_microseconds(&self, state: &mut Self::State) -> i128 {
381 ComponentProvider::unix_timestamp_nanoseconds(self, state) / 1_000
382 }
383
384 #[inline]
385 fn unix_timestamp_nanoseconds(&self, _: &mut Self::State) -> i128 {
386 (*self).unix_timestamp_nanos()
387 }
388}
389
390impl ComponentProvider for OffsetDateTime {
391 type State = DateState;
392
393 const SUPPLIES_DATE: bool = true;
394 const SUPPLIES_TIME: bool = true;
395 const SUPPLIES_OFFSET: bool = true;
396 const SUPPLIES_TIMESTAMP: bool = true;
397
398 delegate_providers!(date {
399 day -> u8
400 month -> Month
401 ordinal -> u16
402 weekday -> Weekday
403 iso_week_number -> u8
404 monday_based_week -> u8
405 sunday_based_week -> u8
406 calendar_year -> i32
407 iso_year -> i32
408 });
409 delegate_providers!(time (&mut ()) {
410 hour -> u8
411 minute -> u8
412 period -> Period
413 second -> u8
414 nanosecond -> u32
415 });
416 delegate_providers!(offset (&mut ()) {
417 offset_is_negative -> bool
418 offset_is_utc -> bool
419 offset_hour -> i8
420 offset_minute -> i8
421 offset_second -> i8
422 });
423
424 #[inline]
425 fn unix_timestamp_seconds(&self, _: &mut Self::State) -> i64 {
426 (*self).unix_timestamp()
427 }
428
429 #[inline]
430 fn unix_timestamp_milliseconds(&self, _: &mut Self::State) -> i64 {
431 ((*self).unix_timestamp_nanos() / 1_000_000) as i64
432 }
433
434 #[inline]
435 fn unix_timestamp_microseconds(&self, _: &mut Self::State) -> i128 {
436 (*self).unix_timestamp_nanos() / 1_000
437 }
438
439 #[inline]
440 fn unix_timestamp_nanoseconds(&self, _: &mut Self::State) -> i128 {
441 (*self).unix_timestamp_nanos()
442 }
443}