1use num_conv::prelude::*;
2
3use crate::format_description::Period;
4use crate::formatting::{
5 Day, IsoWeekNumber, MondayBasedWeek, OptionDay, OptionIsoWeekNumber, OptionYear, Ordinal,
6 SundayBasedWeek, Year,
7};
8use crate::time::{Hours, Minutes, Nanoseconds, Seconds};
9use crate::utc_offset::{Hours as OffsetHours, Minutes as OffsetMinutes, Seconds as OffsetSeconds};
10use crate::{
11 Date, Month, OffsetDateTime, PlainDateTime, Time, Timestamp, UtcDateTime, UtcOffset, Weekday,
12};
13
14#[derive(Debug, Default)]
19pub(crate) struct DateState {
20 day: OptionDay,
21 month: Option<Month>,
22 iso_week: OptionIsoWeekNumber,
23 iso_year: OptionYear,
24}
25
26#[derive(Debug, Default)]
31pub(crate) struct TimestampState {
32 date: Option<Date>,
33 time: Option<Time>,
34 date_state: <Date as ComponentProvider>::State,
35}
36
37macro_rules! unimplemented_methods {
38 ($(
39 $(#[$meta:meta])*
40 ($component:literal) $name:ident => $ret:ty;
41 )*) => {
42 $(
43 $(#[$meta])*
44 #[track_caller]
45 #[expect(unused_variables, reason = "better for auto-generation of method stubs")]
46 fn $name(&self, state: &mut Self::State) -> $ret {
47 unimplemented!(concat!("type does not supply ", $component, " components"))
48 }
49 )*
50 };
51}
52
53macro_rules! delegate_providers {
54 (
55 $target:ident {
56 $($method:ident -> $return:ty)*
57 }
58 ) => {$(
59 #[inline]
60 fn $method(&self, state: &mut Self::State) -> $return {
61 ComponentProvider::$method(&self.$target(), state)
62 }
63 )*};
64 (
65 $target:ident ($state:expr) {
66 $($method:ident -> $return:ty)*
67 }
68 ) => {$(
69 #[inline]
70 fn $method(&self, _: &mut Self::State) -> $return {
71 ComponentProvider::$method(&self.$target(), $state)
72 }
73 )*};
74}
75
76pub(crate) trait ComponentProvider {
82 type State: Default;
84
85 const SUPPLIES_DATE: bool = false;
88 const SUPPLIES_TIME: bool = false;
91 const SUPPLIES_OFFSET: bool = false;
94 const SUPPLIES_TIMESTAMP: bool = false;
97
98 unimplemented_methods! {
99 ("date") day => Day;
101 ("date") month => Month;
103 ("date") ordinal => Ordinal;
105 ("date") weekday => Weekday;
107 ("date") iso_week_number => IsoWeekNumber;
109 ("date") monday_based_week => MondayBasedWeek;
111 ("date") sunday_based_week => SundayBasedWeek;
113 ("date") calendar_year => Year;
115 ("date") iso_year => Year;
117 ("time") hour => Hours;
119 ("time") minute => Minutes;
121 ("time") period => Period;
123 ("time") second => Seconds;
125 ("time") nanosecond => Nanoseconds;
127 ("offset") offset_is_negative => bool;
129 ("offset") offset_is_utc => bool;
131 ("offset") offset_hour => OffsetHours;
133 ("offset") offset_minute => OffsetMinutes;
135 ("offset") offset_second => OffsetSeconds;
137 ("timestamp") unix_timestamp_seconds => i64;
139 ("timestamp") unix_timestamp_milliseconds => i64;
141 ("timestamp") unix_timestamp_microseconds => i128;
143 ("timestamp") unix_timestamp_nanoseconds => i128;
145 }
146}
147
148impl ComponentProvider for Time {
149 type State = ();
150
151 const SUPPLIES_TIME: bool = true;
152
153 #[inline]
154 fn hour(&self, _: &mut Self::State) -> Hours {
155 self.as_hms_nano_ranged().0
156 }
157
158 #[inline]
159 fn minute(&self, _: &mut Self::State) -> Minutes {
160 self.as_hms_nano_ranged().1
161 }
162
163 #[inline]
164 fn period(&self, _: &mut Self::State) -> Period {
165 if (*self).hour() < 12 {
166 Period::Am
167 } else {
168 Period::Pm
169 }
170 }
171
172 #[inline]
173 fn second(&self, _: &mut Self::State) -> Seconds {
174 self.as_hms_nano_ranged().2
175 }
176
177 #[inline]
178 fn nanosecond(&self, _: &mut Self::State) -> Nanoseconds {
179 self.as_hms_nano_ranged().3
180 }
181}
182
183impl ComponentProvider for Date {
184 type State = DateState;
185
186 const SUPPLIES_DATE: bool = true;
187
188 #[inline]
189 fn day(&self, state: &mut Self::State) -> Day {
190 if let Some(day) = state.day.get() {
191 return day;
192 }
193
194 let (_, month, day) = (*self).to_calendar_date();
195 let day = unsafe { Day::new_unchecked(day) };
197 state.month = Some(month);
198 state.day = OptionDay::Some(day);
199 day
200 }
201
202 #[inline]
203 fn month(&self, state: &mut Self::State) -> Month {
204 *state.month.get_or_insert_with(|| (*self).month())
205 }
206
207 #[inline]
208 fn ordinal(&self, _: &mut Self::State) -> Ordinal {
209 unsafe { Ordinal::new_unchecked((*self).ordinal()) }
211 }
212
213 #[inline]
214 fn weekday(&self, _: &mut Self::State) -> Weekday {
215 (*self).weekday()
216 }
217
218 #[inline]
219 fn iso_week_number(&self, state: &mut Self::State) -> IsoWeekNumber {
220 if let Some(week) = state.iso_week.get() {
221 return week;
222 }
223
224 let (iso_year, iso_week) = (*self).iso_year_week();
225 let iso_week = unsafe { IsoWeekNumber::new_unchecked(iso_week) };
227 state.iso_year = OptionYear::Some(unsafe { Year::new_unchecked(iso_year) });
229 state.iso_week = OptionIsoWeekNumber::Some(iso_week);
230 iso_week
231 }
232
233 #[inline]
234 fn monday_based_week(&self, _: &mut Self::State) -> MondayBasedWeek {
235 unsafe { MondayBasedWeek::new_unchecked((*self).monday_based_week()) }
237 }
238
239 #[inline]
240 fn sunday_based_week(&self, _: &mut Self::State) -> SundayBasedWeek {
241 unsafe { SundayBasedWeek::new_unchecked((*self).sunday_based_week()) }
243 }
244
245 #[inline]
246 fn calendar_year(&self, _: &mut Self::State) -> Year {
247 unsafe { Year::new_unchecked((*self).year()) }
249 }
250
251 #[inline]
252 fn iso_year(&self, state: &mut Self::State) -> Year {
253 if let Some(iso_year) = state.iso_year.get() {
254 return iso_year;
255 }
256
257 let (iso_year, iso_week) = (*self).iso_year_week();
258 let iso_year = unsafe { Year::new_unchecked(iso_year) };
260 state.iso_year = OptionYear::Some(iso_year);
261 state.iso_week =
263 OptionIsoWeekNumber::Some(unsafe { IsoWeekNumber::new_unchecked(iso_week) });
264 iso_year
265 }
266}
267
268impl ComponentProvider for PlainDateTime {
269 type State = DateState;
270
271 const SUPPLIES_DATE: bool = true;
272 const SUPPLIES_TIME: bool = true;
273
274 delegate_providers!(date {
275 day -> Day
276 month -> Month
277 ordinal -> Ordinal
278 weekday -> Weekday
279 iso_week_number -> IsoWeekNumber
280 monday_based_week -> MondayBasedWeek
281 sunday_based_week -> SundayBasedWeek
282 calendar_year -> Year
283 iso_year -> Year
284 });
285 delegate_providers!(time (&mut ()) {
286 hour -> Hours
287 minute -> Minutes
288 period -> Period
289 second -> Seconds
290 nanosecond -> Nanoseconds
291 });
292}
293
294impl ComponentProvider for UtcOffset {
295 type State = ();
296
297 const SUPPLIES_OFFSET: bool = true;
298
299 #[inline]
300 fn offset_is_negative(&self, _: &mut Self::State) -> bool {
301 (*self).is_negative()
302 }
303
304 #[inline]
305 fn offset_is_utc(&self, _state: &mut Self::State) -> bool {
306 (*self).is_utc()
307 }
308
309 #[inline]
310 fn offset_hour(&self, _: &mut Self::State) -> OffsetHours {
311 (*self).as_hms_ranged().0
312 }
313
314 #[inline]
315 fn offset_minute(&self, _: &mut Self::State) -> OffsetMinutes {
316 (*self).as_hms_ranged().1
317 }
318
319 #[inline]
320 fn offset_second(&self, _: &mut Self::State) -> OffsetSeconds {
321 (*self).as_hms_ranged().2
322 }
323}
324
325impl ComponentProvider for UtcDateTime {
326 type State = DateState;
327
328 const SUPPLIES_DATE: bool = true;
329 const SUPPLIES_TIME: bool = true;
330 const SUPPLIES_OFFSET: bool = true;
331 const SUPPLIES_TIMESTAMP: bool = true;
332
333 delegate_providers!(date {
334 day -> Day
335 month -> Month
336 ordinal -> Ordinal
337 weekday -> Weekday
338 iso_week_number -> IsoWeekNumber
339 monday_based_week -> MondayBasedWeek
340 sunday_based_week -> SundayBasedWeek
341 calendar_year -> Year
342 iso_year -> Year
343 });
344 delegate_providers!(time (&mut ()) {
345 hour -> Hours
346 minute -> Minutes
347 period -> Period
348 second -> Seconds
349 nanosecond -> Nanoseconds
350 });
351
352 #[inline]
353 fn offset_is_negative(&self, _: &mut Self::State) -> bool {
354 false
355 }
356
357 #[inline]
358 fn offset_is_utc(&self, _state: &mut Self::State) -> bool {
359 true
360 }
361
362 #[inline]
363 fn offset_hour(&self, _: &mut Self::State) -> OffsetHours {
364 OffsetHours::new_static::<0>()
365 }
366
367 #[inline]
368 fn offset_minute(&self, _: &mut Self::State) -> OffsetMinutes {
369 OffsetMinutes::new_static::<0>()
370 }
371
372 #[inline]
373 fn offset_second(&self, _: &mut Self::State) -> OffsetSeconds {
374 OffsetSeconds::new_static::<0>()
375 }
376
377 #[inline]
378 fn unix_timestamp_seconds(&self, _: &mut Self::State) -> i64 {
379 (*self).unix_timestamp()
380 }
381
382 #[inline]
383 fn unix_timestamp_milliseconds(&self, state: &mut Self::State) -> i64 {
384 (ComponentProvider::unix_timestamp_nanoseconds(self, state) / 1_000_000).truncate()
385 }
386
387 #[inline]
388 fn unix_timestamp_microseconds(&self, state: &mut Self::State) -> i128 {
389 ComponentProvider::unix_timestamp_nanoseconds(self, state) / 1_000
390 }
391
392 #[inline]
393 fn unix_timestamp_nanoseconds(&self, _: &mut Self::State) -> i128 {
394 (*self).unix_timestamp_nanos()
395 }
396}
397
398impl ComponentProvider for OffsetDateTime {
399 type State = DateState;
400
401 const SUPPLIES_DATE: bool = true;
402 const SUPPLIES_TIME: bool = true;
403 const SUPPLIES_OFFSET: bool = true;
404 const SUPPLIES_TIMESTAMP: bool = true;
405
406 delegate_providers!(date {
407 day -> Day
408 month -> Month
409 ordinal -> Ordinal
410 weekday -> Weekday
411 iso_week_number -> IsoWeekNumber
412 monday_based_week -> MondayBasedWeek
413 sunday_based_week -> SundayBasedWeek
414 calendar_year -> Year
415 iso_year -> Year
416 });
417 delegate_providers!(time (&mut ()) {
418 hour -> Hours
419 minute -> Minutes
420 period -> Period
421 second -> Seconds
422 nanosecond -> Nanoseconds
423 });
424 delegate_providers!(offset (&mut ()) {
425 offset_is_negative -> bool
426 offset_is_utc -> bool
427 offset_hour -> OffsetHours
428 offset_minute -> OffsetMinutes
429 offset_second -> OffsetSeconds
430 });
431
432 #[inline]
433 fn unix_timestamp_seconds(&self, _: &mut Self::State) -> i64 {
434 (*self).unix_timestamp()
435 }
436
437 #[inline]
438 fn unix_timestamp_milliseconds(&self, _: &mut Self::State) -> i64 {
439 ((*self).unix_timestamp_nanos() / 1_000_000) as i64
440 }
441
442 #[inline]
443 fn unix_timestamp_microseconds(&self, _: &mut Self::State) -> i128 {
444 (*self).unix_timestamp_nanos() / 1_000
445 }
446
447 #[inline]
448 fn unix_timestamp_nanoseconds(&self, _: &mut Self::State) -> i128 {
449 (*self).unix_timestamp_nanos()
450 }
451}
452
453impl ComponentProvider for Timestamp {
454 type State = TimestampState;
455
456 const SUPPLIES_DATE: bool = true;
457 const SUPPLIES_TIME: bool = true;
458 const SUPPLIES_OFFSET: bool = true;
459 const SUPPLIES_TIMESTAMP: bool = true;
460
461 #[inline]
462 fn day(&self, state: &mut Self::State) -> Day {
463 let date = state.date.get_or_insert_with(|| self.date());
464 ComponentProvider::day(date, &mut state.date_state)
465 }
466
467 #[inline]
468 fn month(&self, state: &mut Self::State) -> Month {
469 let date = state.date.get_or_insert_with(|| self.date());
470 ComponentProvider::month(date, &mut state.date_state)
471 }
472
473 #[inline]
474 fn ordinal(&self, state: &mut Self::State) -> Ordinal {
475 let date = state.date.get_or_insert_with(|| self.date());
476 ComponentProvider::ordinal(date, &mut state.date_state)
477 }
478
479 #[inline]
480 fn weekday(&self, state: &mut Self::State) -> Weekday {
481 let date = state.date.get_or_insert_with(|| self.date());
482 ComponentProvider::weekday(date, &mut state.date_state)
483 }
484
485 #[inline]
486 fn iso_week_number(&self, state: &mut Self::State) -> IsoWeekNumber {
487 let date = state.date.get_or_insert_with(|| self.date());
488 ComponentProvider::iso_week_number(date, &mut state.date_state)
489 }
490
491 #[inline]
492 fn monday_based_week(&self, state: &mut Self::State) -> MondayBasedWeek {
493 let date = state.date.get_or_insert_with(|| self.date());
494 ComponentProvider::monday_based_week(date, &mut state.date_state)
495 }
496
497 #[inline]
498 fn sunday_based_week(&self, state: &mut Self::State) -> SundayBasedWeek {
499 let date = state.date.get_or_insert_with(|| self.date());
500 ComponentProvider::sunday_based_week(date, &mut state.date_state)
501 }
502
503 #[inline]
504 fn calendar_year(&self, state: &mut Self::State) -> Year {
505 let date = state.date.get_or_insert_with(|| self.date());
506 ComponentProvider::calendar_year(date, &mut state.date_state)
507 }
508
509 #[inline]
510 fn iso_year(&self, state: &mut Self::State) -> Year {
511 let date = state.date.get_or_insert_with(|| self.date());
512 ComponentProvider::iso_year(date, &mut state.date_state)
513 }
514
515 #[inline]
516 fn hour(&self, state: &mut Self::State) -> Hours {
517 let time = state.time.get_or_insert_with(|| self.time());
518 ComponentProvider::hour(time, &mut ())
519 }
520
521 #[inline]
522 fn minute(&self, state: &mut Self::State) -> Minutes {
523 let time = state.time.get_or_insert_with(|| self.time());
524 ComponentProvider::minute(time, &mut ())
525 }
526
527 #[inline]
528 fn period(&self, state: &mut Self::State) -> Period {
529 let time = state.time.get_or_insert_with(|| self.time());
530 ComponentProvider::period(time, &mut ())
531 }
532
533 #[inline]
534 fn second(&self, state: &mut Self::State) -> Seconds {
535 let time = state.time.get_or_insert_with(|| self.time());
536 ComponentProvider::second(time, &mut ())
537 }
538
539 #[inline]
540 fn nanosecond(&self, _: &mut Self::State) -> Nanoseconds {
541 self.as_parts_ranged().1
544 }
545
546 #[inline]
547 fn offset_is_negative(&self, _: &mut Self::State) -> bool {
548 false
549 }
550
551 #[inline]
552 fn offset_is_utc(&self, _: &mut Self::State) -> bool {
553 true
554 }
555
556 #[inline]
557 fn offset_hour(&self, _: &mut Self::State) -> OffsetHours {
558 OffsetHours::new_static::<0>()
559 }
560
561 #[inline]
562 fn offset_minute(&self, _: &mut Self::State) -> OffsetMinutes {
563 OffsetMinutes::new_static::<0>()
564 }
565
566 #[inline]
567 fn offset_second(&self, _: &mut Self::State) -> OffsetSeconds {
568 OffsetSeconds::new_static::<0>()
569 }
570
571 #[inline]
572 fn unix_timestamp_seconds(&self, _: &mut Self::State) -> i64 {
573 self.as_seconds()
574 }
575
576 #[inline]
577 fn unix_timestamp_milliseconds(&self, _: &mut Self::State) -> i64 {
578 self.as_milliseconds()
579 }
580
581 #[inline]
582 fn unix_timestamp_microseconds(&self, _: &mut Self::State) -> i128 {
583 self.as_microseconds()
584 }
585
586 #[inline]
587 fn unix_timestamp_nanoseconds(&self, _: &mut Self::State) -> i128 {
588 self.as_nanoseconds()
589 }
590}