Skip to main content

deep_time/
macros.rs

1//! Convenience macros
2
3/// Converts whole femtoseconds (`i128`) to total attoseconds (`i128`).
4///
5/// Sugar for [`Dt::fs_to_attos`](../struct.Dt.html#method.fs_to_attos). Does **not** build a
6/// [`Dt`](../struct.Dt.html) — only multiplies the unit count by the attoseconds-per-unit
7/// constant (saturating).
8///
9/// ## Example
10///
11/// ```rust
12/// use deep_time::{Dt, fs};
13///
14/// assert_eq!(fs!(1), Dt::fs_to_attos(1));
15/// ```
16#[macro_export]
17macro_rules! fs {
18    ($x:expr) => {
19        $crate::Dt::fs_to_attos($x)
20    };
21}
22
23/// Converts whole picoseconds (`i128`) to total attoseconds (`i128`).
24///
25/// Sugar for [`Dt::ps_to_attos`](../struct.Dt.html#method.ps_to_attos). Does **not** build a
26/// [`Dt`](../struct.Dt.html) — only multiplies the unit count by the attoseconds-per-unit
27/// constant (saturating).
28///
29/// ## Example
30///
31/// ```rust
32/// use deep_time::{Dt, ps};
33///
34/// assert_eq!(ps!(1), Dt::ps_to_attos(1));
35/// ```
36#[macro_export]
37macro_rules! ps {
38    ($x:expr) => {
39        $crate::Dt::ps_to_attos($x)
40    };
41}
42
43/// Converts whole nanoseconds (`i128`) to total attoseconds (`i128`).
44///
45/// Sugar for [`Dt::ns_to_attos`](../struct.Dt.html#method.ns_to_attos). Does **not** build a
46/// [`Dt`](../struct.Dt.html) — only multiplies the unit count by the attoseconds-per-unit
47/// constant (saturating).
48///
49/// ## Example
50///
51/// ```rust
52/// use deep_time::{Dt, ns};
53///
54/// assert_eq!(ns!(1), Dt::ns_to_attos(1));
55/// ```
56#[macro_export]
57macro_rules! ns {
58    ($x:expr) => {
59        $crate::Dt::ns_to_attos($x)
60    };
61}
62
63/// Converts whole microseconds (`i128`) to total attoseconds (`i128`).
64///
65/// Sugar for [`Dt::us_to_attos`](../struct.Dt.html#method.us_to_attos). Does **not** build a
66/// [`Dt`](../struct.Dt.html) — only multiplies the unit count by the attoseconds-per-unit
67/// constant (saturating).
68///
69/// ## Example
70///
71/// ```rust
72/// use deep_time::{Dt, us};
73///
74/// assert_eq!(us!(1), Dt::us_to_attos(1));
75/// ```
76#[macro_export]
77macro_rules! us {
78    ($x:expr) => {
79        $crate::Dt::us_to_attos($x)
80    };
81}
82
83/// Converts whole milliseconds (`i128`) to total attoseconds (`i128`).
84///
85/// Sugar for [`Dt::ms_to_attos`](../struct.Dt.html#method.ms_to_attos). Does **not** build a
86/// [`Dt`](../struct.Dt.html) — only multiplies the unit count by the attoseconds-per-unit
87/// constant (saturating).
88///
89/// ## Example
90///
91/// ```rust
92/// use deep_time::{Dt, ms};
93///
94/// assert_eq!(ms!(1), Dt::ms_to_attos(1));
95/// ```
96#[macro_export]
97macro_rules! ms {
98    ($x:expr) => {
99        $crate::Dt::ms_to_attos($x)
100    };
101}
102
103/// Converts whole seconds (`i128`) to total attoseconds (`i128`).
104///
105/// Sugar for [`Dt::sec_to_attos`](../struct.Dt.html#method.sec_to_attos). Does **not** build a
106/// [`Dt`](../struct.Dt.html) — only multiplies the unit count by the attoseconds-per-unit
107/// constant (saturating).
108///
109/// ## Example
110///
111/// ```rust
112/// use deep_time::{Dt, sec};
113///
114/// assert_eq!(sec!(1), Dt::sec_to_attos(1));
115/// ```
116#[macro_export]
117macro_rules! sec {
118    ($x:expr) => {
119        $crate::Dt::sec_to_attos($x)
120    };
121}
122
123/// Converts a floating-point second count ([`Real`](crate::Real)) to total attoseconds (`i128`).
124///
125/// Sugar for [`Dt::sec_f_to_attos`](../struct.Dt.html#method.sec_f_to_attos). Does **not** build a
126/// [`Dt`](../struct.Dt.html) — only converts the second count to attoseconds via the
127/// high-precision IEEE 754 path.
128///
129/// ## Example
130///
131/// ```rust
132/// use deep_time::{Dt, sec_f};
133///
134/// assert_eq!(sec_f!(1.5), Dt::sec_f_to_attos(1.5));
135/// ```
136#[macro_export]
137macro_rules! sec_f {
138    ($x:expr) => {
139        $crate::Dt::sec_f_to_attos($x)
140    };
141}
142
143/// Converts whole minutes (`i128`) to total attoseconds (`i128`).
144///
145/// Sugar for [`Dt::mins_to_attos`](../struct.Dt.html#method.mins_to_attos). Does **not** build a
146/// [`Dt`](../struct.Dt.html) — only multiplies the unit count by the attoseconds-per-unit
147/// constant (saturating).
148///
149/// ## Example
150///
151/// ```rust
152/// use deep_time::{Dt, mins};
153///
154/// assert_eq!(mins!(1), Dt::mins_to_attos(1));
155/// ```
156#[macro_export]
157macro_rules! mins {
158    ($x:expr) => {
159        $crate::Dt::mins_to_attos($x)
160    };
161}
162
163/// Converts whole hours (`i128`) to total attoseconds (`i128`).
164///
165/// Sugar for [`Dt::hours_to_attos`](../struct.Dt.html#method.hours_to_attos).
166/// Does **not** build a
167/// [`Dt`](../struct.Dt.html) — only multiplies the unit count by the
168/// attoseconds-per-unit constant (saturating).
169///
170/// ## Example
171///
172/// ```rust
173/// use deep_time::{Dt, hrs};
174///
175/// assert_eq!(hrs!(1), Dt::hours_to_attos(1));
176/// ```
177#[macro_export]
178macro_rules! hrs {
179    ($x:expr) => {
180        $crate::Dt::hours_to_attos($x)
181    };
182}
183
184/// Converts whole days (`i128`) to total attoseconds (`i128`).
185///
186/// Sugar for [`Dt::days_to_attos`](../struct.Dt.html#method.days_to_attos). Does **not**
187/// build a
188/// [`Dt`](../struct.Dt.html) — only multiplies the unit count by the attoseconds-per-unit
189/// constant (saturating).
190///
191/// ## Example
192///
193/// ```rust
194/// use deep_time::{Dt, days};
195///
196/// assert_eq!(days!(1), Dt::days_to_attos(1));
197/// ```
198#[macro_export]
199macro_rules! days {
200    ($x:expr) => {
201        $crate::Dt::days_to_attos($x)
202    };
203}
204
205/// Converts a floating-point day count ([`Real`](crate::Real)) to total attoseconds (`i128`).
206///
207/// Sugar for [`Dt::days_f_to_attos`](../struct.Dt.html#method.days_f_to_attos). Does **not**
208/// build a
209/// [`Dt`](../struct.Dt.html) — only converts the day count to attoseconds.
210///
211/// ## Example
212///
213/// ```rust
214/// use deep_time::{Dt, days_f};
215///
216/// assert_eq!(days_f!(0.25), Dt::days_f_to_attos(0.25));
217/// ```
218#[macro_export]
219macro_rules! days_f {
220    ($x:expr) => {
221        $crate::Dt::days_f_to_attos($x)
222    };
223}
224
225/// Converts whole weeks (`i128`) to total attoseconds (`i128`).
226///
227/// Sugar for [`Dt::weeks_to_attos`](../struct.Dt.html#method.weeks_to_attos).
228/// Does **not** build a
229/// [`Dt`](../struct.Dt.html) — only multiplies the unit count by the
230/// attoseconds-per-unit constant (saturating).
231///
232/// ## Example
233///
234/// ```rust
235/// use deep_time::{Dt, wks};
236///
237/// assert_eq!(wks!(1), Dt::weeks_to_attos(1));
238/// ```
239#[macro_export]
240macro_rules! wks {
241    ($x:expr) => {
242        $crate::Dt::weeks_to_attos($x)
243    };
244}
245
246/// Converts total attoseconds (`i128`) → whole femtoseconds (`i128`).
247///
248/// Sugar for [`Dt::attos_to_fs`](../struct.Dt.html#method.attos_to_fs). Truncating division.
249///
250/// ## Example
251///
252/// ```rust
253/// use deep_time::{Dt, as_fs};
254///
255/// assert_eq!(as_fs!(Dt::fs_to_attos(3)), 3);
256/// ```
257#[macro_export]
258macro_rules! as_fs {
259    ($x:expr) => {
260        $crate::Dt::attos_to_fs($x)
261    };
262}
263
264/// Converts total attoseconds (`i128`) → whole picoseconds (`i128`).
265///
266/// Sugar for [`Dt::attos_to_ps`](../struct.Dt.html#method.attos_to_ps). Truncating division.
267///
268/// ## Example
269///
270/// ```rust
271/// use deep_time::{Dt, as_ps};
272///
273/// assert_eq!(as_ps!(Dt::ps_to_attos(3)), 3);
274/// ```
275#[macro_export]
276macro_rules! as_ps {
277    ($x:expr) => {
278        $crate::Dt::attos_to_ps($x)
279    };
280}
281
282/// Converts total attoseconds (`i128`) → whole nanoseconds (`i128`).
283///
284/// Sugar for [`Dt::attos_to_ns`](../struct.Dt.html#method.attos_to_ns). Truncating division.
285///
286/// ## Example
287///
288/// ```rust
289/// use deep_time::{Dt, as_ns};
290///
291/// assert_eq!(as_ns!(Dt::ns_to_attos(3)), 3);
292/// ```
293#[macro_export]
294macro_rules! as_ns {
295    ($x:expr) => {
296        $crate::Dt::attos_to_ns($x)
297    };
298}
299
300/// Converts total attoseconds (`i128`) → whole microseconds (`i128`).
301///
302/// Sugar for [`Dt::attos_to_us`](../struct.Dt.html#method.attos_to_us). Truncating division.
303///
304/// ## Example
305///
306/// ```rust
307/// use deep_time::{Dt, as_us};
308///
309/// assert_eq!(as_us!(Dt::us_to_attos(3)), 3);
310/// ```
311#[macro_export]
312macro_rules! as_us {
313    ($x:expr) => {
314        $crate::Dt::attos_to_us($x)
315    };
316}
317
318/// Converts total attoseconds (`i128`) → whole milliseconds (`i128`).
319///
320/// Sugar for [`Dt::attos_to_ms`](../struct.Dt.html#method.attos_to_ms). Truncating division.
321///
322/// ## Example
323///
324/// ```rust
325/// use deep_time::{Dt, as_ms};
326///
327/// assert_eq!(as_ms!(Dt::ms_to_attos(3)), 3);
328/// ```
329#[macro_export]
330macro_rules! as_ms {
331    ($x:expr) => {
332        $crate::Dt::attos_to_ms($x)
333    };
334}
335
336/// Converts total attoseconds (`i128`) → whole seconds (`i128`).
337///
338/// Sugar for [`Dt::attos_to_sec`](../struct.Dt.html#method.attos_to_sec). Truncating division.
339///
340/// ## Example
341///
342/// ```rust
343/// use deep_time::{Dt, as_sec};
344///
345/// assert_eq!(as_sec!(Dt::sec_to_attos(3)), 3);
346/// ```
347#[macro_export]
348macro_rules! as_sec {
349    ($x:expr) => {
350        $crate::Dt::attos_to_sec($x)
351    };
352}
353
354/// Converts total attoseconds (`i128`) → float seconds ([`Real`](crate::Real)).
355///
356/// Sugar for [`Dt::attos_to_sec_f`](../struct.Dt.html#method.attos_to_sec_f). Lossy.
357///
358/// ## Example
359///
360/// ```rust
361/// use deep_time::{Dt, as_sec_f};
362///
363/// assert_eq!(as_sec_f!(Dt::sec_to_attos(3)), 3.0);
364/// ```
365#[macro_export]
366macro_rules! as_sec_f {
367    ($x:expr) => {
368        $crate::Dt::attos_to_sec_f($x)
369    };
370}
371
372/// Converts total attoseconds (`i128`) → whole minutes (`i128`).
373///
374/// Sugar for [`Dt::attos_to_mins`](../struct.Dt.html#method.attos_to_mins). Truncating division.
375///
376/// ## Example
377///
378/// ```rust
379/// use deep_time::{Dt, as_mins};
380///
381/// assert_eq!(as_mins!(Dt::mins_to_attos(3)), 3);
382/// ```
383#[macro_export]
384macro_rules! as_mins {
385    ($x:expr) => {
386        $crate::Dt::attos_to_mins($x)
387    };
388}
389
390/// Converts total attoseconds (`i128`) → whole hours (`i128`).
391///
392/// Sugar for [`Dt::attos_to_hours`](../struct.Dt.html#method.attos_to_hours). Truncating division.
393///
394/// ## Example
395///
396/// ```rust
397/// use deep_time::{Dt, as_hrs};
398///
399/// assert_eq!(as_hrs!(Dt::hours_to_attos(3)), 3);
400/// ```
401#[macro_export]
402macro_rules! as_hrs {
403    ($x:expr) => {
404        $crate::Dt::attos_to_hours($x)
405    };
406}
407
408/// Converts total attoseconds (`i128`) → whole days (`i128`).
409///
410/// Sugar for [`Dt::attos_to_days`](../struct.Dt.html#method.attos_to_days). Truncating division.
411///
412/// ## Example
413///
414/// ```rust
415/// use deep_time::{Dt, as_days};
416///
417/// assert_eq!(as_days!(Dt::days_to_attos(3)), 3);
418/// ```
419#[macro_export]
420macro_rules! as_days {
421    ($x:expr) => {
422        $crate::Dt::attos_to_days($x)
423    };
424}
425
426/// Converts total attoseconds (`i128`) → floating-point days ([`Real`](crate::Real)).
427///
428/// Sugar for [`Dt::attos_to_days_f`](../struct.Dt.html#method.attos_to_days_f). Lossy.
429///
430/// ## Example
431///
432/// ```rust
433/// use deep_time::{Dt, as_days_f};
434///
435/// assert_eq!(as_days_f!(Dt::days_to_attos(3)), 3.0);
436/// ```
437#[macro_export]
438macro_rules! as_days_f {
439    ($x:expr) => {
440        $crate::Dt::attos_to_days_f($x)
441    };
442}
443
444/// Converts total attoseconds (`i128`) → whole weeks (`i128`).
445///
446/// Sugar for [`Dt::attos_to_weeks`](../struct.Dt.html#method.attos_to_weeks). Truncating division.
447///
448/// ## Example
449///
450/// ```rust
451/// use deep_time::{Dt, as_wks};
452///
453/// assert_eq!(as_wks!(Dt::weeks_to_attos(3)), 3);
454/// ```
455#[macro_export]
456macro_rules! as_wks {
457    ($x:expr) => {
458        $crate::Dt::attos_to_weeks($x)
459    };
460}
461
462/// Builds a [`Dt`](../struct.Dt.html) from total attoseconds with optional scale labels.
463///
464/// Sugar for [`Dt::new`](../struct.Dt.html#method.new). Does **not** perform time-scale
465/// conversion.
466///
467/// ## Defaults
468///
469/// | Omitted | Default |
470/// |---------|---------|
471/// | `on` and `target` | both [`Scale::TAI`](crate::Scale::TAI) |
472/// | only `on=s` | `target=s` |
473/// | only `target=t` | `on=TAI` |
474///
475/// ## Forms
476///
477/// | Form | Meaning |
478/// |------|---------|
479/// | `dt!(attos)` | both scales TAI |
480/// | `dt!(attos, on=s)` | scale and target `s` |
481/// | `dt!(attos, target=t)` | scale TAI, target `t` |
482/// | `dt!(attos, on=s, target=t)` | either order |
483/// | `dt!(attos, target=t, on=s)` | either order |
484///
485/// ## Examples
486///
487/// ```rust
488/// use deep_time::{Dt, Scale, dt};
489///
490/// let a = dt!(Dt::sec_to_attos(1));
491/// let b = dt!(0, on=Scale::UTC);
492/// let c = dt!(0, on=Scale::TAI, target=Scale::UTC);
493/// let d = dt!(0, target=Scale::UTC, on=Scale::TAI);
494/// let e = dt!(0, target=Scale::UTC);
495///
496/// assert_eq!(a, Dt::new(Dt::sec_to_attos(1), Scale::TAI, Scale::TAI));
497/// assert_eq!(b, Dt::new(0, Scale::UTC, Scale::UTC));
498/// assert_eq!(c, Dt::new(0, Scale::TAI, Scale::UTC));
499/// assert_eq!(d, c);
500/// assert_eq!(e, Dt::new(0, Scale::TAI, Scale::UTC));
501/// ```
502#[macro_export]
503macro_rules! dt {
504    ($attos:expr, on=$scale:expr, target=$target:expr) => {
505        $crate::Dt::new($attos, $scale, $target)
506    };
507    ($attos:expr, target=$target:expr, on=$scale:expr) => {
508        $crate::Dt::new($attos, $scale, $target)
509    };
510    ($attos:expr, on=$scale:expr) => {
511        $crate::Dt::new($attos, $scale, $scale)
512    };
513    ($attos:expr, target=$target:expr) => {
514        $crate::Dt::new($attos, $crate::Scale::TAI, $target)
515    };
516    ($attos:expr) => {
517        $crate::Dt::new($attos, $crate::Scale::TAI, $crate::Scale::TAI)
518    };
519}
520
521/// Builds a [`Dt`](../struct.Dt.html) from whole seconds and an optional signed
522/// sub-second remainder (attoseconds).
523///
524/// Sugar for [`Dt::from_sec_and_frac`](../struct.Dt.html#method.from_sec_and_frac).
525/// Does **not** perform time-scale conversion.
526///
527/// The fractional remainder is in **attoseconds** — use
528/// [`ms!`](../macro.ms.html) (or another `*_to_attos`
529/// helper) instead of writing the attosecond literal by hand.
530///
531/// ## Defaults
532///
533/// | Omitted | Default |
534/// |---------|---------|
535/// | fraction | `0` |
536/// | `on` and `target` | both [`Scale::TAI`](crate::Scale::TAI) |
537/// | only `on=s` | `target=s` |
538/// | only `target=t` | `on=TAI` |
539///
540/// ## Forms
541///
542/// ```text
543/// from_sec!(sec)
544/// from_sec!(sec, frac)
545/// from_sec!(sec, on=s)
546/// from_sec!(sec, target=t)
547/// from_sec!(sec, on=s, target=t)
548/// from_sec!(sec, target=t, on=s)
549/// from_sec!(sec, frac, on=s)
550/// from_sec!(sec, frac, target=t)
551/// from_sec!(sec, frac, on=s, target=t)
552/// from_sec!(sec, frac, target=t, on=s)
553/// ```
554///
555/// ## Examples
556///
557/// ```
558/// use deep_time::{Dt, Scale, from_sec, ms};
559///
560/// // 1.3 s → whole seconds + 300 ms remainder
561/// let a = from_sec!(1);
562/// let b = from_sec!(1, ms!(300));
563/// let c = from_sec!(-1, ms!(-300), on=Scale::TAI);
564/// let d = from_sec!(0, on=Scale::UTC);
565/// let e = from_sec!(1, on=Scale::TAI, target=Scale::UTC);
566/// let f = from_sec!(1, target=Scale::UTC, on=Scale::TAI);
567///
568/// assert_eq!(a, Dt::from_sec_and_frac(1, 0, Scale::TAI, Scale::TAI));
569/// assert_eq!(b, Dt::from_sec_and_frac(1, ms!(300), Scale::TAI, Scale::TAI));
570/// assert_eq!(c, Dt::from_sec_and_frac(-1, ms!(-300), Scale::TAI, Scale::TAI));
571/// assert_eq!(d, Dt::from_sec_and_frac(0, 0, Scale::UTC, Scale::UTC));
572/// assert_eq!(e, Dt::from_sec_and_frac(1, 0, Scale::TAI, Scale::UTC));
573/// assert_eq!(f, e);
574///
575/// let signed = from_sec!(-1, ms!(-300));
576/// let floor = from_sec!(-2, ms!(700));
577/// assert_eq!(signed, floor);
578/// assert_eq!(signed, Dt::from_sec_and_frac(-1, ms!(-300), Scale::TAI, Scale::TAI));
579/// ```
580#[macro_export]
581macro_rules! from_sec {
582    ($sec:expr, $frac:expr, on=$scale:expr, target=$target:expr) => {
583        $crate::Dt::from_sec_and_frac($sec, $frac, $scale, $target)
584    };
585    ($sec:expr, $frac:expr, target=$target:expr, on=$scale:expr) => {
586        $crate::Dt::from_sec_and_frac($sec, $frac, $scale, $target)
587    };
588    ($sec:expr, on=$scale:expr, target=$target:expr) => {
589        $crate::Dt::from_sec_and_frac($sec, 0, $scale, $target)
590    };
591    ($sec:expr, target=$target:expr, on=$scale:expr) => {
592        $crate::Dt::from_sec_and_frac($sec, 0, $scale, $target)
593    };
594    ($sec:expr, $frac:expr, on=$scale:expr) => {
595        $crate::Dt::from_sec_and_frac($sec, $frac, $scale, $scale)
596    };
597    ($sec:expr, $frac:expr, target=$target:expr) => {
598        $crate::Dt::from_sec_and_frac($sec, $frac, $crate::Scale::TAI, $target)
599    };
600    ($sec:expr, on=$scale:expr) => {
601        $crate::Dt::from_sec_and_frac($sec, 0, $scale, $scale)
602    };
603    ($sec:expr, target=$target:expr) => {
604        $crate::Dt::from_sec_and_frac($sec, 0, $crate::Scale::TAI, $target)
605    };
606    ($sec:expr, $frac:expr) => {
607        $crate::Dt::from_sec_and_frac($sec, $frac, $crate::Scale::TAI, $crate::Scale::TAI)
608    };
609    ($sec:expr) => {
610        $crate::Dt::from_sec_and_frac($sec, 0, $crate::Scale::TAI, $crate::Scale::TAI)
611    };
612}
613
614/// Builds a [`Dt`](../struct.Dt.html) from a floating-point seconds count with optional
615/// scale labels.
616///
617/// Sugar for [`Dt::from_sec_f`](../struct.Dt.html#method.from_sec_f). Does **not** perform
618/// time-scale conversion.
619///
620/// ## Defaults
621///
622/// | Omitted | Default |
623/// |---------|---------|
624/// | `on` and `target` | both [`Scale::TAI`](crate::Scale::TAI) |
625/// | only `on=s` | `target=s` |
626/// | only `target=t` | `on=TAI` |
627///
628/// ## Forms
629///
630/// | Form | Meaning |
631/// |------|---------|
632/// | `from_sec_f!(sec)` | both scales TAI |
633/// | `from_sec_f!(sec, on=s)` | scale and target `s` |
634/// | `from_sec_f!(sec, target=t)` | scale TAI, target `t` |
635/// | `from_sec_f!(sec, on=s, target=t)` | either order |
636/// | `from_sec_f!(sec, target=t, on=s)` | either order |
637///
638/// ## Examples
639///
640/// ```
641/// use deep_time::Scale;
642/// use deep_time::from_sec_f;
643///
644/// let a = from_sec_f!(5.5);
645/// let b = from_sec_f!(0.0, on=Scale::UTC);
646/// let c = from_sec_f!(1.0, on=Scale::TAI, target=Scale::UTC);
647/// let d = from_sec_f!(1.0, target=Scale::UTC, on=Scale::TAI);
648///
649/// assert_eq!(a, deep_time::Dt::from_sec_f(5.5, Scale::TAI, Scale::TAI));
650/// assert_eq!(b, deep_time::Dt::from_sec_f(0.0, Scale::UTC, Scale::UTC));
651/// assert_eq!(c, deep_time::Dt::from_sec_f(1.0, Scale::TAI, Scale::UTC));
652/// assert_eq!(d, c);
653/// ```
654#[macro_export]
655macro_rules! from_sec_f {
656    ($sec:expr, on=$scale:expr, target=$target:expr) => {
657        $crate::Dt::from_sec_f($sec, $scale, $target)
658    };
659    ($sec:expr, target=$target:expr, on=$scale:expr) => {
660        $crate::Dt::from_sec_f($sec, $scale, $target)
661    };
662    ($sec:expr, on=$scale:expr) => {
663        $crate::Dt::from_sec_f($sec, $scale, $scale)
664    };
665    ($sec:expr, target=$target:expr) => {
666        $crate::Dt::from_sec_f($sec, $crate::Scale::TAI, $target)
667    };
668    ($sec:expr) => {
669        $crate::Dt::from_sec_f($sec, $crate::Scale::TAI, $crate::Scale::TAI)
670    };
671}
672
673/// Builds a [`Dt`](../struct.Dt.html) from a floating-point day count with optional
674/// scale labels.
675///
676/// Sugar for [`Dt::from_days_f`](../struct.Dt.html#method.from_days_f). Does **not**
677/// perform time-scale conversion.
678///
679/// ## Defaults
680///
681/// | Omitted | Default |
682/// |---------|---------|
683/// | `on` and `target` | both [`Scale::TAI`](crate::Scale::TAI) |
684/// | only `on=s` | `target=s` |
685/// | only `target=t` | `on=TAI` |
686///
687/// ## Forms
688///
689/// | Form | Meaning |
690/// |------|---------|
691/// | `from_days_f!(days)` | both scales TAI |
692/// | `from_days_f!(days, on=s)` | scale and target `s` |
693/// | `from_days_f!(days, target=t)` | scale TAI, target `t` |
694/// | `from_days_f!(days, on=s, target=t)` | either order |
695/// | `from_days_f!(days, target=t, on=s)` | either order |
696///
697/// ## Examples
698///
699/// ```
700/// use deep_time::Scale;
701/// use deep_time::from_days_f;
702///
703/// let a = from_days_f!(1.25);
704/// let b = from_days_f!(0.0, on=Scale::UTC);
705/// let c = from_days_f!(1.0, on=Scale::TAI, target=Scale::UTC);
706///
707/// assert_eq!(a, deep_time::Dt::from_days_f(1.25, Scale::TAI, Scale::TAI));
708/// assert_eq!(b, deep_time::Dt::from_days_f(0.0, Scale::UTC, Scale::UTC));
709/// assert_eq!(c, deep_time::Dt::from_days_f(1.0, Scale::TAI, Scale::UTC));
710/// ```
711#[macro_export]
712macro_rules! from_days_f {
713    ($days:expr, on=$scale:expr, target=$target:expr) => {
714        $crate::Dt::from_days_f($days, $scale, $target)
715    };
716    ($days:expr, target=$target:expr, on=$scale:expr) => {
717        $crate::Dt::from_days_f($days, $scale, $target)
718    };
719    ($days:expr, on=$scale:expr) => {
720        $crate::Dt::from_days_f($days, $scale, $scale)
721    };
722    ($days:expr, target=$target:expr) => {
723        $crate::Dt::from_days_f($days, $crate::Scale::TAI, $target)
724    };
725    ($days:expr) => {
726        $crate::Dt::from_days_f($days, $crate::Scale::TAI, $crate::Scale::TAI)
727    };
728}
729
730/// Builds a [`Dt`](../struct.Dt.html) from whole nanoseconds and an optional signed
731/// fractional remainder in attoseconds.
732///
733/// Sugar for [`Dt::from_ns`](../struct.Dt.html#method.from_ns). Does **not** perform
734/// time-scale conversion.
735///
736/// The fractional remainder is in **attoseconds** — use
737/// [`ps!`](../macro.ps.html) (or another `*_to_attos`
738/// helper) instead of writing the attosecond literal by hand.
739///
740/// ## Defaults
741///
742/// | Omitted | Default |
743/// |---------|---------|
744/// | fraction | `0` |
745/// | `on` and `target` | both [`Scale::TAI`](crate::Scale::TAI) |
746/// | only `on=s` | `target=s` |
747/// | only `target=t` | `on=TAI` |
748///
749/// ## Forms
750///
751/// ```text
752/// from_ns!(ns)
753/// from_ns!(ns, frac)
754/// from_ns!(ns, on=s)
755/// from_ns!(ns, target=t)
756/// from_ns!(ns, on=s, target=t)
757/// from_ns!(ns, target=t, on=s)
758/// from_ns!(ns, frac, on=s)
759/// from_ns!(ns, frac, target=t)
760/// from_ns!(ns, frac, on=s, target=t)
761/// from_ns!(ns, frac, target=t, on=s)
762/// ```
763///
764/// ## Examples
765///
766/// ```
767/// use deep_time::{Dt, Scale, from_ns, ps};
768///
769/// // 1.3 ns → whole nanoseconds + 300 ps remainder
770/// let a = from_ns!(1);
771/// let b = from_ns!(1, ps!(300));
772/// let c = from_ns!(-1, ps!(-300), on=Scale::TAI);
773/// let d = from_ns!(0, on=Scale::UTC);
774/// let e = from_ns!(1, on=Scale::TAI, target=Scale::UTC);
775/// let f = from_ns!(1, target=Scale::UTC);
776///
777/// assert_eq!(a, Dt::from_ns(1, 0, Scale::TAI, Scale::TAI));
778/// assert_eq!(b, Dt::from_ns(1, ps!(300), Scale::TAI, Scale::TAI));
779/// assert_eq!(c, Dt::from_ns(-1, ps!(-300), Scale::TAI, Scale::TAI));
780/// assert_eq!(d, Dt::from_ns(0, 0, Scale::UTC, Scale::UTC));
781/// assert_eq!(e, Dt::from_ns(1, 0, Scale::TAI, Scale::UTC));
782/// assert_eq!(f, e);
783///
784/// let signed = from_ns!(-1, ps!(-300));
785/// let floor = from_ns!(-2, ps!(700));
786/// assert_eq!(signed, floor);
787/// assert_eq!(signed, Dt::from_ns(-1, ps!(-300), Scale::TAI, Scale::TAI));
788/// ```
789#[macro_export]
790macro_rules! from_ns {
791    ($ns:expr, $frac:expr, on=$scale:expr, target=$target:expr) => {
792        $crate::Dt::from_ns($ns, $frac, $scale, $target)
793    };
794    ($ns:expr, $frac:expr, target=$target:expr, on=$scale:expr) => {
795        $crate::Dt::from_ns($ns, $frac, $scale, $target)
796    };
797    ($ns:expr, on=$scale:expr, target=$target:expr) => {
798        $crate::Dt::from_ns($ns, 0, $scale, $target)
799    };
800    ($ns:expr, target=$target:expr, on=$scale:expr) => {
801        $crate::Dt::from_ns($ns, 0, $scale, $target)
802    };
803    ($ns:expr, $frac:expr, on=$scale:expr) => {
804        $crate::Dt::from_ns($ns, $frac, $scale, $scale)
805    };
806    ($ns:expr, $frac:expr, target=$target:expr) => {
807        $crate::Dt::from_ns($ns, $frac, $crate::Scale::TAI, $target)
808    };
809    ($ns:expr, on=$scale:expr) => {
810        $crate::Dt::from_ns($ns, 0, $scale, $scale)
811    };
812    ($ns:expr, target=$target:expr) => {
813        $crate::Dt::from_ns($ns, 0, $crate::Scale::TAI, $target)
814    };
815    ($ns:expr, $frac:expr) => {
816        $crate::Dt::from_ns($ns, $frac, $crate::Scale::TAI, $crate::Scale::TAI)
817    };
818    ($ns:expr) => {
819        $crate::Dt::from_ns($ns, 0, $crate::Scale::TAI, $crate::Scale::TAI)
820    };
821}
822
823/// Builds a [`Dt`](../struct.Dt.html) from whole milliseconds and an optional signed
824/// fractional remainder in attoseconds.
825///
826/// Sugar for [`Dt::from_ms`](../struct.Dt.html#method.from_ms). Does **not** perform
827/// time-scale conversion.
828///
829/// The fractional remainder is in **attoseconds** — use
830/// [`us!`](../macro.us.html) (or another `*_to_attos`
831/// helper) instead of writing the attosecond literal by hand.
832///
833/// ## Defaults
834///
835/// | Omitted | Default |
836/// |---------|---------|
837/// | fraction | `0` |
838/// | `on` and `target` | both [`Scale::TAI`](crate::Scale::TAI) |
839/// | only `on=s` | `target=s` |
840/// | only `target=t` | `on=TAI` |
841///
842/// ## Forms
843///
844/// ```text
845/// from_ms!(ms)
846/// from_ms!(ms, frac)
847/// from_ms!(ms, on=s)
848/// from_ms!(ms, target=t)
849/// from_ms!(ms, on=s, target=t)
850/// from_ms!(ms, target=t, on=s)
851/// from_ms!(ms, frac, on=s)
852/// from_ms!(ms, frac, target=t)
853/// from_ms!(ms, frac, on=s, target=t)
854/// from_ms!(ms, frac, target=t, on=s)
855/// ```
856///
857/// ## Examples
858///
859/// ```
860/// use deep_time::{Dt, Scale, from_ms, us};
861///
862/// // 1.3 ms → whole milliseconds + 300 µs remainder
863/// let a = from_ms!(1);
864/// let b = from_ms!(1, us!(300));
865/// let c = from_ms!(-1, us!(-300), on=Scale::TAI);
866/// let d = from_ms!(0, on=Scale::UTC);
867/// let e = from_ms!(1, on=Scale::TAI, target=Scale::UTC);
868/// let f = from_ms!(1, target=Scale::UTC);
869///
870/// assert_eq!(a, Dt::from_ms(1, 0, Scale::TAI, Scale::TAI));
871/// assert_eq!(b, Dt::from_ms(1, us!(300), Scale::TAI, Scale::TAI));
872/// assert_eq!(c, Dt::from_ms(-1, us!(-300), Scale::TAI, Scale::TAI));
873/// assert_eq!(d, Dt::from_ms(0, 0, Scale::UTC, Scale::UTC));
874/// assert_eq!(e, Dt::from_ms(1, 0, Scale::TAI, Scale::UTC));
875/// assert_eq!(f, e);
876///
877/// let signed = from_ms!(-1, us!(-300));
878/// let floor = from_ms!(-2, us!(700));
879/// assert_eq!(signed, floor);
880/// assert_eq!(signed, Dt::from_ms(-1, us!(-300), Scale::TAI, Scale::TAI));
881/// ```
882#[macro_export]
883macro_rules! from_ms {
884    ($ms:expr, $frac:expr, on=$scale:expr, target=$target:expr) => {
885        $crate::Dt::from_ms($ms, $frac, $scale, $target)
886    };
887    ($ms:expr, $frac:expr, target=$target:expr, on=$scale:expr) => {
888        $crate::Dt::from_ms($ms, $frac, $scale, $target)
889    };
890    ($ms:expr, on=$scale:expr, target=$target:expr) => {
891        $crate::Dt::from_ms($ms, 0, $scale, $target)
892    };
893    ($ms:expr, target=$target:expr, on=$scale:expr) => {
894        $crate::Dt::from_ms($ms, 0, $scale, $target)
895    };
896    ($ms:expr, $frac:expr, on=$scale:expr) => {
897        $crate::Dt::from_ms($ms, $frac, $scale, $scale)
898    };
899    ($ms:expr, $frac:expr, target=$target:expr) => {
900        $crate::Dt::from_ms($ms, $frac, $crate::Scale::TAI, $target)
901    };
902    ($ms:expr, on=$scale:expr) => {
903        $crate::Dt::from_ms($ms, 0, $scale, $scale)
904    };
905    ($ms:expr, target=$target:expr) => {
906        $crate::Dt::from_ms($ms, 0, $crate::Scale::TAI, $target)
907    };
908    ($ms:expr, $frac:expr) => {
909        $crate::Dt::from_ms($ms, $frac, $crate::Scale::TAI, $crate::Scale::TAI)
910    };
911    ($ms:expr) => {
912        $crate::Dt::from_ms($ms, 0, $crate::Scale::TAI, $crate::Scale::TAI)
913    };
914}
915
916/// Builds a [`Dt`](../struct.Dt.html) from whole microseconds and an optional signed
917/// fractional remainder in attoseconds.
918///
919/// Sugar for [`Dt::from_us`](../struct.Dt.html#method.from_us). Does **not** perform
920/// time-scale conversion.
921///
922/// The fractional remainder is in **attoseconds** — use
923/// [`ns!`](../macro.ns.html) (or another `*_to_attos`
924/// helper) instead of writing the attosecond literal by hand.
925///
926/// ## Defaults
927///
928/// | Omitted | Default |
929/// |---------|---------|
930/// | fraction | `0` |
931/// | `on` and `target` | both [`Scale::TAI`](crate::Scale::TAI) |
932/// | only `on=s` | `target=s` |
933/// | only `target=t` | `on=TAI` |
934///
935/// ## Forms
936///
937/// ```text
938/// from_us!(us)
939/// from_us!(us, frac)
940/// from_us!(us, on=s)
941/// from_us!(us, target=t)
942/// from_us!(us, on=s, target=t)
943/// from_us!(us, target=t, on=s)
944/// from_us!(us, frac, on=s)
945/// from_us!(us, frac, target=t)
946/// from_us!(us, frac, on=s, target=t)
947/// from_us!(us, frac, target=t, on=s)
948/// ```
949///
950/// ## Examples
951///
952/// ```
953/// use deep_time::{Dt, Scale, from_us, ns};
954///
955/// // 1.3 µs → whole microseconds + 300 ns remainder
956/// let a = from_us!(1);
957/// let b = from_us!(1, ns!(300));
958/// let c = from_us!(-1, ns!(-300), on=Scale::TAI);
959/// let d = from_us!(0, on=Scale::UTC);
960/// let e = from_us!(1, on=Scale::TAI, target=Scale::UTC);
961/// let f = from_us!(1, target=Scale::UTC);
962///
963/// assert_eq!(a, Dt::from_us(1, 0, Scale::TAI, Scale::TAI));
964/// assert_eq!(b, Dt::from_us(1, ns!(300), Scale::TAI, Scale::TAI));
965/// assert_eq!(c, Dt::from_us(-1, ns!(-300), Scale::TAI, Scale::TAI));
966/// assert_eq!(d, Dt::from_us(0, 0, Scale::UTC, Scale::UTC));
967/// assert_eq!(e, Dt::from_us(1, 0, Scale::TAI, Scale::UTC));
968/// assert_eq!(f, e);
969///
970/// let signed = from_us!(-1, ns!(-300));
971/// let floor = from_us!(-2, ns!(700));
972/// assert_eq!(signed, floor);
973/// assert_eq!(signed, Dt::from_us(-1, ns!(-300), Scale::TAI, Scale::TAI));
974/// ```
975#[macro_export]
976macro_rules! from_us {
977    ($us:expr, $frac:expr, on=$scale:expr, target=$target:expr) => {
978        $crate::Dt::from_us($us, $frac, $scale, $target)
979    };
980    ($us:expr, $frac:expr, target=$target:expr, on=$scale:expr) => {
981        $crate::Dt::from_us($us, $frac, $scale, $target)
982    };
983    ($us:expr, on=$scale:expr, target=$target:expr) => {
984        $crate::Dt::from_us($us, 0, $scale, $target)
985    };
986    ($us:expr, target=$target:expr, on=$scale:expr) => {
987        $crate::Dt::from_us($us, 0, $scale, $target)
988    };
989    ($us:expr, $frac:expr, on=$scale:expr) => {
990        $crate::Dt::from_us($us, $frac, $scale, $scale)
991    };
992    ($us:expr, $frac:expr, target=$target:expr) => {
993        $crate::Dt::from_us($us, $frac, $crate::Scale::TAI, $target)
994    };
995    ($us:expr, on=$scale:expr) => {
996        $crate::Dt::from_us($us, 0, $scale, $scale)
997    };
998    ($us:expr, target=$target:expr) => {
999        $crate::Dt::from_us($us, 0, $crate::Scale::TAI, $target)
1000    };
1001    ($us:expr, $frac:expr) => {
1002        $crate::Dt::from_us($us, $frac, $crate::Scale::TAI, $crate::Scale::TAI)
1003    };
1004    ($us:expr) => {
1005        $crate::Dt::from_us($us, 0, $crate::Scale::TAI, $crate::Scale::TAI)
1006    };
1007}
1008
1009/// Builds a [`Dt`](../struct.Dt.html) from whole picoseconds and an optional signed
1010/// fractional remainder in attoseconds.
1011///
1012/// Sugar for [`Dt::from_ps`](../struct.Dt.html#method.from_ps). Does **not** perform
1013/// time-scale conversion.
1014///
1015/// The fractional remainder is in **attoseconds** — use
1016/// [`fs!`](../macro.fs.html) (or another `*_to_attos`
1017/// helper) instead of writing the attosecond literal by hand.
1018///
1019/// ## Defaults
1020///
1021/// | Omitted | Default |
1022/// |---------|---------|
1023/// | fraction | `0` |
1024/// | `on` and `target` | both [`Scale::TAI`](crate::Scale::TAI) |
1025/// | only `on=s` | `target=s` |
1026/// | only `target=t` | `on=TAI` |
1027///
1028/// ## Forms
1029///
1030/// ```text
1031/// from_ps!(ps)
1032/// from_ps!(ps, frac)
1033/// from_ps!(ps, on=s)
1034/// from_ps!(ps, target=t)
1035/// from_ps!(ps, on=s, target=t)
1036/// from_ps!(ps, target=t, on=s)
1037/// from_ps!(ps, frac, on=s)
1038/// from_ps!(ps, frac, target=t)
1039/// from_ps!(ps, frac, on=s, target=t)
1040/// from_ps!(ps, frac, target=t, on=s)
1041/// ```
1042///
1043/// ## Examples
1044///
1045/// ```
1046/// use deep_time::{Dt, Scale, from_ps, fs};
1047///
1048/// // 1.3 ps → whole picoseconds + 300 fs remainder
1049/// let a = from_ps!(1);
1050/// let b = from_ps!(1, fs!(300));
1051/// let c = from_ps!(-1, fs!(-300), on=Scale::TAI);
1052/// let d = from_ps!(0, on=Scale::UTC);
1053/// let e = from_ps!(1, on=Scale::TAI, target=Scale::UTC);
1054/// let f = from_ps!(1, target=Scale::UTC);
1055///
1056/// assert_eq!(a, Dt::from_ps(1, 0, Scale::TAI, Scale::TAI));
1057/// assert_eq!(b, Dt::from_ps(1, fs!(300), Scale::TAI, Scale::TAI));
1058/// assert_eq!(c, Dt::from_ps(-1, fs!(-300), Scale::TAI, Scale::TAI));
1059/// assert_eq!(d, Dt::from_ps(0, 0, Scale::UTC, Scale::UTC));
1060/// assert_eq!(e, Dt::from_ps(1, 0, Scale::TAI, Scale::UTC));
1061/// assert_eq!(f, e);
1062///
1063/// let signed = from_ps!(-1, fs!(-300));
1064/// let floor = from_ps!(-2, fs!(700));
1065/// assert_eq!(signed, floor);
1066/// assert_eq!(signed, Dt::from_ps(-1, fs!(-300), Scale::TAI, Scale::TAI));
1067/// ```
1068#[macro_export]
1069macro_rules! from_ps {
1070    ($ps:expr, $frac:expr, on=$scale:expr, target=$target:expr) => {
1071        $crate::Dt::from_ps($ps, $frac, $scale, $target)
1072    };
1073    ($ps:expr, $frac:expr, target=$target:expr, on=$scale:expr) => {
1074        $crate::Dt::from_ps($ps, $frac, $scale, $target)
1075    };
1076    ($ps:expr, on=$scale:expr, target=$target:expr) => {
1077        $crate::Dt::from_ps($ps, 0, $scale, $target)
1078    };
1079    ($ps:expr, target=$target:expr, on=$scale:expr) => {
1080        $crate::Dt::from_ps($ps, 0, $scale, $target)
1081    };
1082    ($ps:expr, $frac:expr, on=$scale:expr) => {
1083        $crate::Dt::from_ps($ps, $frac, $scale, $scale)
1084    };
1085    ($ps:expr, $frac:expr, target=$target:expr) => {
1086        $crate::Dt::from_ps($ps, $frac, $crate::Scale::TAI, $target)
1087    };
1088    ($ps:expr, on=$scale:expr) => {
1089        $crate::Dt::from_ps($ps, 0, $scale, $scale)
1090    };
1091    ($ps:expr, target=$target:expr) => {
1092        $crate::Dt::from_ps($ps, 0, $crate::Scale::TAI, $target)
1093    };
1094    ($ps:expr, $frac:expr) => {
1095        $crate::Dt::from_ps($ps, $frac, $crate::Scale::TAI, $crate::Scale::TAI)
1096    };
1097    ($ps:expr) => {
1098        $crate::Dt::from_ps($ps, 0, $crate::Scale::TAI, $crate::Scale::TAI)
1099    };
1100}
1101
1102/// Builds a [`Dt`](../struct.Dt.html) from whole femtoseconds and an optional signed
1103/// fractional remainder in attoseconds.
1104///
1105/// Sugar for [`Dt::from_fs`](../struct.Dt.html#method.from_fs). Does **not** perform
1106/// time-scale conversion.
1107///
1108/// The fractional remainder is already in **attoseconds** (one femtosecond is
1109/// 1000 attoseconds) — there is no smaller named unit macro.
1110///
1111/// ## Defaults
1112///
1113/// | Omitted | Default |
1114/// |---------|---------|
1115/// | fraction | `0` |
1116/// | `on` and `target` | both [`Scale::TAI`](crate::Scale::TAI) |
1117/// | only `on=s` | `target=s` |
1118/// | only `target=t` | `on=TAI` |
1119///
1120/// ## Forms
1121///
1122/// ```text
1123/// from_fs!(fs)
1124/// from_fs!(fs, frac)
1125/// from_fs!(fs, on=s)
1126/// from_fs!(fs, target=t)
1127/// from_fs!(fs, on=s, target=t)
1128/// from_fs!(fs, target=t, on=s)
1129/// from_fs!(fs, frac, on=s)
1130/// from_fs!(fs, frac, target=t)
1131/// from_fs!(fs, frac, on=s, target=t)
1132/// from_fs!(fs, frac, target=t, on=s)
1133/// ```
1134///
1135/// ## Examples
1136///
1137/// ```
1138/// use deep_time::{Dt, Scale, from_fs};
1139///
1140/// // 1.3 fs → whole femtoseconds + 300 attoseconds remainder
1141/// let a = from_fs!(1);
1142/// let b = from_fs!(1, 300);
1143/// let c = from_fs!(-1, -300, on=Scale::TAI);
1144/// let d = from_fs!(0, on=Scale::UTC);
1145/// let e = from_fs!(1, on=Scale::TAI, target=Scale::UTC);
1146/// let f = from_fs!(1, target=Scale::UTC);
1147///
1148/// assert_eq!(a, Dt::from_fs(1, 0, Scale::TAI, Scale::TAI));
1149/// assert_eq!(b, Dt::from_fs(1, 300, Scale::TAI, Scale::TAI));
1150/// assert_eq!(c, Dt::from_fs(-1, -300, Scale::TAI, Scale::TAI));
1151/// assert_eq!(d, Dt::from_fs(0, 0, Scale::UTC, Scale::UTC));
1152/// assert_eq!(e, Dt::from_fs(1, 0, Scale::TAI, Scale::UTC));
1153/// assert_eq!(f, e);
1154///
1155/// let signed = from_fs!(-1, -300);
1156/// let floor = from_fs!(-2, 700);
1157/// assert_eq!(signed, floor);
1158/// assert_eq!(signed, Dt::from_fs(-1, -300, Scale::TAI, Scale::TAI));
1159/// ```
1160#[macro_export]
1161macro_rules! from_fs {
1162    ($fs:expr, $frac:expr, on=$scale:expr, target=$target:expr) => {
1163        $crate::Dt::from_fs($fs, $frac, $scale, $target)
1164    };
1165    ($fs:expr, $frac:expr, target=$target:expr, on=$scale:expr) => {
1166        $crate::Dt::from_fs($fs, $frac, $scale, $target)
1167    };
1168    ($fs:expr, on=$scale:expr, target=$target:expr) => {
1169        $crate::Dt::from_fs($fs, 0, $scale, $target)
1170    };
1171    ($fs:expr, target=$target:expr, on=$scale:expr) => {
1172        $crate::Dt::from_fs($fs, 0, $scale, $target)
1173    };
1174    ($fs:expr, $frac:expr, on=$scale:expr) => {
1175        $crate::Dt::from_fs($fs, $frac, $scale, $scale)
1176    };
1177    ($fs:expr, $frac:expr, target=$target:expr) => {
1178        $crate::Dt::from_fs($fs, $frac, $crate::Scale::TAI, $target)
1179    };
1180    ($fs:expr, on=$scale:expr) => {
1181        $crate::Dt::from_fs($fs, 0, $scale, $scale)
1182    };
1183    ($fs:expr, target=$target:expr) => {
1184        $crate::Dt::from_fs($fs, 0, $crate::Scale::TAI, $target)
1185    };
1186    ($fs:expr, $frac:expr) => {
1187        $crate::Dt::from_fs($fs, $frac, $crate::Scale::TAI, $crate::Scale::TAI)
1188    };
1189    ($fs:expr) => {
1190        $crate::Dt::from_fs($fs, 0, $crate::Scale::TAI, $crate::Scale::TAI)
1191    };
1192}
1193
1194/// Builds a **TAI** [`Dt`](../struct.Dt.html) from a Julian Date (whole days plus
1195/// optional attosecond remainder).
1196///
1197/// Sugar for [`Dt::from_jd`](../struct.Dt.html#method.from_jd).
1198///
1199/// When an `on` arg is provided and it's not [`Scale::TAI`](crate::Scale::TAI)
1200/// then a time scale conversion is performed equivalent to `on` ->
1201/// [`Scale::TAI`](crate::Scale::TAI).
1202///
1203/// There is no `target=` on this macro — the returned [`Dt`](../struct.Dt.html)'s
1204/// `target` is set from `on` (or TAI when omitted), as
1205/// [`from_jd`](../struct.Dt.html#method.from_jd) does. Chain
1206/// [`.target(…)`](../struct.Dt.html#method.target) if needed.
1207///
1208/// The fractional remainder is in **attoseconds** — use a `*_to_attos` helper
1209/// (e.g. a day fraction built from [`days_f!`](../macro.days_f.html))
1210/// instead of hand-counting zeros when convenient.
1211///
1212/// ## Defaults
1213///
1214/// | Omitted | Default |
1215/// |---------|---------|
1216/// | fraction | `0` |
1217/// | `on` | [`Scale::TAI`](crate::Scale::TAI) |
1218///
1219/// ## Forms
1220///
1221/// ```text
1222/// from_jd!(jd_days)
1223/// from_jd!(jd_days, frac)
1224/// from_jd!(jd_days, on=s)
1225/// from_jd!(jd_days, frac, on=s)
1226/// ```
1227///
1228/// ## Examples
1229///
1230/// ```
1231/// use deep_time::{Dt, Scale, days_f, from_jd};
1232///
1233/// // 2_460_782.25
1234/// let a = from_jd!(2_460_782);
1235/// let b = from_jd!(2_460_782, days_f!(0.25));
1236/// let c = from_jd!(2_460_782, days_f!(0.25), on=Scale::TAI);
1237/// let d = from_jd!(2_460_782, on=Scale::UTC);
1238///
1239/// assert_eq!(a, Dt::from_jd(2_460_782, 0, Scale::TAI));
1240/// assert_eq!(b, Dt::from_jd(2_460_782, days_f!(0.25), Scale::TAI));
1241/// assert_eq!(c, b);
1242/// assert_eq!(d, Dt::from_jd(2_460_782, 0, Scale::UTC));
1243///
1244/// // -1_000.25 (signed remainder)
1245/// let neg = from_jd!(-1_000, -days_f!(0.25));
1246/// assert_eq!(neg, Dt::from_jd(-1_000, -days_f!(0.25), Scale::TAI));
1247/// assert_eq!(neg.to_jd(), (-1_000, -days_f!(0.25)));
1248///
1249/// // or with floor style
1250/// assert_eq!(neg, from_jd!(-1_001, days_f!(0.75)));
1251/// ```
1252#[macro_export]
1253macro_rules! from_jd {
1254    // `on=` arms before bare `$frac:expr` so `on=…` is not taken as an expr.
1255    ($jd_days:expr, $frac:expr, on=$scale:expr) => {
1256        $crate::Dt::from_jd($jd_days, $frac, $scale)
1257    };
1258    ($jd_days:expr, on=$scale:expr) => {
1259        $crate::Dt::from_jd($jd_days, 0, $scale)
1260    };
1261    ($jd_days:expr, $frac:expr) => {
1262        $crate::Dt::from_jd($jd_days, $frac, $crate::Scale::TAI)
1263    };
1264    ($jd_days:expr) => {
1265        $crate::Dt::from_jd($jd_days, 0, $crate::Scale::TAI)
1266    };
1267}
1268
1269/// Builds a **TAI** [`Dt`](../struct.Dt.html) from a floating-point Julian Date.
1270///
1271/// Sugar for [`Dt::from_jd_f`](../struct.Dt.html#method.from_jd_f).
1272///
1273/// When an `on` arg is provided and it's not [`Scale::TAI`](crate::Scale::TAI)
1274/// then a time scale conversion is performed equivalent to `on` ->
1275/// [`Scale::TAI`](crate::Scale::TAI).
1276///
1277/// There is no `target=` on this macro — the returned [`Dt`](../struct.Dt.html)'s
1278/// `target` is set from `on` (or TAI when omitted), as
1279/// [`from_jd_f`](../struct.Dt.html#method.from_jd_f) does. Chain
1280/// [`.target(…)`](../struct.Dt.html#method.target) if needed.
1281///
1282/// ## Defaults
1283///
1284/// | Omitted | Default |
1285/// |---------|---------|
1286/// | `on` | [`Scale::TAI`](crate::Scale::TAI) |
1287///
1288/// ## Forms
1289///
1290/// ```text
1291/// from_jd_f!(jd)
1292/// from_jd_f!(jd, on=s)
1293/// ```
1294///
1295/// ## Examples
1296///
1297/// ```
1298/// use deep_time::{Dt, Scale, days_f, from_jd_f};
1299///
1300/// // 2_460_782.25
1301/// let a = from_jd_f!(2_460_782.25);
1302/// let b = from_jd_f!(2_460_782.25, on=Scale::TAI);
1303/// let c = from_jd_f!(2_460_782.0, on=Scale::UTC);
1304///
1305/// assert_eq!(a, Dt::from_jd_f(2_460_782.25, Scale::TAI));
1306/// assert_eq!(b, a);
1307/// assert_eq!(c, Dt::from_jd_f(2_460_782.0, Scale::UTC));
1308/// assert_eq!(a.to_jd(), (2_460_782, days_f!(0.25)));
1309///
1310/// // -1_000.25 (signed remainder)
1311/// let neg = from_jd_f!(-1_000.25);
1312/// assert_eq!(neg, Dt::from_jd_f(-1_000.25, Scale::TAI));
1313/// assert_eq!(neg.to_jd(), (-1_000, -days_f!(0.25)));
1314/// ```
1315#[macro_export]
1316macro_rules! from_jd_f {
1317    ($jd:expr, on=$scale:expr) => {
1318        $crate::Dt::from_jd_f($jd, $scale)
1319    };
1320    ($jd:expr) => {
1321        $crate::Dt::from_jd_f($jd, $crate::Scale::TAI)
1322    };
1323}
1324
1325/// Builds a **TAI** [`Dt`](../struct.Dt.html) from a Modified Julian Date (whole days
1326/// plus optional attosecond remainder).
1327///
1328/// Sugar for [`Dt::from_mjd`](../struct.Dt.html#method.from_mjd).
1329///
1330/// When an `on` arg is provided and it's not [`Scale::TAI`](crate::Scale::TAI)
1331/// then a time scale conversion is performed equivalent to `on` ->
1332/// [`Scale::TAI`](crate::Scale::TAI).
1333///
1334/// There is no `target=` on this macro — the returned [`Dt`](../struct.Dt.html)'s
1335/// `target` is set from `on` (or TAI when omitted), as
1336/// [`from_mjd`](../struct.Dt.html#method.from_mjd) does. Chain
1337/// [`.target(…)`](../struct.Dt.html#method.target) if needed.
1338///
1339/// MJD and JD relate by `JD = MJD + 2_400_000.5`.
1340///
1341/// The fractional remainder is in **attoseconds** — use a `*_to_attos` helper
1342/// (e.g. a day fraction built from [`days_f!`](../macro.days_f.html))
1343/// instead of hand-counting zeros when convenient.
1344///
1345/// ## Defaults
1346///
1347/// | Omitted | Default |
1348/// |---------|---------|
1349/// | fraction | `0` |
1350/// | `on` | [`Scale::TAI`](crate::Scale::TAI) |
1351///
1352/// ## Forms
1353///
1354/// ```text
1355/// from_mjd!(mjd_days)
1356/// from_mjd!(mjd_days, frac)
1357/// from_mjd!(mjd_days, on=s)
1358/// from_mjd!(mjd_days, frac, on=s)
1359/// ```
1360///
1361/// ## Examples
1362///
1363/// ```
1364/// use deep_time::{Dt, Scale, days_f, from_mjd};
1365///
1366/// // J2000.0 → MJD 51_544.5
1367/// let a = from_mjd!(51_544);
1368/// let b = from_mjd!(51_544, days_f!(0.5));
1369/// let c = from_mjd!(51_544, days_f!(0.5), on=Scale::TAI);
1370/// let d = from_mjd!(51_544, on=Scale::UTC);
1371///
1372/// assert_eq!(a, Dt::from_mjd(51_544, 0, Scale::TAI));
1373/// assert_eq!(b, Dt::from_mjd(51_544, days_f!(0.5), Scale::TAI));
1374/// assert_eq!(c, b);
1375/// assert_eq!(d, Dt::from_mjd(51_544, 0, Scale::UTC));
1376/// assert_eq!(b.to_mjd(), (51_544, days_f!(0.5)));
1377///
1378/// // -1_000.25 (signed truncating remainder)
1379/// let neg = from_mjd!(-1_000, -days_f!(0.25));
1380/// assert_eq!(neg, Dt::from_mjd(-1_000, -days_f!(0.25), Scale::TAI));
1381/// assert_eq!(neg.to_mjd(), (-1_000, -days_f!(0.25)));
1382/// ```
1383#[macro_export]
1384macro_rules! from_mjd {
1385    // `on=` arms before bare `$frac:expr` so `on=…` is not taken as an expr.
1386    ($mjd_days:expr, $frac:expr, on=$scale:expr) => {
1387        $crate::Dt::from_mjd($mjd_days, $frac, $scale)
1388    };
1389    ($mjd_days:expr, on=$scale:expr) => {
1390        $crate::Dt::from_mjd($mjd_days, 0, $scale)
1391    };
1392    ($mjd_days:expr, $frac:expr) => {
1393        $crate::Dt::from_mjd($mjd_days, $frac, $crate::Scale::TAI)
1394    };
1395    ($mjd_days:expr) => {
1396        $crate::Dt::from_mjd($mjd_days, 0, $crate::Scale::TAI)
1397    };
1398}
1399
1400/// Builds a **TAI** [`Dt`](../struct.Dt.html) from a floating-point Modified Julian Date.
1401///
1402/// Sugar for [`Dt::from_mjd_f`](../struct.Dt.html#method.from_mjd_f).
1403///
1404/// When an `on` arg is provided and it's not [`Scale::TAI`](crate::Scale::TAI)
1405/// then a time scale conversion is performed equivalent to `on` ->
1406/// [`Scale::TAI`](crate::Scale::TAI).
1407///
1408/// There is no `target=` on this macro — the returned [`Dt`](../struct.Dt.html)'s
1409/// `target` is set from `on` (or TAI when omitted), as
1410/// [`from_mjd_f`](../struct.Dt.html#method.from_mjd_f) does. Chain
1411/// [`.target(…)`](../struct.Dt.html#method.target) if needed.
1412///
1413/// MJD and JD relate by `JD = MJD + 2_400_000.5`.
1414///
1415/// ## Defaults
1416///
1417/// | Omitted | Default |
1418/// |---------|---------|
1419/// | `on` | [`Scale::TAI`](crate::Scale::TAI) |
1420///
1421/// ## Forms
1422///
1423/// ```text
1424/// from_mjd_f!(mjd)
1425/// from_mjd_f!(mjd, on=s)
1426/// ```
1427///
1428/// ## Examples
1429///
1430/// ```
1431/// use deep_time::{Dt, Scale, days_f, from_mjd_f};
1432///
1433/// // 60_961.25
1434/// let a = from_mjd_f!(60_961.25);
1435/// let b = from_mjd_f!(60_961.25, on=Scale::TAI);
1436/// let c = from_mjd_f!(60_961.0, on=Scale::UTC);
1437///
1438/// assert_eq!(a, Dt::from_mjd_f(60_961.25, Scale::TAI));
1439/// assert_eq!(b, a);
1440/// assert_eq!(c, Dt::from_mjd_f(60_961.0, Scale::UTC));
1441/// assert_eq!(a.to_mjd_floor(), (60_961, days_f!(0.25)));
1442///
1443/// // -1_000.25 as -1_001 + 0.75 day
1444/// let neg = from_mjd_f!(-1_000.25);
1445/// assert_eq!(neg, Dt::from_mjd_f(-1_000.25, Scale::TAI));
1446/// assert_eq!(neg.to_mjd_floor(), (-1_001, days_f!(0.75)));
1447/// ```
1448#[macro_export]
1449macro_rules! from_mjd_f {
1450    ($mjd:expr, on=$scale:expr) => {
1451        $crate::Dt::from_mjd_f($mjd, $scale)
1452    };
1453    ($mjd:expr) => {
1454        $crate::Dt::from_mjd_f($mjd, $crate::Scale::TAI)
1455    };
1456}
1457
1458/// Builds a [`Dt`](../struct.Dt.html) from a Gregorian calendar date and optional time.
1459///
1460/// Sugar for [`Dt::from_ymd`](../struct.Dt.html#method.from_ymd).
1461///
1462/// Date fields are positional (`y`, `m`, `d`). Time is optional: put a
1463/// **semicolon after the day**, then hour (required if `;` is present), then
1464/// optional minute, second, and attoseconds. An optional `on=` civil scale may
1465/// follow.
1466///
1467/// A time scale conversion is performed from the `on` arg ->
1468/// [`Scale::TAI`](crate::Scale::TAI).
1469///
1470/// When no `on` arg is used the time scale is assumed to be
1471/// [`Scale::UTC`](crate::Scale::UTC).
1472///
1473/// | Omitted field | Default |
1474/// |---------------|---------|
1475/// | month | `1` |
1476/// | day | `1` |
1477/// | time (no `;`) | `0, 0, 0, 0` |
1478/// | minute / second / attos after `; h` | `0` |
1479/// | `on` | [`Scale::UTC`](crate::Scale::UTC) |
1480///
1481/// The resulting [`Dt`](../struct.Dt.html)'s `target` field is set from that civil
1482/// scale (the `on=` value, or UTC when omitted), as
1483/// [`Dt::from_ymd`](../struct.Dt.html#method.from_ymd) does. There is no `target=` on
1484/// this macro — chain [`.target(…)`](../struct.Dt.html#method.target) if needed.
1485///
1486/// ## Forms
1487///
1488/// ```text
1489/// from_ymd!(y)
1490/// from_ymd!(y, m)
1491/// from_ymd!(y, m, d)
1492/// from_ymd!(y, m, d, on=Scale::TAI)
1493/// from_ymd!(y, m, d; h)
1494/// from_ymd!(y, m, d; h, min)
1495/// from_ymd!(y, m, d; h, min, sec)
1496/// from_ymd!(y, m, d; h, min, sec, attos)
1497/// from_ymd!(y, m, d; h, min, sec, attos, on=Scale::UTC)
1498/// ```
1499///
1500/// ## Examples
1501///
1502/// ```
1503/// use deep_time::Scale;
1504/// use deep_time::from_ymd;
1505///
1506/// assert_eq!(
1507///     from_ymd!(1970),
1508///     deep_time::Dt::UNIX_EPOCH,
1509/// );
1510/// assert_eq!(
1511///     from_ymd!(2026, 6, 16),
1512///     deep_time::Dt::from_ymd(2026, 6, 16, Scale::UTC, 0, 0, 0, 0),
1513/// );
1514/// assert_eq!(
1515///     from_ymd!(2000, 1, 1; 12, on=Scale::TAI),
1516///     deep_time::Dt::ZERO,
1517/// );
1518/// assert_eq!(
1519///     from_ymd!(2000, 1, 1; 12, 0, 0, 123_456_789, on=Scale::UTC),
1520///     deep_time::Dt::from_ymd(2000, 1, 1, Scale::UTC, 12, 0, 0, 123_456_789),
1521/// );
1522///
1523/// // different target field after construction
1524/// let _ = from_ymd!(2020, 1, 1, on=Scale::UTC).target(Scale::TAI);
1525/// ```
1526#[macro_export]
1527macro_rules! from_ymd {
1528    // Time section: `d; h …` — `on=` arms before bare so `on=…` is not an `:expr`.
1529    ($y:expr, $m:expr, $d:expr; $h:expr, $min:expr, $s:expr, $attos:expr, on=$scale:expr) => {
1530        $crate::Dt::from_ymd($y, $m, $d, $scale, $h, $min, $s, $attos)
1531    };
1532    ($y:expr, $m:expr, $d:expr; $h:expr, $min:expr, $s:expr, on=$scale:expr) => {
1533        $crate::Dt::from_ymd($y, $m, $d, $scale, $h, $min, $s, 0)
1534    };
1535    ($y:expr, $m:expr, $d:expr; $h:expr, $min:expr, on=$scale:expr) => {
1536        $crate::Dt::from_ymd($y, $m, $d, $scale, $h, $min, 0, 0)
1537    };
1538    ($y:expr, $m:expr, $d:expr; $h:expr, on=$scale:expr) => {
1539        $crate::Dt::from_ymd($y, $m, $d, $scale, $h, 0, 0, 0)
1540    };
1541    ($y:expr, $m:expr, $d:expr; $h:expr, $min:expr, $s:expr, $attos:expr) => {
1542        $crate::Dt::from_ymd($y, $m, $d, $crate::Scale::UTC, $h, $min, $s, $attos)
1543    };
1544    ($y:expr, $m:expr, $d:expr; $h:expr, $min:expr, $s:expr) => {
1545        $crate::Dt::from_ymd($y, $m, $d, $crate::Scale::UTC, $h, $min, $s, 0)
1546    };
1547    ($y:expr, $m:expr, $d:expr; $h:expr, $min:expr) => {
1548        $crate::Dt::from_ymd($y, $m, $d, $crate::Scale::UTC, $h, $min, 0, 0)
1549    };
1550    ($y:expr, $m:expr, $d:expr; $h:expr) => {
1551        $crate::Dt::from_ymd($y, $m, $d, $crate::Scale::UTC, $h, 0, 0, 0)
1552    };
1553
1554    // Date only (+ optional on=)
1555    ($y:expr, $m:expr, $d:expr, on=$scale:expr) => {
1556        $crate::Dt::from_ymd($y, $m, $d, $scale, 0, 0, 0, 0)
1557    };
1558    ($y:expr, $m:expr, on=$scale:expr) => {
1559        $crate::Dt::from_ymd($y, $m, 1, $scale, 0, 0, 0, 0)
1560    };
1561    ($y:expr, on=$scale:expr) => {
1562        $crate::Dt::from_ymd($y, 1, 1, $scale, 0, 0, 0, 0)
1563    };
1564    ($y:expr, $m:expr, $d:expr) => {
1565        $crate::Dt::from_ymd($y, $m, $d, $crate::Scale::UTC, 0, 0, 0, 0)
1566    };
1567    ($y:expr, $m:expr) => {
1568        $crate::Dt::from_ymd($y, $m, 1, $crate::Scale::UTC, 0, 0, 0, 0)
1569    };
1570    ($y:expr) => {
1571        $crate::Dt::from_ymd($y, 1, 1, $crate::Scale::UTC, 0, 0, 0, 0)
1572    };
1573}