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