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