Skip to main content

deep_time/
macros.rs

1//! Macros for easy unit conversion and
2//! [`Dt`](../struct.Dt.html) construction.
3//!
4//! Each macro expands to a call on an equivalent [`Dt`](../struct.Dt.html)
5//! method.
6//!
7//! ## Overview
8//!
9//! ### Unit → attoseconds
10//!
11//! Returns total attoseconds as `i128`.
12//!
13//! - [`fs!`]
14//! - [`ps!`]
15//! - [`ns!`]
16//! - [`us!`]
17//! - [`ms!`]
18//! - [`sec!`]
19//! - [`sec_f!`]
20//! - [`mins!`]
21//! - [`hours!`]
22//! - [`days!`]
23//! - [`days_f!`]
24//! - [`weeks!`]
25//!
26//! ### Attoseconds → unit
27//!
28//! Returns a whole-unit count as `i128`, or a lossy
29//! [`Real`](../type.Real.html) for the `_f` forms.
30//!
31//! - [`as_fs!`]
32//! - [`as_ps!`]
33//! - [`as_ns!`]
34//! - [`as_us!`]
35//! - [`as_ms!`]
36//! - [`as_sec!`]
37//! - [`as_sec_f!`]
38//! - [`as_mins!`]
39//! - [`as_hours!`]
40//! - [`as_days!`]
41//! - [`as_days_f!`]
42//! - [`as_weeks!`]
43//!
44//! ### Instant / duration
45//!
46//! Returns a [`Dt`](../struct.Dt.html).
47//!
48//! - [`dt!`]
49//! - [`from_sec!`]
50//! - [`from_sec_f!`]
51//! - [`from_ms!`]
52//! - [`from_us!`]
53//! - [`from_ns!`]
54//! - [`from_ps!`]
55//! - [`from_fs!`]
56//! - [`from_days_f!`]
57//! - [`from_ymd!`]
58//! - [`from_jd!`]
59//! - [`from_jd_f!`]
60//! - [`from_mjd!`]
61//! - [`from_mjd_f!`]
62//!
63//! ## Import paths
64//!
65//! All macros can be imported from this module:
66//!
67//! ```
68//! use deep_time::macros::{from_ns, ms, sec};
69//! ```
70//!
71//! These are also available at the crate root via `use deep_time::{…}`:
72//!
73//! - [`ns!`]
74//! - [`ms!`]
75//! - [`days_f!`]
76//! - [`dt!`]
77//! - [`from_sec_f!`]
78//! - [`from_ymd!`]
79//!
80//! The rest are available only under `deep_time::macros`.
81//! `use deep_time::macros::*` brings in every macro listed above.
82//!
83//! ## How they work
84//!
85//! - **Attosecond storage unit.** Forward converters such as [`ms!`] and
86//!   [`sec!`] return total attoseconds as `i128`. Reverse converters such as
87//!   [`as_ms!`] and [`as_sec!`] take total attoseconds and return a count in
88//!   the named unit.
89//! - **Truncation toward zero.** Integer reverse converters use ordinary
90//!   `i128` division (`attos / unit`). Any leftover below one whole unit is
91//!   dropped, and the result moves toward zero—not toward −∞. For example,
92//!   −0.5 s as whole seconds is `0`, and −1.5 s is `-1`. The floating reverse
93//!   converters ([`as_sec_f!`], [`as_days_f!`]) are lossy
94//!   [`Real`](crate::Real) casts instead.
95//! - **Signed remainders on constructors.** Macros such as [`from_sec!`] and
96//!   [`from_ns!`] accept an optional fractional remainder in **attoseconds**.
97//!   Both signs of the remainder are valid; the total is
98//!   `whole × unit + frac` (with saturating arithmetic on the underlying
99//!   method). The same total can often be written with a signed remainder or
100//!   as a floor-style split with a non-negative remainder.
101//! - **Scale labels vs conversion.** Most `from_*` macros only set the
102//!   returned [`Dt`](../struct.Dt.html)'s `scale` / `target` fields; they do
103//!   **not** convert the attosecond count between time scales. [`from_ymd!`],
104//!   [`from_jd!`], [`from_jd_f!`], [`from_mjd!`], and [`from_mjd_f!`] are the
105//!   exceptions: they build a [`Dt`](../struct.Dt.html) on TAI (converting
106//!   from the `on=` scale when needed) and set `target` from `on=`, as
107//!   documented on each macro.
108//! - **`const` contexts.** Expansions call `const` methods on
109//!   [`Dt`](../struct.Dt.html), so these macros work in `const` contexts where
110//!   the underlying method does.
111//!
112//! ## Examples
113//!
114//! ```
115//! use deep_time::{Dt, Scale, dt, from_ymd, ms, ns};
116//! use deep_time::macros::{as_sec, from_sec, sec};
117//!
118//! // Unit helpers avoid hand-counting zeros in attosecond literals.
119//! assert_eq!(ms!(300), Dt::ms_to_attos(300));
120//! assert_eq!(ns!(1), 1_000_000_000);
121//!
122//! // Whole seconds + sub-second remainder (remainder is attoseconds).
123//! let a = from_sec!(1, ms!(300));
124//! assert_eq!(a, dt!(1_300_000_000_000_000_000));
125//!
126//! // Reverse conversion truncates toward zero.
127//! assert_eq!(as_sec!(sec!(1) + ms!(900)), 1);
128//! assert_eq!(as_sec!(-ms!(500)), 0);
129//! assert_eq!(as_sec!(-sec!(1) - ms!(500)), -1);
130//!
131//! // Calendar construction: builds a Dt, converting civil time to TAI.
132//! assert_eq!(from_ymd!(2000, 1, 1; 12, on=Scale::TAI), Dt::ZERO);
133//! ```
134//!
135//! See each macro's own documentation for accepted forms, defaults, and
136//! links to the corresponding [`Dt`](../struct.Dt.html) methods.
137
138/// Converts whole femtoseconds (`i128`) to total attoseconds (`i128`).
139///
140/// Equivalent to [`Dt::fs_to_attos`](../struct.Dt.html#method.fs_to_attos).
141///
142/// ## Examples
143///
144/// ```rust
145/// use deep_time::{Dt, macros::fs};
146///
147/// assert_eq!(fs!(1), Dt::fs_to_attos(1));
148/// ```
149#[doc(hidden)]
150#[macro_export]
151macro_rules! __fs {
152    ($x:expr) => {
153        $crate::Dt::fs_to_attos($x)
154    };
155}
156
157#[doc(inline)]
158pub use __fs as fs;
159
160/// Converts whole picoseconds (`i128`) to total attoseconds (`i128`).
161///
162/// Equivalent to [`Dt::ps_to_attos`](../struct.Dt.html#method.ps_to_attos).
163///
164/// ## Examples
165///
166/// ```rust
167/// use deep_time::{Dt, macros::ps};
168///
169/// assert_eq!(ps!(1), Dt::ps_to_attos(1));
170/// ```
171#[doc(hidden)]
172#[macro_export]
173macro_rules! __ps {
174    ($x:expr) => {
175        $crate::Dt::ps_to_attos($x)
176    };
177}
178
179#[doc(inline)]
180pub use __ps as ps;
181
182/// Converts whole nanoseconds (`i128`) to total attoseconds (`i128`).
183///
184/// Equivalent to [`Dt::ns_to_attos`](../struct.Dt.html#method.ns_to_attos).
185///
186/// ## Examples
187///
188/// ```rust
189/// use deep_time::{Dt, ns};
190///
191/// assert_eq!(ns!(1), Dt::ns_to_attos(1));
192/// ```
193#[macro_export]
194macro_rules! ns {
195    ($x:expr) => {
196        $crate::Dt::ns_to_attos($x)
197    };
198}
199
200/// Converts whole microseconds (`i128`) to total attoseconds (`i128`).
201///
202/// Equivalent to [`Dt::us_to_attos`](../struct.Dt.html#method.us_to_attos).
203///
204/// ## Examples
205///
206/// ```rust
207/// use deep_time::{Dt, macros::us};
208///
209/// assert_eq!(us!(1), Dt::us_to_attos(1));
210/// ```
211#[doc(hidden)]
212#[macro_export]
213macro_rules! __us {
214    ($x:expr) => {
215        $crate::Dt::us_to_attos($x)
216    };
217}
218
219#[doc(inline)]
220pub use __us as us;
221
222/// Converts whole milliseconds (`i128`) to total attoseconds (`i128`).
223///
224/// Equivalent to [`Dt::ms_to_attos`](../struct.Dt.html#method.ms_to_attos).
225///
226/// ## Examples
227///
228/// ```rust
229/// use deep_time::{Dt, ms};
230///
231/// assert_eq!(ms!(1), Dt::ms_to_attos(1));
232/// ```
233#[macro_export]
234macro_rules! ms {
235    ($x:expr) => {
236        $crate::Dt::ms_to_attos($x)
237    };
238}
239
240/// Converts whole seconds (`i128`) to total attoseconds (`i128`).
241///
242/// Equivalent to [`Dt::sec_to_attos`](../struct.Dt.html#method.sec_to_attos).
243///
244/// ## Examples
245///
246/// ```rust
247/// use deep_time::{Dt, macros::sec};
248///
249/// assert_eq!(sec!(1), Dt::sec_to_attos(1));
250/// ```
251#[doc(hidden)]
252#[macro_export]
253macro_rules! __sec {
254    ($x:expr) => {
255        $crate::Dt::sec_to_attos($x)
256    };
257}
258
259#[doc(inline)]
260pub use __sec as sec;
261
262/// Converts a floating-point second count ([`Real`](crate::Real)) to
263/// total attoseconds (`i128`).
264///
265/// Equivalent to [`Dt::sec_f_to_attos`](../struct.Dt.html#method.sec_f_to_attos).
266///
267/// ## Examples
268///
269/// ```rust
270/// use deep_time::{Dt, macros::sec_f};
271///
272/// assert_eq!(sec_f!(1.5), Dt::sec_f_to_attos(1.5));
273/// ```
274#[doc(hidden)]
275#[macro_export]
276macro_rules! __sec_f {
277    ($x:expr) => {
278        $crate::Dt::sec_f_to_attos($x)
279    };
280}
281
282#[doc(inline)]
283pub use __sec_f as sec_f;
284
285/// Converts whole minutes (`i128`) to total attoseconds (`i128`).
286///
287/// Equivalent to [`Dt::mins_to_attos`](../struct.Dt.html#method.mins_to_attos).
288///
289/// ## Examples
290///
291/// ```rust
292/// use deep_time::{Dt, macros::mins};
293///
294/// assert_eq!(mins!(1), Dt::mins_to_attos(1));
295/// ```
296#[doc(hidden)]
297#[macro_export]
298macro_rules! __mins {
299    ($x:expr) => {
300        $crate::Dt::mins_to_attos($x)
301    };
302}
303
304#[doc(inline)]
305pub use __mins as mins;
306
307/// Converts whole hours (`i128`) to total attoseconds (`i128`).
308///
309/// Equivalent to [`Dt::hours_to_attos`](../struct.Dt.html#method.hours_to_attos).
310///
311/// ## Examples
312///
313/// ```rust
314/// use deep_time::{Dt, macros::hours};
315///
316/// assert_eq!(hours!(1), Dt::hours_to_attos(1));
317/// ```
318#[doc(hidden)]
319#[macro_export]
320macro_rules! __hours {
321    ($x:expr) => {
322        $crate::Dt::hours_to_attos($x)
323    };
324}
325
326#[doc(inline)]
327pub use __hours as hours;
328
329/// Converts whole days (`i128`) to total attoseconds (`i128`).
330///
331/// Equivalent to [`Dt::days_to_attos`](../struct.Dt.html#method.days_to_attos).
332///
333/// ## Examples
334///
335/// ```rust
336/// use deep_time::{Dt, macros::days};
337///
338/// assert_eq!(days!(1), Dt::days_to_attos(1));
339/// ```
340#[doc(hidden)]
341#[macro_export]
342macro_rules! __days {
343    ($x:expr) => {
344        $crate::Dt::days_to_attos($x)
345    };
346}
347
348#[doc(inline)]
349pub use __days as days;
350
351/// Converts a floating-point day count ([`Real`](crate::Real)) to total attoseconds (`i128`).
352///
353/// Equivalent to [`Dt::days_f_to_attos`](../struct.Dt.html#method.days_f_to_attos).
354///
355/// ## Examples
356///
357/// ```rust
358/// use deep_time::{Dt, days_f};
359///
360/// assert_eq!(days_f!(0.25), Dt::days_f_to_attos(0.25));
361/// ```
362#[macro_export]
363macro_rules! days_f {
364    ($x:expr) => {
365        $crate::Dt::days_f_to_attos($x)
366    };
367}
368
369/// Converts whole weeks (`i128`) to total attoseconds (`i128`).
370///
371/// Equivalent to [`Dt::weeks_to_attos`](../struct.Dt.html#method.weeks_to_attos).
372///
373/// ## Examples
374///
375/// ```rust
376/// use deep_time::{Dt, macros::weeks};
377///
378/// assert_eq!(weeks!(1), Dt::weeks_to_attos(1));
379/// ```
380#[doc(hidden)]
381#[macro_export]
382macro_rules! __weeks {
383    ($x:expr) => {
384        $crate::Dt::weeks_to_attos($x)
385    };
386}
387
388#[doc(inline)]
389pub use __weeks as weeks;
390
391/// Converts total attoseconds (`i128`) → whole femtoseconds (`i128`).
392///
393/// Equivalent to [`Dt::attos_to_fs`](../struct.Dt.html#method.attos_to_fs).
394///
395/// Truncates toward zero.
396///
397/// Half a femtosecond is `500` attoseconds (no smaller named unit macro).
398///
399/// ## Examples
400///
401/// Example shows attos inputs being built with macros rather than counting
402/// attosecond zeros by hand.
403///
404/// ```rust
405/// use deep_time::macros::{as_fs, fs};
406///
407/// // an amount of attoseconds that is equal to
408/// // −1.5 fs becomes −1 femtoseconds
409/// assert_eq!(as_fs!(-fs!(1) - 500), -1);
410/// ```
411#[doc(hidden)]
412#[macro_export]
413macro_rules! __as_fs {
414    ($x:expr) => {
415        $crate::Dt::attos_to_fs($x)
416    };
417}
418
419#[doc(inline)]
420pub use __as_fs as as_fs;
421
422/// Converts total attoseconds (`i128`) → whole picoseconds (`i128`).
423///
424/// Equivalent to [`Dt::attos_to_ps`](../struct.Dt.html#method.attos_to_ps).
425///
426/// Truncates toward zero.
427///
428/// ## Examples
429///
430/// Example shows attos inputs being built with macros rather than counting
431/// attosecond zeros by hand.
432///
433/// ```rust
434/// use deep_time::macros::{as_ps, fs, ps};
435///
436/// // an amount of attoseconds that is equal to
437/// // −1.5 ps becomes −1 picoseconds
438/// assert_eq!(as_ps!(-ps!(1) - fs!(500)), -1);
439/// ```
440#[doc(hidden)]
441#[macro_export]
442macro_rules! __as_ps {
443    ($x:expr) => {
444        $crate::Dt::attos_to_ps($x)
445    };
446}
447
448#[doc(inline)]
449pub use __as_ps as as_ps;
450
451/// Converts total attoseconds (`i128`) → whole nanoseconds (`i128`).
452///
453/// Equivalent to [`Dt::attos_to_ns`](../struct.Dt.html#method.attos_to_ns).
454///
455/// Truncates toward zero.
456///
457/// ## Examples
458///
459/// Example shows attos inputs being built with macros rather than counting
460/// attosecond zeros by hand.
461///
462/// ```rust
463/// use deep_time::macros::{as_ns, ns, ps};
464///
465/// // an amount of attoseconds that is equal to
466/// // −1.5 ns becomes −1 nanoseconds
467/// assert_eq!(as_ns!(-ns!(1) - ps!(500)), -1);
468/// ```
469#[doc(hidden)]
470#[macro_export]
471macro_rules! __as_ns {
472    ($x:expr) => {
473        $crate::Dt::attos_to_ns($x)
474    };
475}
476
477#[doc(inline)]
478pub use __as_ns as as_ns;
479
480/// Converts total attoseconds (`i128`) → whole microseconds (`i128`).
481///
482/// Equivalent to [`Dt::attos_to_us`](../struct.Dt.html#method.attos_to_us).
483///
484/// Truncates toward zero.
485///
486/// ## Examples
487///
488/// Example shows attos inputs being built with macros rather than counting
489/// attosecond zeros by hand.
490///
491/// ```rust
492/// use deep_time::macros::{as_us, ns, us};
493///
494/// // an amount of attoseconds that is equal to
495/// // −1.5 µs becomes −1 microseconds
496/// assert_eq!(as_us!(-us!(1) - ns!(500)), -1);
497/// ```
498#[doc(hidden)]
499#[macro_export]
500macro_rules! __as_us {
501    ($x:expr) => {
502        $crate::Dt::attos_to_us($x)
503    };
504}
505
506#[doc(inline)]
507pub use __as_us as as_us;
508
509/// Converts total attoseconds (`i128`) → whole milliseconds (`i128`).
510///
511/// Equivalent to [`Dt::attos_to_ms`](../struct.Dt.html#method.attos_to_ms).
512///
513/// Truncates toward zero.
514///
515/// ## Examples
516///
517/// Example shows attos inputs being built with macros rather than counting
518/// attosecond zeros by hand.
519///
520/// ```rust
521/// use deep_time::macros::{as_ms, ms, us};
522///
523/// // an amount of attoseconds that is equal to
524/// // −1.5 ms becomes −1 milliseconds
525/// assert_eq!(as_ms!(-ms!(1) - us!(500)), -1);
526/// ```
527#[doc(hidden)]
528#[macro_export]
529macro_rules! __as_ms {
530    ($x:expr) => {
531        $crate::Dt::attos_to_ms($x)
532    };
533}
534
535#[doc(inline)]
536pub use __as_ms as as_ms;
537
538/// Converts total attoseconds (`i128`) → whole seconds (`i128`).
539///
540/// Equivalent to [`Dt::attos_to_sec`](../struct.Dt.html#method.attos_to_sec).
541///
542/// Truncates toward zero.
543///
544/// ## Examples
545///
546/// Example shows attos inputs being built with macros rather than counting
547/// attosecond zeros by hand.
548///
549/// ```rust
550/// use deep_time::macros::{as_sec, ms, sec};
551///
552/// // an amount of attoseconds that is equal to
553/// // −1.5 s becomes −1 seconds
554/// assert_eq!(as_sec!(-sec!(1) - ms!(500)), -1);
555/// ```
556#[doc(hidden)]
557#[macro_export]
558macro_rules! __as_sec {
559    ($x:expr) => {
560        $crate::Dt::attos_to_sec($x)
561    };
562}
563
564#[doc(inline)]
565pub use __as_sec as as_sec;
566
567/// Converts total attoseconds (`i128`) → lossy float seconds ([`Real`](crate::Real)).
568///
569/// Equivalent to [`Dt::attos_to_sec_f`](../struct.Dt.html#method.attos_to_sec_f).
570///
571/// ## Examples
572///
573/// Example shows attos inputs being built with macros rather than counting
574/// attosecond zeros by hand.
575///
576/// ```rust
577/// use deep_time::macros::{as_sec_f, ms, sec};
578///
579/// // an amount of attoseconds that is equal to
580/// // −1.5 s becomes -1.5 seconds
581/// assert_eq!(as_sec_f!(-sec!(1) - ms!(500)), -1.5);
582/// ```
583#[doc(hidden)]
584#[macro_export]
585macro_rules! __as_sec_f {
586    ($x:expr) => {
587        $crate::Dt::attos_to_sec_f($x)
588    };
589}
590
591#[doc(inline)]
592pub use __as_sec_f as as_sec_f;
593
594/// Converts total attoseconds (`i128`) → whole minutes (`i128`).
595///
596/// Equivalent to [`Dt::attos_to_mins`](../struct.Dt.html#method.attos_to_mins).
597///
598/// Truncates toward zero.
599///
600/// ## Examples
601///
602/// Example shows attos inputs being built with macros rather than counting
603/// attosecond zeros by hand.
604///
605/// ```rust
606/// use deep_time::macros::{as_mins, mins, sec};
607///
608/// // an amount of attoseconds that is equal to
609/// // −1.5 min becomes −1 minutes
610/// assert_eq!(as_mins!(-mins!(1) - sec!(30)), -1);
611/// ```
612#[doc(hidden)]
613#[macro_export]
614macro_rules! __as_mins {
615    ($x:expr) => {
616        $crate::Dt::attos_to_mins($x)
617    };
618}
619
620#[doc(inline)]
621pub use __as_mins as as_mins;
622
623/// Converts total attoseconds (`i128`) → whole hours (`i128`).
624///
625/// Equivalent to [`Dt::attos_to_hours`](../struct.Dt.html#method.attos_to_hours).
626///
627/// Truncates toward zero.
628///
629/// ## Examples
630///
631/// Example shows attos inputs being built with macros rather than counting
632/// attosecond zeros by hand.
633///
634/// ```rust
635/// use deep_time::macros::{as_hours, hours, mins};
636///
637/// // an amount of attoseconds that is equal to
638/// // −1.5 h becomes −1 hours
639/// assert_eq!(as_hours!(-hours!(1) - mins!(30)), -1);
640/// ```
641#[doc(hidden)]
642#[macro_export]
643macro_rules! __as_hours {
644    ($x:expr) => {
645        $crate::Dt::attos_to_hours($x)
646    };
647}
648
649#[doc(inline)]
650pub use __as_hours as as_hours;
651
652/// Converts total attoseconds (`i128`) → whole days (`i128`).
653///
654/// Equivalent to [`Dt::attos_to_days`](../struct.Dt.html#method.attos_to_days).
655///
656/// Truncates toward zero.
657///
658/// ## Examples
659///
660/// Example shows attos inputs being built with macros rather than counting
661/// attosecond zeros by hand.
662///
663/// ```rust
664/// use deep_time::macros::{as_days, days, hours};
665///
666/// // an amount of attoseconds that is equal to
667/// // −1.5 d becomes −1 days
668/// assert_eq!(as_days!(-days!(1) - hours!(12)), -1);
669/// ```
670#[doc(hidden)]
671#[macro_export]
672macro_rules! __as_days {
673    ($x:expr) => {
674        $crate::Dt::attos_to_days($x)
675    };
676}
677
678#[doc(inline)]
679pub use __as_days as as_days;
680
681/// Converts total attoseconds (`i128`) → lossy float days ([`Real`](crate::Real)).
682///
683/// Equivalent to [`Dt::attos_to_days_f`](../struct.Dt.html#method.attos_to_days_f).
684///
685/// ## Examples
686///
687/// Example shows attos inputs being built with macros rather than counting
688/// attosecond zeros by hand.
689///
690/// ```rust
691/// use deep_time::macros::{as_days_f, days, hours};
692///
693/// // an amount of attoseconds that is equal to
694/// // −1.5 d becomes -1.5 days
695/// assert_eq!(as_days_f!(-days!(1) - hours!(12)), -1.5);
696/// ```
697#[doc(hidden)]
698#[macro_export]
699macro_rules! __as_days_f {
700    ($x:expr) => {
701        $crate::Dt::attos_to_days_f($x)
702    };
703}
704
705#[doc(inline)]
706pub use __as_days_f as as_days_f;
707
708/// Converts total attoseconds (`i128`) → whole weeks (`i128`).
709///
710/// Equivalent to [`Dt::attos_to_weeks`](../struct.Dt.html#method.attos_to_weeks).
711///
712/// Truncates toward zero.
713///
714/// ## Examples
715///
716/// Example shows attos inputs being built with macros rather than counting
717/// attosecond zeros by hand.
718///
719/// ```rust
720/// use deep_time::macros::{as_weeks, days, hours, weeks};
721///
722/// // an amount of attoseconds that is equal to
723/// // −1.5 wk becomes −1 weeks
724/// assert_eq!(as_weeks!(-weeks!(1) - days!(3) - hours!(12)), -1);
725/// ```
726#[doc(hidden)]
727#[macro_export]
728macro_rules! __as_weeks {
729    ($x:expr) => {
730        $crate::Dt::attos_to_weeks($x)
731    };
732}
733
734#[doc(inline)]
735pub use __as_weeks as as_weeks;
736
737/// Builds a [`Dt`](../struct.Dt.html) from total attoseconds with optional scale labels.
738///
739/// - Equivalent to [`Dt::new`](../struct.Dt.html#method.new).
740/// - Does **not** perform time-scale conversion.
741///
742/// ## Defaults
743///
744/// | Omitted | Default |
745/// |---------|---------|
746/// | `on` and `target` | both [`Scale::TAI`](crate::Scale::TAI) |
747/// | only `on=s` | `target=s` |
748/// | only `target=t` | `on=TAI` |
749///
750/// ## Forms
751///
752/// | Form | Meaning |
753/// |------|---------|
754/// | `dt!(attos)` | both scales TAI |
755/// | `dt!(attos, on=s)` | scale and target `s` |
756/// | `dt!(attos, target=t)` | scale TAI, target `t` |
757/// | `dt!(attos, on=s, target=t)` | either order |
758/// | `dt!(attos, target=t, on=s)` | either order |
759///
760/// ## Examples
761///
762/// ```rust
763/// use deep_time::{Dt, Scale, dt};
764///
765/// let a = dt!(Dt::sec_to_attos(1));
766/// let b = dt!(0, on=Scale::UTC);
767/// let c = dt!(0, on=Scale::TAI, target=Scale::UTC);
768/// let d = dt!(0, target=Scale::UTC, on=Scale::TAI);
769/// let e = dt!(0, target=Scale::UTC);
770///
771/// assert_eq!(a, Dt::new(Dt::sec_to_attos(1), Scale::TAI, Scale::TAI));
772/// assert_eq!(b, Dt::new(0, Scale::UTC, Scale::UTC));
773/// assert_eq!(c, Dt::new(0, Scale::TAI, Scale::UTC));
774/// assert_eq!(d, c);
775/// assert_eq!(e, Dt::new(0, Scale::TAI, Scale::UTC));
776/// ```
777#[macro_export]
778macro_rules! dt {
779    ($attos:expr, on=$scale:expr, target=$target:expr) => {
780        $crate::Dt::new($attos, $scale, $target)
781    };
782    ($attos:expr, target=$target:expr, on=$scale:expr) => {
783        $crate::Dt::new($attos, $scale, $target)
784    };
785    ($attos:expr, on=$scale:expr) => {
786        $crate::Dt::new($attos, $scale, $scale)
787    };
788    ($attos:expr, target=$target:expr) => {
789        $crate::Dt::new($attos, $crate::Scale::TAI, $target)
790    };
791    ($attos:expr) => {
792        $crate::Dt::new($attos, $crate::Scale::TAI, $crate::Scale::TAI)
793    };
794}
795
796/// Builds a [`Dt`](../struct.Dt.html) from whole seconds and an optional signed
797/// sub-second remainder (attoseconds).
798///
799/// - Equivalent to [`Dt::from_sec_and_frac`](../struct.Dt.html#method.from_sec_and_frac).
800/// - Does **not** perform time-scale conversion.
801///
802/// The fractional remainder is in **attoseconds** — use
803/// [`ms!`](../macro.ms.html) (or another `*_to_attos`
804/// helper) instead of writing the attosecond literal by hand.
805///
806/// ## Defaults
807///
808/// | Omitted | Default |
809/// |---------|---------|
810/// | fraction | `0` |
811/// | `on` and `target` | both [`Scale::TAI`](crate::Scale::TAI) |
812/// | only `on=s` | `target=s` |
813/// | only `target=t` | `on=TAI` |
814///
815/// ## Forms
816///
817/// ```text
818/// from_sec!(sec)
819/// from_sec!(sec, frac)
820/// from_sec!(sec, on=s)
821/// from_sec!(sec, target=t)
822/// from_sec!(sec, on=s, target=t)
823/// from_sec!(sec, target=t, on=s)
824/// from_sec!(sec, frac, on=s)
825/// from_sec!(sec, frac, target=t)
826/// from_sec!(sec, frac, on=s, target=t)
827/// from_sec!(sec, frac, target=t, on=s)
828/// ```
829///
830/// ## Examples
831///
832/// ```
833/// use deep_time::{Dt, Scale, macros::from_sec, ms};
834///
835/// // 1.3 s → whole seconds + 300 ms remainder
836/// let a = from_sec!(1);
837/// let b = from_sec!(1, ms!(300));
838/// let c = from_sec!(-1, ms!(-300), on=Scale::TAI);
839/// let d = from_sec!(0, on=Scale::UTC);
840/// let e = from_sec!(1, on=Scale::TAI, target=Scale::UTC);
841/// let f = from_sec!(1, target=Scale::UTC, on=Scale::TAI);
842///
843/// assert_eq!(a, Dt::from_sec_and_frac(1, 0, Scale::TAI, Scale::TAI));
844/// assert_eq!(b, Dt::from_sec_and_frac(1, ms!(300), Scale::TAI, Scale::TAI));
845/// assert_eq!(c, Dt::from_sec_and_frac(-1, ms!(-300), Scale::TAI, Scale::TAI));
846/// assert_eq!(d, Dt::from_sec_and_frac(0, 0, Scale::UTC, Scale::UTC));
847/// assert_eq!(e, Dt::from_sec_and_frac(1, 0, Scale::TAI, Scale::UTC));
848/// assert_eq!(f, e);
849///
850/// let signed = from_sec!(-1, ms!(-300));
851/// let floored = from_sec!(-2, ms!(700));
852/// assert_eq!(signed, floored);
853/// assert_eq!(signed, Dt::from_sec_and_frac(-1, ms!(-300), Scale::TAI, Scale::TAI));
854/// ```
855#[doc(hidden)]
856#[macro_export]
857macro_rules! __from_sec {
858    ($sec:expr, $frac:expr, on=$scale:expr, target=$target:expr) => {
859        $crate::Dt::from_sec_and_frac($sec, $frac, $scale, $target)
860    };
861    ($sec:expr, $frac:expr, target=$target:expr, on=$scale:expr) => {
862        $crate::Dt::from_sec_and_frac($sec, $frac, $scale, $target)
863    };
864    ($sec:expr, on=$scale:expr, target=$target:expr) => {
865        $crate::Dt::from_sec_and_frac($sec, 0, $scale, $target)
866    };
867    ($sec:expr, target=$target:expr, on=$scale:expr) => {
868        $crate::Dt::from_sec_and_frac($sec, 0, $scale, $target)
869    };
870    ($sec:expr, $frac:expr, on=$scale:expr) => {
871        $crate::Dt::from_sec_and_frac($sec, $frac, $scale, $scale)
872    };
873    ($sec:expr, $frac:expr, target=$target:expr) => {
874        $crate::Dt::from_sec_and_frac($sec, $frac, $crate::Scale::TAI, $target)
875    };
876    ($sec:expr, on=$scale:expr) => {
877        $crate::Dt::from_sec_and_frac($sec, 0, $scale, $scale)
878    };
879    ($sec:expr, target=$target:expr) => {
880        $crate::Dt::from_sec_and_frac($sec, 0, $crate::Scale::TAI, $target)
881    };
882    ($sec:expr, $frac:expr) => {
883        $crate::Dt::from_sec_and_frac($sec, $frac, $crate::Scale::TAI, $crate::Scale::TAI)
884    };
885    ($sec:expr) => {
886        $crate::Dt::from_sec_and_frac($sec, 0, $crate::Scale::TAI, $crate::Scale::TAI)
887    };
888}
889
890#[doc(inline)]
891pub use __from_sec as from_sec;
892
893/// Builds a [`Dt`](../struct.Dt.html) from a floating-point seconds count with optional
894/// scale labels.
895///
896/// - Equivalent to [`Dt::from_sec_f`](../struct.Dt.html#method.from_sec_f).
897/// - Does **not** perform time-scale conversion.
898///
899/// ## Defaults
900///
901/// | Omitted | Default |
902/// |---------|---------|
903/// | `on` and `target` | both [`Scale::TAI`](crate::Scale::TAI) |
904/// | only `on=s` | `target=s` |
905/// | only `target=t` | `on=TAI` |
906///
907/// ## Forms
908///
909/// | Form | Meaning |
910/// |------|---------|
911/// | `from_sec_f!(sec)` | both scales TAI |
912/// | `from_sec_f!(sec, on=s)` | scale and target `s` |
913/// | `from_sec_f!(sec, target=t)` | scale TAI, target `t` |
914/// | `from_sec_f!(sec, on=s, target=t)` | either order |
915/// | `from_sec_f!(sec, target=t, on=s)` | either order |
916///
917/// ## Examples
918///
919/// ```
920/// use deep_time::Scale;
921/// use deep_time::from_sec_f;
922///
923/// let a = from_sec_f!(5.5);
924/// let b = from_sec_f!(0.0, on=Scale::UTC);
925/// let c = from_sec_f!(1.0, on=Scale::TAI, target=Scale::UTC);
926/// let d = from_sec_f!(1.0, target=Scale::UTC, on=Scale::TAI);
927///
928/// assert_eq!(a, deep_time::Dt::from_sec_f(5.5, Scale::TAI, Scale::TAI));
929/// assert_eq!(b, deep_time::Dt::from_sec_f(0.0, Scale::UTC, Scale::UTC));
930/// assert_eq!(c, deep_time::Dt::from_sec_f(1.0, Scale::TAI, Scale::UTC));
931/// assert_eq!(d, c);
932/// ```
933#[macro_export]
934macro_rules! from_sec_f {
935    ($sec:expr, on=$scale:expr, target=$target:expr) => {
936        $crate::Dt::from_sec_f($sec, $scale, $target)
937    };
938    ($sec:expr, target=$target:expr, on=$scale:expr) => {
939        $crate::Dt::from_sec_f($sec, $scale, $target)
940    };
941    ($sec:expr, on=$scale:expr) => {
942        $crate::Dt::from_sec_f($sec, $scale, $scale)
943    };
944    ($sec:expr, target=$target:expr) => {
945        $crate::Dt::from_sec_f($sec, $crate::Scale::TAI, $target)
946    };
947    ($sec:expr) => {
948        $crate::Dt::from_sec_f($sec, $crate::Scale::TAI, $crate::Scale::TAI)
949    };
950}
951
952/// Builds a [`Dt`](../struct.Dt.html) from a floating-point day count with optional
953/// scale labels.
954///
955/// - Equivalent to [`Dt::from_days_f`](../struct.Dt.html#method.from_days_f).
956/// - Does **not** perform time-scale conversion.
957///
958/// ## Defaults
959///
960/// | Omitted | Default |
961/// |---------|---------|
962/// | `on` and `target` | both [`Scale::TAI`](crate::Scale::TAI) |
963/// | only `on=s` | `target=s` |
964/// | only `target=t` | `on=TAI` |
965///
966/// ## Forms
967///
968/// | Form | Meaning |
969/// |------|---------|
970/// | `from_days_f!(days)` | both scales TAI |
971/// | `from_days_f!(days, on=s)` | scale and target `s` |
972/// | `from_days_f!(days, target=t)` | scale TAI, target `t` |
973/// | `from_days_f!(days, on=s, target=t)` | either order |
974/// | `from_days_f!(days, target=t, on=s)` | either order |
975///
976/// ## Examples
977///
978/// ```
979/// use deep_time::Scale;
980/// use deep_time::macros::from_days_f;
981///
982/// let a = from_days_f!(1.25);
983/// let b = from_days_f!(0.0, on=Scale::UTC);
984/// let c = from_days_f!(1.0, on=Scale::TAI, target=Scale::UTC);
985///
986/// assert_eq!(a, deep_time::Dt::from_days_f(1.25, Scale::TAI, Scale::TAI));
987/// assert_eq!(b, deep_time::Dt::from_days_f(0.0, Scale::UTC, Scale::UTC));
988/// assert_eq!(c, deep_time::Dt::from_days_f(1.0, Scale::TAI, Scale::UTC));
989/// ```
990#[doc(hidden)]
991#[macro_export]
992macro_rules! __from_days_f {
993    ($days:expr, on=$scale:expr, target=$target:expr) => {
994        $crate::Dt::from_days_f($days, $scale, $target)
995    };
996    ($days:expr, target=$target:expr, on=$scale:expr) => {
997        $crate::Dt::from_days_f($days, $scale, $target)
998    };
999    ($days:expr, on=$scale:expr) => {
1000        $crate::Dt::from_days_f($days, $scale, $scale)
1001    };
1002    ($days:expr, target=$target:expr) => {
1003        $crate::Dt::from_days_f($days, $crate::Scale::TAI, $target)
1004    };
1005    ($days:expr) => {
1006        $crate::Dt::from_days_f($days, $crate::Scale::TAI, $crate::Scale::TAI)
1007    };
1008}
1009
1010#[doc(inline)]
1011pub use __from_days_f as from_days_f;
1012
1013/// Builds a [`Dt`](../struct.Dt.html) from whole nanoseconds and an optional signed
1014/// fractional remainder in attoseconds.
1015///
1016/// - Equivalent to [`Dt::from_ns`](../struct.Dt.html#method.from_ns).
1017/// - Does **not** perform time-scale conversion.
1018///
1019/// The fractional remainder is in **attoseconds** — use
1020/// [`ps!`](macro.ps.html) (or another `*_to_attos`
1021/// helper) instead of writing the attosecond literal by hand.
1022///
1023/// ## Defaults
1024///
1025/// | Omitted | Default |
1026/// |---------|---------|
1027/// | fraction | `0` |
1028/// | `on` and `target` | both [`Scale::TAI`](crate::Scale::TAI) |
1029/// | only `on=s` | `target=s` |
1030/// | only `target=t` | `on=TAI` |
1031///
1032/// ## Forms
1033///
1034/// ```text
1035/// from_ns!(ns)
1036/// from_ns!(ns, frac)
1037/// from_ns!(ns, on=s)
1038/// from_ns!(ns, target=t)
1039/// from_ns!(ns, on=s, target=t)
1040/// from_ns!(ns, target=t, on=s)
1041/// from_ns!(ns, frac, on=s)
1042/// from_ns!(ns, frac, target=t)
1043/// from_ns!(ns, frac, on=s, target=t)
1044/// from_ns!(ns, frac, target=t, on=s)
1045/// ```
1046///
1047/// ## Examples
1048///
1049/// ```
1050/// use deep_time::{Dt, Scale, macros::from_ns, macros::ps};
1051///
1052/// // 1.3 ns → whole nanoseconds + 300 ps remainder
1053/// let a = from_ns!(1);
1054/// let b = from_ns!(1, ps!(300));
1055/// let c = from_ns!(-1, ps!(-300), on=Scale::TAI);
1056/// let d = from_ns!(0, on=Scale::UTC);
1057/// let e = from_ns!(1, on=Scale::TAI, target=Scale::UTC);
1058/// let f = from_ns!(1, target=Scale::UTC);
1059///
1060/// assert_eq!(a, Dt::from_ns(1, 0, Scale::TAI, Scale::TAI));
1061/// assert_eq!(b, Dt::from_ns(1, ps!(300), Scale::TAI, Scale::TAI));
1062/// assert_eq!(c, Dt::from_ns(-1, ps!(-300), Scale::TAI, Scale::TAI));
1063/// assert_eq!(d, Dt::from_ns(0, 0, Scale::UTC, Scale::UTC));
1064/// assert_eq!(e, Dt::from_ns(1, 0, Scale::TAI, Scale::UTC));
1065/// assert_eq!(f, e);
1066///
1067/// let signed = from_ns!(-1, ps!(-300));
1068/// let floor = from_ns!(-2, ps!(700));
1069/// assert_eq!(signed, floor);
1070/// assert_eq!(signed, Dt::from_ns(-1, ps!(-300), Scale::TAI, Scale::TAI));
1071/// ```
1072#[doc(hidden)]
1073#[macro_export]
1074macro_rules! __from_ns {
1075    ($ns:expr, $frac:expr, on=$scale:expr, target=$target:expr) => {
1076        $crate::Dt::from_ns($ns, $frac, $scale, $target)
1077    };
1078    ($ns:expr, $frac:expr, target=$target:expr, on=$scale:expr) => {
1079        $crate::Dt::from_ns($ns, $frac, $scale, $target)
1080    };
1081    ($ns:expr, on=$scale:expr, target=$target:expr) => {
1082        $crate::Dt::from_ns($ns, 0, $scale, $target)
1083    };
1084    ($ns:expr, target=$target:expr, on=$scale:expr) => {
1085        $crate::Dt::from_ns($ns, 0, $scale, $target)
1086    };
1087    ($ns:expr, $frac:expr, on=$scale:expr) => {
1088        $crate::Dt::from_ns($ns, $frac, $scale, $scale)
1089    };
1090    ($ns:expr, $frac:expr, target=$target:expr) => {
1091        $crate::Dt::from_ns($ns, $frac, $crate::Scale::TAI, $target)
1092    };
1093    ($ns:expr, on=$scale:expr) => {
1094        $crate::Dt::from_ns($ns, 0, $scale, $scale)
1095    };
1096    ($ns:expr, target=$target:expr) => {
1097        $crate::Dt::from_ns($ns, 0, $crate::Scale::TAI, $target)
1098    };
1099    ($ns:expr, $frac:expr) => {
1100        $crate::Dt::from_ns($ns, $frac, $crate::Scale::TAI, $crate::Scale::TAI)
1101    };
1102    ($ns:expr) => {
1103        $crate::Dt::from_ns($ns, 0, $crate::Scale::TAI, $crate::Scale::TAI)
1104    };
1105}
1106
1107#[doc(inline)]
1108pub use __from_ns as from_ns;
1109
1110/// Builds a [`Dt`](../struct.Dt.html) from whole milliseconds and an optional signed
1111/// fractional remainder in attoseconds.
1112///
1113/// - Equivalent to [`Dt::from_ms`](../struct.Dt.html#method.from_ms).
1114/// - Does **not** perform time-scale conversion.
1115///
1116/// The fractional remainder is in **attoseconds** — use
1117/// [`us!`](macro.us.html) (or another `*_to_attos`
1118/// helper) instead of writing the attosecond literal by hand.
1119///
1120/// ## Defaults
1121///
1122/// | Omitted | Default |
1123/// |---------|---------|
1124/// | fraction | `0` |
1125/// | `on` and `target` | both [`Scale::TAI`](crate::Scale::TAI) |
1126/// | only `on=s` | `target=s` |
1127/// | only `target=t` | `on=TAI` |
1128///
1129/// ## Forms
1130///
1131/// ```text
1132/// from_ms!(ms)
1133/// from_ms!(ms, frac)
1134/// from_ms!(ms, on=s)
1135/// from_ms!(ms, target=t)
1136/// from_ms!(ms, on=s, target=t)
1137/// from_ms!(ms, target=t, on=s)
1138/// from_ms!(ms, frac, on=s)
1139/// from_ms!(ms, frac, target=t)
1140/// from_ms!(ms, frac, on=s, target=t)
1141/// from_ms!(ms, frac, target=t, on=s)
1142/// ```
1143///
1144/// ## Examples
1145///
1146/// ```
1147/// use deep_time::{Dt, Scale, macros::from_ms, macros::us};
1148///
1149/// // 1.3 ms → whole milliseconds + 300 µs remainder
1150/// let a = from_ms!(1);
1151/// let b = from_ms!(1, us!(300));
1152/// let c = from_ms!(-1, us!(-300), on=Scale::TAI);
1153/// let d = from_ms!(0, on=Scale::UTC);
1154/// let e = from_ms!(1, on=Scale::TAI, target=Scale::UTC);
1155/// let f = from_ms!(1, target=Scale::UTC);
1156///
1157/// assert_eq!(a, Dt::from_ms(1, 0, Scale::TAI, Scale::TAI));
1158/// assert_eq!(b, Dt::from_ms(1, us!(300), Scale::TAI, Scale::TAI));
1159/// assert_eq!(c, Dt::from_ms(-1, us!(-300), Scale::TAI, Scale::TAI));
1160/// assert_eq!(d, Dt::from_ms(0, 0, Scale::UTC, Scale::UTC));
1161/// assert_eq!(e, Dt::from_ms(1, 0, Scale::TAI, Scale::UTC));
1162/// assert_eq!(f, e);
1163///
1164/// let signed = from_ms!(-1, us!(-300));
1165/// let floor = from_ms!(-2, us!(700));
1166/// assert_eq!(signed, floor);
1167/// assert_eq!(signed, Dt::from_ms(-1, us!(-300), Scale::TAI, Scale::TAI));
1168/// ```
1169#[doc(hidden)]
1170#[macro_export]
1171macro_rules! __from_ms {
1172    ($ms:expr, $frac:expr, on=$scale:expr, target=$target:expr) => {
1173        $crate::Dt::from_ms($ms, $frac, $scale, $target)
1174    };
1175    ($ms:expr, $frac:expr, target=$target:expr, on=$scale:expr) => {
1176        $crate::Dt::from_ms($ms, $frac, $scale, $target)
1177    };
1178    ($ms:expr, on=$scale:expr, target=$target:expr) => {
1179        $crate::Dt::from_ms($ms, 0, $scale, $target)
1180    };
1181    ($ms:expr, target=$target:expr, on=$scale:expr) => {
1182        $crate::Dt::from_ms($ms, 0, $scale, $target)
1183    };
1184    ($ms:expr, $frac:expr, on=$scale:expr) => {
1185        $crate::Dt::from_ms($ms, $frac, $scale, $scale)
1186    };
1187    ($ms:expr, $frac:expr, target=$target:expr) => {
1188        $crate::Dt::from_ms($ms, $frac, $crate::Scale::TAI, $target)
1189    };
1190    ($ms:expr, on=$scale:expr) => {
1191        $crate::Dt::from_ms($ms, 0, $scale, $scale)
1192    };
1193    ($ms:expr, target=$target:expr) => {
1194        $crate::Dt::from_ms($ms, 0, $crate::Scale::TAI, $target)
1195    };
1196    ($ms:expr, $frac:expr) => {
1197        $crate::Dt::from_ms($ms, $frac, $crate::Scale::TAI, $crate::Scale::TAI)
1198    };
1199    ($ms:expr) => {
1200        $crate::Dt::from_ms($ms, 0, $crate::Scale::TAI, $crate::Scale::TAI)
1201    };
1202}
1203
1204#[doc(inline)]
1205pub use __from_ms as from_ms;
1206
1207/// Builds a [`Dt`](../struct.Dt.html) from whole microseconds and an optional signed
1208/// fractional remainder in attoseconds.
1209///
1210/// - Equivalent to [`Dt::from_us`](../struct.Dt.html#method.from_us).
1211/// - Does **not** perform time-scale conversion.
1212///
1213/// The fractional remainder is in **attoseconds** — use
1214/// [`ns!`](../macro.ns.html) (or another `*_to_attos`
1215/// helper) instead of writing the attosecond literal by hand.
1216///
1217/// ## Defaults
1218///
1219/// | Omitted | Default |
1220/// |---------|---------|
1221/// | fraction | `0` |
1222/// | `on` and `target` | both [`Scale::TAI`](crate::Scale::TAI) |
1223/// | only `on=s` | `target=s` |
1224/// | only `target=t` | `on=TAI` |
1225///
1226/// ## Forms
1227///
1228/// ```text
1229/// from_us!(us)
1230/// from_us!(us, frac)
1231/// from_us!(us, on=s)
1232/// from_us!(us, target=t)
1233/// from_us!(us, on=s, target=t)
1234/// from_us!(us, target=t, on=s)
1235/// from_us!(us, frac, on=s)
1236/// from_us!(us, frac, target=t)
1237/// from_us!(us, frac, on=s, target=t)
1238/// from_us!(us, frac, target=t, on=s)
1239/// ```
1240///
1241/// ## Examples
1242///
1243/// ```
1244/// use deep_time::{Dt, Scale, macros::from_us, ns};
1245///
1246/// // 1.3 µs → whole microseconds + 300 ns remainder
1247/// let a = from_us!(1);
1248/// let b = from_us!(1, ns!(300));
1249/// let c = from_us!(-1, ns!(-300), on=Scale::TAI);
1250/// let d = from_us!(0, on=Scale::UTC);
1251/// let e = from_us!(1, on=Scale::TAI, target=Scale::UTC);
1252/// let f = from_us!(1, target=Scale::UTC);
1253///
1254/// assert_eq!(a, Dt::from_us(1, 0, Scale::TAI, Scale::TAI));
1255/// assert_eq!(b, Dt::from_us(1, ns!(300), Scale::TAI, Scale::TAI));
1256/// assert_eq!(c, Dt::from_us(-1, ns!(-300), Scale::TAI, Scale::TAI));
1257/// assert_eq!(d, Dt::from_us(0, 0, Scale::UTC, Scale::UTC));
1258/// assert_eq!(e, Dt::from_us(1, 0, Scale::TAI, Scale::UTC));
1259/// assert_eq!(f, e);
1260///
1261/// let signed = from_us!(-1, ns!(-300));
1262/// let floor = from_us!(-2, ns!(700));
1263/// assert_eq!(signed, floor);
1264/// assert_eq!(signed, Dt::from_us(-1, ns!(-300), Scale::TAI, Scale::TAI));
1265/// ```
1266#[doc(hidden)]
1267#[macro_export]
1268macro_rules! __from_us {
1269    ($us:expr, $frac:expr, on=$scale:expr, target=$target:expr) => {
1270        $crate::Dt::from_us($us, $frac, $scale, $target)
1271    };
1272    ($us:expr, $frac:expr, target=$target:expr, on=$scale:expr) => {
1273        $crate::Dt::from_us($us, $frac, $scale, $target)
1274    };
1275    ($us:expr, on=$scale:expr, target=$target:expr) => {
1276        $crate::Dt::from_us($us, 0, $scale, $target)
1277    };
1278    ($us:expr, target=$target:expr, on=$scale:expr) => {
1279        $crate::Dt::from_us($us, 0, $scale, $target)
1280    };
1281    ($us:expr, $frac:expr, on=$scale:expr) => {
1282        $crate::Dt::from_us($us, $frac, $scale, $scale)
1283    };
1284    ($us:expr, $frac:expr, target=$target:expr) => {
1285        $crate::Dt::from_us($us, $frac, $crate::Scale::TAI, $target)
1286    };
1287    ($us:expr, on=$scale:expr) => {
1288        $crate::Dt::from_us($us, 0, $scale, $scale)
1289    };
1290    ($us:expr, target=$target:expr) => {
1291        $crate::Dt::from_us($us, 0, $crate::Scale::TAI, $target)
1292    };
1293    ($us:expr, $frac:expr) => {
1294        $crate::Dt::from_us($us, $frac, $crate::Scale::TAI, $crate::Scale::TAI)
1295    };
1296    ($us:expr) => {
1297        $crate::Dt::from_us($us, 0, $crate::Scale::TAI, $crate::Scale::TAI)
1298    };
1299}
1300
1301#[doc(inline)]
1302pub use __from_us as from_us;
1303
1304/// Builds a [`Dt`](../struct.Dt.html) from whole picoseconds and an optional signed
1305/// fractional remainder in attoseconds.
1306///
1307/// - Equivalent to [`Dt::from_ps`](../struct.Dt.html#method.from_ps).
1308/// - Does **not** perform time-scale conversion.
1309///
1310/// The fractional remainder is in **attoseconds** — use
1311/// [`fs!`](macro.fs.html) (or another `*_to_attos`
1312/// helper) instead of writing the attosecond literal by hand.
1313///
1314/// ## Defaults
1315///
1316/// | Omitted | Default |
1317/// |---------|---------|
1318/// | fraction | `0` |
1319/// | `on` and `target` | both [`Scale::TAI`](crate::Scale::TAI) |
1320/// | only `on=s` | `target=s` |
1321/// | only `target=t` | `on=TAI` |
1322///
1323/// ## Forms
1324///
1325/// ```text
1326/// from_ps!(ps)
1327/// from_ps!(ps, frac)
1328/// from_ps!(ps, on=s)
1329/// from_ps!(ps, target=t)
1330/// from_ps!(ps, on=s, target=t)
1331/// from_ps!(ps, target=t, on=s)
1332/// from_ps!(ps, frac, on=s)
1333/// from_ps!(ps, frac, target=t)
1334/// from_ps!(ps, frac, on=s, target=t)
1335/// from_ps!(ps, frac, target=t, on=s)
1336/// ```
1337///
1338/// ## Examples
1339///
1340/// ```
1341/// use deep_time::{Dt, Scale, macros::from_ps, macros::fs};
1342///
1343/// // 1.3 ps → whole picoseconds + 300 fs remainder
1344/// let a = from_ps!(1);
1345/// let b = from_ps!(1, fs!(300));
1346/// let c = from_ps!(-1, fs!(-300), on=Scale::TAI);
1347/// let d = from_ps!(0, on=Scale::UTC);
1348/// let e = from_ps!(1, on=Scale::TAI, target=Scale::UTC);
1349/// let f = from_ps!(1, target=Scale::UTC);
1350///
1351/// assert_eq!(a, Dt::from_ps(1, 0, Scale::TAI, Scale::TAI));
1352/// assert_eq!(b, Dt::from_ps(1, fs!(300), Scale::TAI, Scale::TAI));
1353/// assert_eq!(c, Dt::from_ps(-1, fs!(-300), Scale::TAI, Scale::TAI));
1354/// assert_eq!(d, Dt::from_ps(0, 0, Scale::UTC, Scale::UTC));
1355/// assert_eq!(e, Dt::from_ps(1, 0, Scale::TAI, Scale::UTC));
1356/// assert_eq!(f, e);
1357///
1358/// let signed = from_ps!(-1, fs!(-300));
1359/// let floor = from_ps!(-2, fs!(700));
1360/// assert_eq!(signed, floor);
1361/// assert_eq!(signed, Dt::from_ps(-1, fs!(-300), Scale::TAI, Scale::TAI));
1362/// ```
1363#[doc(hidden)]
1364#[macro_export]
1365macro_rules! __from_ps {
1366    ($ps:expr, $frac:expr, on=$scale:expr, target=$target:expr) => {
1367        $crate::Dt::from_ps($ps, $frac, $scale, $target)
1368    };
1369    ($ps:expr, $frac:expr, target=$target:expr, on=$scale:expr) => {
1370        $crate::Dt::from_ps($ps, $frac, $scale, $target)
1371    };
1372    ($ps:expr, on=$scale:expr, target=$target:expr) => {
1373        $crate::Dt::from_ps($ps, 0, $scale, $target)
1374    };
1375    ($ps:expr, target=$target:expr, on=$scale:expr) => {
1376        $crate::Dt::from_ps($ps, 0, $scale, $target)
1377    };
1378    ($ps:expr, $frac:expr, on=$scale:expr) => {
1379        $crate::Dt::from_ps($ps, $frac, $scale, $scale)
1380    };
1381    ($ps:expr, $frac:expr, target=$target:expr) => {
1382        $crate::Dt::from_ps($ps, $frac, $crate::Scale::TAI, $target)
1383    };
1384    ($ps:expr, on=$scale:expr) => {
1385        $crate::Dt::from_ps($ps, 0, $scale, $scale)
1386    };
1387    ($ps:expr, target=$target:expr) => {
1388        $crate::Dt::from_ps($ps, 0, $crate::Scale::TAI, $target)
1389    };
1390    ($ps:expr, $frac:expr) => {
1391        $crate::Dt::from_ps($ps, $frac, $crate::Scale::TAI, $crate::Scale::TAI)
1392    };
1393    ($ps:expr) => {
1394        $crate::Dt::from_ps($ps, 0, $crate::Scale::TAI, $crate::Scale::TAI)
1395    };
1396}
1397
1398#[doc(inline)]
1399pub use __from_ps as from_ps;
1400
1401/// Builds a [`Dt`](../struct.Dt.html) from whole femtoseconds and an optional signed
1402/// fractional remainder in attoseconds.
1403///
1404/// - Equivalent to [`Dt::from_fs`](../struct.Dt.html#method.from_fs).
1405/// - Does **not** perform time-scale conversion.
1406///
1407/// The fractional remainder is already in **attoseconds** (one femtosecond is
1408/// 1000 attoseconds) — there is no smaller named unit macro.
1409///
1410/// ## Defaults
1411///
1412/// | Omitted | Default |
1413/// |---------|---------|
1414/// | fraction | `0` |
1415/// | `on` and `target` | both [`Scale::TAI`](crate::Scale::TAI) |
1416/// | only `on=s` | `target=s` |
1417/// | only `target=t` | `on=TAI` |
1418///
1419/// ## Forms
1420///
1421/// ```text
1422/// from_fs!(fs)
1423/// from_fs!(fs, frac)
1424/// from_fs!(fs, on=s)
1425/// from_fs!(fs, target=t)
1426/// from_fs!(fs, on=s, target=t)
1427/// from_fs!(fs, target=t, on=s)
1428/// from_fs!(fs, frac, on=s)
1429/// from_fs!(fs, frac, target=t)
1430/// from_fs!(fs, frac, on=s, target=t)
1431/// from_fs!(fs, frac, target=t, on=s)
1432/// ```
1433///
1434/// ## Examples
1435///
1436/// ```
1437/// use deep_time::{Dt, Scale, macros::from_fs};
1438///
1439/// // 1.3 fs → whole femtoseconds + 300 attoseconds remainder
1440/// let a = from_fs!(1);
1441/// let b = from_fs!(1, 300);
1442/// let c = from_fs!(-1, -300, on=Scale::TAI);
1443/// let d = from_fs!(0, on=Scale::UTC);
1444/// let e = from_fs!(1, on=Scale::TAI, target=Scale::UTC);
1445/// let f = from_fs!(1, target=Scale::UTC);
1446///
1447/// assert_eq!(a, Dt::from_fs(1, 0, Scale::TAI, Scale::TAI));
1448/// assert_eq!(b, Dt::from_fs(1, 300, Scale::TAI, Scale::TAI));
1449/// assert_eq!(c, Dt::from_fs(-1, -300, Scale::TAI, Scale::TAI));
1450/// assert_eq!(d, Dt::from_fs(0, 0, Scale::UTC, Scale::UTC));
1451/// assert_eq!(e, Dt::from_fs(1, 0, Scale::TAI, Scale::UTC));
1452/// assert_eq!(f, e);
1453///
1454/// let signed = from_fs!(-1, -300);
1455/// let floor = from_fs!(-2, 700);
1456/// assert_eq!(signed, floor);
1457/// assert_eq!(signed, Dt::from_fs(-1, -300, Scale::TAI, Scale::TAI));
1458/// ```
1459#[doc(hidden)]
1460#[macro_export]
1461macro_rules! __from_fs {
1462    ($fs:expr, $frac:expr, on=$scale:expr, target=$target:expr) => {
1463        $crate::Dt::from_fs($fs, $frac, $scale, $target)
1464    };
1465    ($fs:expr, $frac:expr, target=$target:expr, on=$scale:expr) => {
1466        $crate::Dt::from_fs($fs, $frac, $scale, $target)
1467    };
1468    ($fs:expr, on=$scale:expr, target=$target:expr) => {
1469        $crate::Dt::from_fs($fs, 0, $scale, $target)
1470    };
1471    ($fs:expr, target=$target:expr, on=$scale:expr) => {
1472        $crate::Dt::from_fs($fs, 0, $scale, $target)
1473    };
1474    ($fs:expr, $frac:expr, on=$scale:expr) => {
1475        $crate::Dt::from_fs($fs, $frac, $scale, $scale)
1476    };
1477    ($fs:expr, $frac:expr, target=$target:expr) => {
1478        $crate::Dt::from_fs($fs, $frac, $crate::Scale::TAI, $target)
1479    };
1480    ($fs:expr, on=$scale:expr) => {
1481        $crate::Dt::from_fs($fs, 0, $scale, $scale)
1482    };
1483    ($fs:expr, target=$target:expr) => {
1484        $crate::Dt::from_fs($fs, 0, $crate::Scale::TAI, $target)
1485    };
1486    ($fs:expr, $frac:expr) => {
1487        $crate::Dt::from_fs($fs, $frac, $crate::Scale::TAI, $crate::Scale::TAI)
1488    };
1489    ($fs:expr) => {
1490        $crate::Dt::from_fs($fs, 0, $crate::Scale::TAI, $crate::Scale::TAI)
1491    };
1492}
1493
1494#[doc(inline)]
1495pub use __from_fs as from_fs;
1496
1497/// Builds a **TAI** [`Dt`](../struct.Dt.html) from a Julian Date (whole days plus
1498/// optional attosecond remainder).
1499///
1500/// Equivalent to [`Dt::from_jd`](../struct.Dt.html#method.from_jd).
1501///
1502/// When an `on` arg is provided and it's not [`Scale::TAI`](crate::Scale::TAI)
1503/// then a time scale conversion is performed equivalent to `on` ->
1504/// [`Scale::TAI`](crate::Scale::TAI).
1505///
1506/// There is no `target=` on this macro — the returned [`Dt`](../struct.Dt.html)'s
1507/// `target` is set from `on` (or TAI when omitted), as
1508/// [`from_jd`](../struct.Dt.html#method.from_jd) does. Chain
1509/// [`.target(…)`](../struct.Dt.html#method.target) if needed.
1510///
1511/// The fractional remainder is in **attoseconds** — use a `*_to_attos` helper
1512/// (e.g. a day fraction built from [`days_f!`](../macro.days_f.html))
1513/// instead of hand-counting zeros when convenient.
1514///
1515/// ## Defaults
1516///
1517/// | Omitted | Default |
1518/// |---------|---------|
1519/// | fraction | `0` |
1520/// | `on` | [`Scale::TAI`](crate::Scale::TAI) |
1521///
1522/// ## Forms
1523///
1524/// ```text
1525/// from_jd!(jd_days)
1526/// from_jd!(jd_days, frac)
1527/// from_jd!(jd_days, on=s)
1528/// from_jd!(jd_days, frac, on=s)
1529/// ```
1530///
1531/// ## Examples
1532///
1533/// ```
1534/// use deep_time::{Dt, Scale, days_f, macros::from_jd};
1535///
1536/// // 2_460_782.25
1537/// let a = from_jd!(2_460_782);
1538/// let b = from_jd!(2_460_782, days_f!(0.25));
1539/// let c = from_jd!(2_460_782, days_f!(0.25), on=Scale::TAI);
1540/// let d = from_jd!(2_460_782, on=Scale::UTC);
1541///
1542/// assert_eq!(a, Dt::from_jd(2_460_782, 0, Scale::TAI));
1543/// assert_eq!(b, Dt::from_jd(2_460_782, days_f!(0.25), Scale::TAI));
1544/// assert_eq!(c, b);
1545/// assert_eq!(d, Dt::from_jd(2_460_782, 0, Scale::UTC));
1546///
1547/// // -1_000.25 (signed remainder)
1548/// let neg = from_jd!(-1_000, -days_f!(0.25));
1549/// assert_eq!(neg, Dt::from_jd(-1_000, -days_f!(0.25), Scale::TAI));
1550/// assert_eq!(neg.to_jd(), (-1_000, -days_f!(0.25)));
1551///
1552/// // or with floor style
1553/// assert_eq!(neg, from_jd!(-1_001, days_f!(0.75)));
1554/// ```
1555#[doc(hidden)]
1556#[macro_export]
1557macro_rules! __from_jd {
1558    // `on=` arms before bare `$frac:expr` so `on=…` is not taken as an expr.
1559    ($jd_days:expr, $frac:expr, on=$scale:expr) => {
1560        $crate::Dt::from_jd($jd_days, $frac, $scale)
1561    };
1562    ($jd_days:expr, on=$scale:expr) => {
1563        $crate::Dt::from_jd($jd_days, 0, $scale)
1564    };
1565    ($jd_days:expr, $frac:expr) => {
1566        $crate::Dt::from_jd($jd_days, $frac, $crate::Scale::TAI)
1567    };
1568    ($jd_days:expr) => {
1569        $crate::Dt::from_jd($jd_days, 0, $crate::Scale::TAI)
1570    };
1571}
1572
1573#[doc(inline)]
1574pub use __from_jd as from_jd;
1575
1576/// Builds a **TAI** [`Dt`](../struct.Dt.html) from a floating-point Julian Date.
1577///
1578/// Equivalent to [`Dt::from_jd_f`](../struct.Dt.html#method.from_jd_f).
1579///
1580/// When an `on` arg is provided and it's not [`Scale::TAI`](crate::Scale::TAI)
1581/// then a time scale conversion is performed equivalent to `on` ->
1582/// [`Scale::TAI`](crate::Scale::TAI).
1583///
1584/// There is no `target=` on this macro — the returned [`Dt`](../struct.Dt.html)'s
1585/// `target` is set from `on` (or TAI when omitted), as
1586/// [`from_jd_f`](../struct.Dt.html#method.from_jd_f) does. Chain
1587/// [`.target(…)`](../struct.Dt.html#method.target) if needed.
1588///
1589/// ## Defaults
1590///
1591/// | Omitted | Default |
1592/// |---------|---------|
1593/// | `on` | [`Scale::TAI`](crate::Scale::TAI) |
1594///
1595/// ## Forms
1596///
1597/// ```text
1598/// from_jd_f!(jd)
1599/// from_jd_f!(jd, on=s)
1600/// ```
1601///
1602/// ## Examples
1603///
1604/// ```
1605/// use deep_time::{Dt, Scale, days_f, macros::from_jd_f};
1606///
1607/// // 2_460_782.25
1608/// let a = from_jd_f!(2_460_782.25);
1609/// let b = from_jd_f!(2_460_782.25, on=Scale::TAI);
1610/// let c = from_jd_f!(2_460_782.0, on=Scale::UTC);
1611///
1612/// assert_eq!(a, Dt::from_jd_f(2_460_782.25, Scale::TAI));
1613/// assert_eq!(b, a);
1614/// assert_eq!(c, Dt::from_jd_f(2_460_782.0, Scale::UTC));
1615/// assert_eq!(a.to_jd(), (2_460_782, days_f!(0.25)));
1616///
1617/// // -1_000.25 (signed remainder)
1618/// let neg = from_jd_f!(-1_000.25);
1619/// assert_eq!(neg, Dt::from_jd_f(-1_000.25, Scale::TAI));
1620/// assert_eq!(neg.to_jd(), (-1_000, -days_f!(0.25)));
1621/// ```
1622#[doc(hidden)]
1623#[macro_export]
1624macro_rules! __from_jd_f {
1625    ($jd:expr, on=$scale:expr) => {
1626        $crate::Dt::from_jd_f($jd, $scale)
1627    };
1628    ($jd:expr) => {
1629        $crate::Dt::from_jd_f($jd, $crate::Scale::TAI)
1630    };
1631}
1632
1633#[doc(inline)]
1634pub use __from_jd_f as from_jd_f;
1635
1636/// Builds a **TAI** [`Dt`](../struct.Dt.html) from a Modified Julian Date (whole days
1637/// plus optional attosecond remainder).
1638///
1639/// Equivalent to [`Dt::from_mjd`](../struct.Dt.html#method.from_mjd).
1640///
1641/// When an `on` arg is provided and it's not [`Scale::TAI`](crate::Scale::TAI)
1642/// then a time scale conversion is performed equivalent to `on` ->
1643/// [`Scale::TAI`](crate::Scale::TAI).
1644///
1645/// There is no `target=` on this macro — the returned [`Dt`](../struct.Dt.html)'s
1646/// `target` is set from `on` (or TAI when omitted), as
1647/// [`from_mjd`](../struct.Dt.html#method.from_mjd) does. Chain
1648/// [`.target(…)`](../struct.Dt.html#method.target) if needed.
1649///
1650/// MJD and JD relate by `JD = MJD + 2_400_000.5`.
1651///
1652/// The fractional remainder is in **attoseconds** — use a `*_to_attos` helper
1653/// (e.g. a day fraction built from [`days_f!`](../macro.days_f.html))
1654/// instead of hand-counting zeros when convenient.
1655///
1656/// ## Defaults
1657///
1658/// | Omitted | Default |
1659/// |---------|---------|
1660/// | fraction | `0` |
1661/// | `on` | [`Scale::TAI`](crate::Scale::TAI) |
1662///
1663/// ## Forms
1664///
1665/// ```text
1666/// from_mjd!(mjd_days)
1667/// from_mjd!(mjd_days, frac)
1668/// from_mjd!(mjd_days, on=s)
1669/// from_mjd!(mjd_days, frac, on=s)
1670/// ```
1671///
1672/// ## Examples
1673///
1674/// ```
1675/// use deep_time::{Dt, Scale, days_f, macros::from_mjd};
1676///
1677/// // J2000.0 → MJD 51_544.5
1678/// let a = from_mjd!(51_544);
1679/// let b = from_mjd!(51_544, days_f!(0.5));
1680/// let c = from_mjd!(51_544, days_f!(0.5), on=Scale::TAI);
1681/// let d = from_mjd!(51_544, on=Scale::UTC);
1682///
1683/// assert_eq!(a, Dt::from_mjd(51_544, 0, Scale::TAI));
1684/// assert_eq!(b, Dt::from_mjd(51_544, days_f!(0.5), Scale::TAI));
1685/// assert_eq!(c, b);
1686/// assert_eq!(d, Dt::from_mjd(51_544, 0, Scale::UTC));
1687/// assert_eq!(b.to_mjd(), (51_544, days_f!(0.5)));
1688///
1689/// // -1_000.25 (signed truncating remainder)
1690/// let neg = from_mjd!(-1_000, -days_f!(0.25));
1691/// assert_eq!(neg, Dt::from_mjd(-1_000, -days_f!(0.25), Scale::TAI));
1692/// assert_eq!(neg.to_mjd(), (-1_000, -days_f!(0.25)));
1693///
1694/// // or with floor style
1695/// assert_eq!(neg, from_mjd!(-1_001, days_f!(0.75)));
1696/// ```
1697#[doc(hidden)]
1698#[macro_export]
1699macro_rules! __from_mjd {
1700    // `on=` arms before bare `$frac:expr` so `on=…` is not taken as an expr.
1701    ($mjd_days:expr, $frac:expr, on=$scale:expr) => {
1702        $crate::Dt::from_mjd($mjd_days, $frac, $scale)
1703    };
1704    ($mjd_days:expr, on=$scale:expr) => {
1705        $crate::Dt::from_mjd($mjd_days, 0, $scale)
1706    };
1707    ($mjd_days:expr, $frac:expr) => {
1708        $crate::Dt::from_mjd($mjd_days, $frac, $crate::Scale::TAI)
1709    };
1710    ($mjd_days:expr) => {
1711        $crate::Dt::from_mjd($mjd_days, 0, $crate::Scale::TAI)
1712    };
1713}
1714
1715#[doc(inline)]
1716pub use __from_mjd as from_mjd;
1717
1718/// Builds a **TAI** [`Dt`](../struct.Dt.html) from a floating-point Modified Julian Date.
1719///
1720/// Equivalent to [`Dt::from_mjd_f`](../struct.Dt.html#method.from_mjd_f).
1721///
1722/// When an `on` arg is provided and it's not [`Scale::TAI`](crate::Scale::TAI)
1723/// then a time scale conversion is performed equivalent to `on` ->
1724/// [`Scale::TAI`](crate::Scale::TAI).
1725///
1726/// There is no `target=` on this macro — the returned [`Dt`](../struct.Dt.html)'s
1727/// `target` is set from `on` (or TAI when omitted), as
1728/// [`from_mjd_f`](../struct.Dt.html#method.from_mjd_f) does. Chain
1729/// [`.target(…)`](../struct.Dt.html#method.target) if needed.
1730///
1731/// MJD and JD relate by `JD = MJD + 2_400_000.5`.
1732///
1733/// ## Defaults
1734///
1735/// | Omitted | Default |
1736/// |---------|---------|
1737/// | `on` | [`Scale::TAI`](crate::Scale::TAI) |
1738///
1739/// ## Forms
1740///
1741/// ```text
1742/// from_mjd_f!(mjd)
1743/// from_mjd_f!(mjd, on=s)
1744/// ```
1745///
1746/// ## Examples
1747///
1748/// ```
1749/// use deep_time::{Dt, Scale, days_f, macros::from_mjd_f};
1750///
1751/// // 60_961.25
1752/// let a = from_mjd_f!(60_961.25);
1753/// let b = from_mjd_f!(60_961.25, on=Scale::TAI);
1754/// let c = from_mjd_f!(60_961.0, on=Scale::UTC);
1755///
1756/// assert_eq!(a, Dt::from_mjd_f(60_961.25, Scale::TAI));
1757/// assert_eq!(b, a);
1758/// assert_eq!(c, Dt::from_mjd_f(60_961.0, Scale::UTC));
1759/// assert_eq!(a.to_mjd_floor(), (60_961, days_f!(0.25)));
1760///
1761/// // -1_000.25 as -1_001 + 0.75 day
1762/// let neg = from_mjd_f!(-1_000.25);
1763/// assert_eq!(neg, Dt::from_mjd_f(-1_000.25, Scale::TAI));
1764/// assert_eq!(neg.to_mjd_floor(), (-1_001, days_f!(0.75)));
1765/// ```
1766#[doc(hidden)]
1767#[macro_export]
1768macro_rules! __from_mjd_f {
1769    ($mjd:expr, on=$scale:expr) => {
1770        $crate::Dt::from_mjd_f($mjd, $scale)
1771    };
1772    ($mjd:expr) => {
1773        $crate::Dt::from_mjd_f($mjd, $crate::Scale::TAI)
1774    };
1775}
1776
1777#[doc(inline)]
1778pub use __from_mjd_f as from_mjd_f;
1779
1780/// Builds a [`Dt`](../struct.Dt.html) from a Gregorian calendar date and optional time.
1781///
1782/// Equivalent to [`Dt::from_ymd`](../struct.Dt.html#method.from_ymd).
1783///
1784/// Date fields are positional (`y`, `m`, `d`). Time is optional: put a
1785/// **semicolon after the day**, then hour (required if `;` is present), then
1786/// optional minute, second, and attoseconds. An optional `on=` civil scale may
1787/// follow.
1788///
1789/// A time scale conversion is performed from the `on` arg ->
1790/// [`Scale::TAI`](crate::Scale::TAI).
1791///
1792/// When no `on` arg is used the time scale is assumed to be
1793/// [`Scale::UTC`](crate::Scale::UTC).
1794///
1795/// | Omitted field | Default |
1796/// |---------------|---------|
1797/// | month | `1` |
1798/// | day | `1` |
1799/// | time (no `;`) | `0, 0, 0, 0` |
1800/// | minute / second / attos after `; h` | `0` |
1801/// | `on` | [`Scale::UTC`](crate::Scale::UTC) |
1802///
1803/// The resulting [`Dt`](../struct.Dt.html)'s `target` field is set from that civil
1804/// scale (the `on=` value, or UTC when omitted), as
1805/// [`Dt::from_ymd`](../struct.Dt.html#method.from_ymd) does. There is no `target=` on
1806/// this macro — chain [`.target(…)`](../struct.Dt.html#method.target) if needed.
1807///
1808/// ## Forms
1809///
1810/// ```text
1811/// from_ymd!(y)
1812/// from_ymd!(y, m)
1813/// from_ymd!(y, m, d)
1814/// from_ymd!(y, m, d, on=Scale::TAI)
1815/// from_ymd!(y, m, d; h)
1816/// from_ymd!(y, m, d; h, min)
1817/// from_ymd!(y, m, d; h, min, sec)
1818/// from_ymd!(y, m, d; h, min, sec, attos)
1819/// from_ymd!(y, m, d; h, min, sec, attos, on=Scale::UTC)
1820/// ```
1821///
1822/// ## Examples
1823///
1824/// ```
1825/// use deep_time::Scale;
1826/// use deep_time::from_ymd;
1827///
1828/// assert_eq!(
1829///     from_ymd!(1970),
1830///     deep_time::Dt::UNIX_EPOCH,
1831/// );
1832/// assert_eq!(
1833///     from_ymd!(2026, 6, 16),
1834///     deep_time::Dt::from_ymd(2026, 6, 16, Scale::UTC, 0, 0, 0, 0),
1835/// );
1836/// assert_eq!(
1837///     from_ymd!(2000, 1, 1; 12, on=Scale::TAI),
1838///     deep_time::Dt::ZERO,
1839/// );
1840/// assert_eq!(
1841///     from_ymd!(2000, 1, 1; 12, 0, 0, 123_456_789, on=Scale::UTC),
1842///     deep_time::Dt::from_ymd(2000, 1, 1, Scale::UTC, 12, 0, 0, 123_456_789),
1843/// );
1844///
1845/// // different target field after construction
1846/// let _ = from_ymd!(2020, 1, 1, on=Scale::UTC).target(Scale::TAI);
1847/// ```
1848#[macro_export]
1849macro_rules! from_ymd {
1850    // Time section: `d; h …` — `on=` arms before bare so `on=…` is not an `:expr`.
1851    ($y:expr, $m:expr, $d:expr; $h:expr, $min:expr, $s:expr, $attos:expr, on=$scale:expr) => {
1852        $crate::Dt::from_ymd($y, $m, $d, $scale, $h, $min, $s, $attos)
1853    };
1854    ($y:expr, $m:expr, $d:expr; $h:expr, $min:expr, $s:expr, on=$scale:expr) => {
1855        $crate::Dt::from_ymd($y, $m, $d, $scale, $h, $min, $s, 0)
1856    };
1857    ($y:expr, $m:expr, $d:expr; $h:expr, $min:expr, on=$scale:expr) => {
1858        $crate::Dt::from_ymd($y, $m, $d, $scale, $h, $min, 0, 0)
1859    };
1860    ($y:expr, $m:expr, $d:expr; $h:expr, on=$scale:expr) => {
1861        $crate::Dt::from_ymd($y, $m, $d, $scale, $h, 0, 0, 0)
1862    };
1863    ($y:expr, $m:expr, $d:expr; $h:expr, $min:expr, $s:expr, $attos:expr) => {
1864        $crate::Dt::from_ymd($y, $m, $d, $crate::Scale::UTC, $h, $min, $s, $attos)
1865    };
1866    ($y:expr, $m:expr, $d:expr; $h:expr, $min:expr, $s:expr) => {
1867        $crate::Dt::from_ymd($y, $m, $d, $crate::Scale::UTC, $h, $min, $s, 0)
1868    };
1869    ($y:expr, $m:expr, $d:expr; $h:expr, $min:expr) => {
1870        $crate::Dt::from_ymd($y, $m, $d, $crate::Scale::UTC, $h, $min, 0, 0)
1871    };
1872    ($y:expr, $m:expr, $d:expr; $h:expr) => {
1873        $crate::Dt::from_ymd($y, $m, $d, $crate::Scale::UTC, $h, 0, 0, 0)
1874    };
1875
1876    // Date only (+ optional on=)
1877    ($y:expr, $m:expr, $d:expr, on=$scale:expr) => {
1878        $crate::Dt::from_ymd($y, $m, $d, $scale, 0, 0, 0, 0)
1879    };
1880    ($y:expr, $m:expr, on=$scale:expr) => {
1881        $crate::Dt::from_ymd($y, $m, 1, $scale, 0, 0, 0, 0)
1882    };
1883    ($y:expr, on=$scale:expr) => {
1884        $crate::Dt::from_ymd($y, 1, 1, $scale, 0, 0, 0, 0)
1885    };
1886    ($y:expr, $m:expr, $d:expr) => {
1887        $crate::Dt::from_ymd($y, $m, $d, $crate::Scale::UTC, 0, 0, 0, 0)
1888    };
1889    ($y:expr, $m:expr) => {
1890        $crate::Dt::from_ymd($y, $m, 1, $crate::Scale::UTC, 0, 0, 0, 0)
1891    };
1892    ($y:expr) => {
1893        $crate::Dt::from_ymd($y, 1, 1, $crate::Scale::UTC, 0, 0, 0, 0)
1894    };
1895}
1896
1897#[doc(inline)]
1898pub use crate::{days_f, dt, from_sec_f, from_ymd, ms, ns};