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, PrimitiveDateTime, Time, Timestamp, UtcDateTime, UtcOffset,
12 Weekday,
13};
14
15#[derive(Debug, Default)]
20pub(crate) struct DateState {
21 day: OptionDay,
22 month: Option<Month>,
23 iso_week: OptionIsoWeekNumber,
24 iso_year: OptionYear,
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 *state.month.get_or_insert_with(|| (*self).month())
206 }
207
208 #[inline]
209 fn ordinal(&self, _: &mut Self::State) -> Ordinal {
210 unsafe { Ordinal::new_unchecked((*self).ordinal()) }
212 }
213
214 #[inline]
215 fn weekday(&self, _: &mut Self::State) -> Weekday {
216 (*self).weekday()
217 }
218
219 #[inline]
220 fn iso_week_number(&self, state: &mut Self::State) -> IsoWeekNumber {
221 if let Some(week) = state.iso_week.get() {
222 return week;
223 }
224
225 let (iso_year, iso_week) = (*self).iso_year_week();
226 let iso_week = unsafe { IsoWeekNumber::new_unchecked(iso_week) };
228 state.iso_year = OptionYear::Some(unsafe { Year::new_unchecked(iso_year) });
230 state.iso_week = OptionIsoWeekNumber::Some(iso_week);
231 iso_week
232 }
233
234 #[inline]
235 fn monday_based_week(&self, _: &mut Self::State) -> MondayBasedWeek {
236 unsafe { MondayBasedWeek::new_unchecked((*self).monday_based_week()) }
238 }
239
240 #[inline]
241 fn sunday_based_week(&self, _: &mut Self::State) -> SundayBasedWeek {
242 unsafe { SundayBasedWeek::new_unchecked((*self).sunday_based_week()) }
244 }
245
246 #[inline]
247 fn calendar_year(&self, _: &mut Self::State) -> Year {
248 unsafe { Year::new_unchecked((*self).year()) }
250 }
251
252 #[inline]
253 fn iso_year(&self, state: &mut Self::State) -> Year {
254 if let Some(iso_year) = state.iso_year.get() {
255 return iso_year;
256 }
257
258 let (iso_year, iso_week) = (*self).iso_year_week();
259 let iso_year = unsafe { Year::new_unchecked(iso_year) };
261 state.iso_year = OptionYear::Some(iso_year);
262 state.iso_week =
264 OptionIsoWeekNumber::Some(unsafe { IsoWeekNumber::new_unchecked(iso_week) });
265 iso_year
266 }
267}
268
269impl ComponentProvider for PrimitiveDateTime {
270 type State = DateState;
271
272 const SUPPLIES_DATE: bool = true;
273 const SUPPLIES_TIME: bool = true;
274
275 delegate_providers!(date {
276 day -> Day
277 month -> Month
278 ordinal -> Ordinal
279 weekday -> Weekday
280 iso_week_number -> IsoWeekNumber
281 monday_based_week -> MondayBasedWeek
282 sunday_based_week -> SundayBasedWeek
283 calendar_year -> Year
284 iso_year -> Year
285 });
286 delegate_providers!(time (&mut ()) {
287 hour -> Hours
288 minute -> Minutes
289 period -> Period
290 second -> Seconds
291 nanosecond -> Nanoseconds
292 });
293}
294
295impl ComponentProvider for UtcOffset {
296 type State = ();
297
298 const SUPPLIES_OFFSET: bool = true;
299
300 #[inline]
301 fn offset_is_negative(&self, _: &mut Self::State) -> bool {
302 (*self).is_negative()
303 }
304
305 #[inline]
306 fn offset_is_utc(&self, _state: &mut Self::State) -> bool {
307 (*self).is_utc()
308 }
309
310 #[inline]
311 fn offset_hour(&self, _: &mut Self::State) -> OffsetHours {
312 (*self).as_hms_ranged().0
313 }
314
315 #[inline]
316 fn offset_minute(&self, _: &mut Self::State) -> OffsetMinutes {
317 (*self).as_hms_ranged().1
318 }
319
320 #[inline]
321 fn offset_second(&self, _: &mut Self::State) -> OffsetSeconds {
322 (*self).as_hms_ranged().2
323 }
324}
325
326impl ComponentProvider for UtcDateTime {
327 type State = DateState;
328
329 const SUPPLIES_DATE: bool = true;
330 const SUPPLIES_TIME: bool = true;
331 const SUPPLIES_OFFSET: bool = true;
332 const SUPPLIES_TIMESTAMP: bool = true;
333
334 delegate_providers!(date {
335 day -> Day
336 month -> Month
337 ordinal -> Ordinal
338 weekday -> Weekday
339 iso_week_number -> IsoWeekNumber
340 monday_based_week -> MondayBasedWeek
341 sunday_based_week -> SundayBasedWeek
342 calendar_year -> Year
343 iso_year -> Year
344 });
345 delegate_providers!(time (&mut ()) {
346 hour -> Hours
347 minute -> Minutes
348 period -> Period
349 second -> Seconds
350 nanosecond -> Nanoseconds
351 });
352
353 #[inline]
354 fn offset_is_negative(&self, _: &mut Self::State) -> bool {
355 false
356 }
357
358 #[inline]
359 fn offset_is_utc(&self, _state: &mut Self::State) -> bool {
360 true
361 }
362
363 #[inline]
364 fn offset_hour(&self, _: &mut Self::State) -> OffsetHours {
365 OffsetHours::new_static::<0>()
366 }
367
368 #[inline]
369 fn offset_minute(&self, _: &mut Self::State) -> OffsetMinutes {
370 OffsetMinutes::new_static::<0>()
371 }
372
373 #[inline]
374 fn offset_second(&self, _: &mut Self::State) -> OffsetSeconds {
375 OffsetSeconds::new_static::<0>()
376 }
377
378 #[inline]
379 fn unix_timestamp_seconds(&self, _: &mut Self::State) -> i64 {
380 (*self).unix_timestamp()
381 }
382
383 #[inline]
384 fn unix_timestamp_milliseconds(&self, state: &mut Self::State) -> i64 {
385 (ComponentProvider::unix_timestamp_nanoseconds(self, state) / 1_000_000).truncate()
386 }
387
388 #[inline]
389 fn unix_timestamp_microseconds(&self, state: &mut Self::State) -> i128 {
390 ComponentProvider::unix_timestamp_nanoseconds(self, state) / 1_000
391 }
392
393 #[inline]
394 fn unix_timestamp_nanoseconds(&self, _: &mut Self::State) -> i128 {
395 (*self).unix_timestamp_nanos()
396 }
397}
398
399impl ComponentProvider for OffsetDateTime {
400 type State = DateState;
401
402 const SUPPLIES_DATE: bool = true;
403 const SUPPLIES_TIME: bool = true;
404 const SUPPLIES_OFFSET: bool = true;
405 const SUPPLIES_TIMESTAMP: bool = true;
406
407 delegate_providers!(date {
408 day -> Day
409 month -> Month
410 ordinal -> Ordinal
411 weekday -> Weekday
412 iso_week_number -> IsoWeekNumber
413 monday_based_week -> MondayBasedWeek
414 sunday_based_week -> SundayBasedWeek
415 calendar_year -> Year
416 iso_year -> Year
417 });
418 delegate_providers!(time (&mut ()) {
419 hour -> Hours
420 minute -> Minutes
421 period -> Period
422 second -> Seconds
423 nanosecond -> Nanoseconds
424 });
425 delegate_providers!(offset (&mut ()) {
426 offset_is_negative -> bool
427 offset_is_utc -> bool
428 offset_hour -> OffsetHours
429 offset_minute -> OffsetMinutes
430 offset_second -> OffsetSeconds
431 });
432
433 #[inline]
434 fn unix_timestamp_seconds(&self, _: &mut Self::State) -> i64 {
435 (*self).unix_timestamp()
436 }
437
438 #[inline]
439 fn unix_timestamp_milliseconds(&self, _: &mut Self::State) -> i64 {
440 ((*self).unix_timestamp_nanos() / 1_000_000) as i64
441 }
442
443 #[inline]
444 fn unix_timestamp_microseconds(&self, _: &mut Self::State) -> i128 {
445 (*self).unix_timestamp_nanos() / 1_000
446 }
447
448 #[inline]
449 fn unix_timestamp_nanoseconds(&self, _: &mut Self::State) -> i128 {
450 (*self).unix_timestamp_nanos()
451 }
452}
453
454impl ComponentProvider for Timestamp {
455 type State = TimestampState;
456
457 const SUPPLIES_DATE: bool = true;
458 const SUPPLIES_TIME: bool = true;
459 const SUPPLIES_OFFSET: bool = true;
460 const SUPPLIES_TIMESTAMP: bool = true;
461
462 #[inline]
463 fn day(&self, state: &mut Self::State) -> Day {
464 let date = state.date.get_or_insert_with(|| self.date());
465 ComponentProvider::day(date, &mut state.date_state)
466 }
467
468 #[inline]
469 fn month(&self, state: &mut Self::State) -> Month {
470 let date = state.date.get_or_insert_with(|| self.date());
471 ComponentProvider::month(date, &mut state.date_state)
472 }
473
474 #[inline]
475 fn ordinal(&self, state: &mut Self::State) -> Ordinal {
476 let date = state.date.get_or_insert_with(|| self.date());
477 ComponentProvider::ordinal(date, &mut state.date_state)
478 }
479
480 #[inline]
481 fn weekday(&self, state: &mut Self::State) -> Weekday {
482 let date = state.date.get_or_insert_with(|| self.date());
483 ComponentProvider::weekday(date, &mut state.date_state)
484 }
485
486 #[inline]
487 fn iso_week_number(&self, state: &mut Self::State) -> IsoWeekNumber {
488 let date = state.date.get_or_insert_with(|| self.date());
489 ComponentProvider::iso_week_number(date, &mut state.date_state)
490 }
491
492 #[inline]
493 fn monday_based_week(&self, state: &mut Self::State) -> MondayBasedWeek {
494 let date = state.date.get_or_insert_with(|| self.date());
495 ComponentProvider::monday_based_week(date, &mut state.date_state)
496 }
497
498 #[inline]
499 fn sunday_based_week(&self, state: &mut Self::State) -> SundayBasedWeek {
500 let date = state.date.get_or_insert_with(|| self.date());
501 ComponentProvider::sunday_based_week(date, &mut state.date_state)
502 }
503
504 #[inline]
505 fn calendar_year(&self, state: &mut Self::State) -> Year {
506 let date = state.date.get_or_insert_with(|| self.date());
507 ComponentProvider::calendar_year(date, &mut state.date_state)
508 }
509
510 #[inline]
511 fn iso_year(&self, state: &mut Self::State) -> Year {
512 let date = state.date.get_or_insert_with(|| self.date());
513 ComponentProvider::iso_year(date, &mut state.date_state)
514 }
515
516 #[inline]
517 fn hour(&self, state: &mut Self::State) -> Hours {
518 let time = state.time.get_or_insert_with(|| self.time());
519 ComponentProvider::hour(time, &mut ())
520 }
521
522 #[inline]
523 fn minute(&self, state: &mut Self::State) -> Minutes {
524 let time = state.time.get_or_insert_with(|| self.time());
525 ComponentProvider::minute(time, &mut ())
526 }
527
528 #[inline]
529 fn period(&self, state: &mut Self::State) -> Period {
530 let time = state.time.get_or_insert_with(|| self.time());
531 ComponentProvider::period(time, &mut ())
532 }
533
534 #[inline]
535 fn second(&self, state: &mut Self::State) -> Seconds {
536 let time = state.time.get_or_insert_with(|| self.time());
537 ComponentProvider::second(time, &mut ())
538 }
539
540 #[inline]
541 fn nanosecond(&self, _: &mut Self::State) -> Nanoseconds {
542 self.as_parts_ranged().1
545 }
546
547 #[inline]
548 fn offset_is_negative(&self, _: &mut Self::State) -> bool {
549 false
550 }
551
552 #[inline]
553 fn offset_is_utc(&self, _: &mut Self::State) -> bool {
554 true
555 }
556
557 #[inline]
558 fn offset_hour(&self, _: &mut Self::State) -> OffsetHours {
559 OffsetHours::new_static::<0>()
560 }
561
562 #[inline]
563 fn offset_minute(&self, _: &mut Self::State) -> OffsetMinutes {
564 OffsetMinutes::new_static::<0>()
565 }
566
567 #[inline]
568 fn offset_second(&self, _: &mut Self::State) -> OffsetSeconds {
569 OffsetSeconds::new_static::<0>()
570 }
571
572 #[inline]
573 fn unix_timestamp_seconds(&self, _: &mut Self::State) -> i64 {
574 self.as_seconds()
575 }
576
577 #[inline]
578 fn unix_timestamp_milliseconds(&self, _: &mut Self::State) -> i64 {
579 self.as_milliseconds()
580 }
581
582 #[inline]
583 fn unix_timestamp_microseconds(&self, _: &mut Self::State) -> i128 {
584 self.as_microseconds()
585 }
586
587 #[inline]
588 fn unix_timestamp_nanoseconds(&self, _: &mut Self::State) -> i128 {
589 self.as_nanoseconds()
590 }
591}