1use std::fmt::Display;
17use std::ops::{Add, AddAssign, Mul, Neg, Sub, SubAssign};
18
19use lox_test_utils::approx_eq::ApproxEq;
20
21use crate::f64;
22use crate::i64::consts::{
23 ATTOSECONDS_IN_FEMTOSECOND, ATTOSECONDS_IN_MICROSECOND, ATTOSECONDS_IN_MILLISECOND,
24 ATTOSECONDS_IN_NANOSECOND, ATTOSECONDS_IN_PICOSECOND, ATTOSECONDS_IN_SECOND,
25 SECONDS_BETWEEN_JD_AND_J2000, SECONDS_PER_DAY as I64_SECONDS_PER_DAY,
26 SECONDS_PER_HOUR as I64_SECONDS_PER_HOUR, SECONDS_PER_MINUTE as I64_SECONDS_PER_MINUTE,
27};
28use crate::types::units::Days;
29
30use super::julian_dates::{Epoch, JulianDate, Unit};
31use super::subsecond::Subsecond;
32
33pub trait TimeUnits {
45 fn days(&self) -> TimeDelta;
47 fn hours(&self) -> TimeDelta;
49 fn mins(&self) -> TimeDelta;
51 fn secs(&self) -> TimeDelta;
53 fn millis(&self) -> TimeDelta;
55 fn micros(&self) -> TimeDelta;
57 fn nanos(&self) -> TimeDelta;
59 fn picos(&self) -> TimeDelta;
61 fn femtos(&self) -> TimeDelta;
63 fn attos(&self) -> TimeDelta;
65}
66
67impl TimeUnits for f64 {
68 fn days(&self) -> TimeDelta {
69 TimeDelta::from_days_f64(*self)
70 }
71 fn hours(&self) -> TimeDelta {
72 TimeDelta::from_hours_f64(*self)
73 }
74 fn mins(&self) -> TimeDelta {
75 TimeDelta::from_minutes_f64(*self)
76 }
77 fn secs(&self) -> TimeDelta {
78 TimeDelta::from_seconds_f64(*self)
79 }
80 fn millis(&self) -> TimeDelta {
81 TimeDelta::from_seconds_f64(*self * f64::consts::SECONDS_PER_MILLISECOND)
82 }
83 fn micros(&self) -> TimeDelta {
84 TimeDelta::from_seconds_f64(*self * f64::consts::SECONDS_PER_MICROSECOND)
85 }
86 fn nanos(&self) -> TimeDelta {
87 TimeDelta::from_seconds_f64(*self * f64::consts::SECONDS_PER_NANOSECOND)
88 }
89 fn picos(&self) -> TimeDelta {
90 TimeDelta::from_seconds_f64(*self * f64::consts::SECONDS_PER_PICOSECOND)
91 }
92 fn femtos(&self) -> TimeDelta {
93 TimeDelta::from_seconds_f64(*self * f64::consts::SECONDS_PER_FEMTOSECOND)
94 }
95 fn attos(&self) -> TimeDelta {
96 TimeDelta::from_seconds_f64(*self * f64::consts::SECONDS_PER_ATTOSECOND)
97 }
98}
99
100impl TimeUnits for i64 {
101 fn days(&self) -> TimeDelta {
102 TimeDelta::from_days(*self)
103 }
104 fn hours(&self) -> TimeDelta {
105 TimeDelta::from_hours(*self)
106 }
107 fn mins(&self) -> TimeDelta {
108 TimeDelta::from_minutes(*self)
109 }
110 fn secs(&self) -> TimeDelta {
111 TimeDelta::from_seconds(*self)
112 }
113 fn millis(&self) -> TimeDelta {
114 TimeDelta::from_milliseconds(*self)
115 }
116 fn micros(&self) -> TimeDelta {
117 TimeDelta::from_microseconds(*self)
118 }
119 fn nanos(&self) -> TimeDelta {
120 TimeDelta::from_nanoseconds(*self)
121 }
122 fn picos(&self) -> TimeDelta {
123 TimeDelta::from_picoseconds(*self)
124 }
125 fn femtos(&self) -> TimeDelta {
126 TimeDelta::from_femtoseconds(*self)
127 }
128 fn attos(&self) -> TimeDelta {
129 TimeDelta::from_attoseconds(*self)
130 }
131}
132
133pub trait ToDelta {
135 fn to_delta(&self) -> TimeDelta;
137}
138
139#[derive(Copy, Clone, Debug, Default, PartialEq)]
149pub struct Seconds {
150 pub hi: f64,
152 pub lo: f64,
154}
155
156impl Seconds {
157 pub const fn new(hi: f64, lo: f64) -> Self {
159 Self { hi, lo }
160 }
161
162 pub const fn from_f64(value: f64) -> Self {
164 Self { hi: value, lo: 0.0 }
165 }
166
167 pub const fn to_f64(self) -> f64 {
169 self.hi + self.lo
170 }
171
172 pub const fn is_nan(self) -> bool {
174 self.hi.is_nan() || self.lo.is_nan()
175 }
176
177 pub const fn is_infinite(self) -> bool {
179 self.hi.is_infinite() || self.lo.is_infinite()
180 }
181
182 fn compensated_add(self, other: Self) -> Self {
184 let (s, e) = two_sum(self.hi, other.hi);
185 let e = e + self.lo + other.lo;
186 let (hi, lo) = two_sum(s, e);
187 Self { hi, lo }
188 }
189
190 fn compensated_sub(self, other: Self) -> Self {
192 self.compensated_add(other.neg())
193 }
194
195 pub const fn neg(self) -> Self {
197 Self {
198 hi: -self.hi,
199 lo: -self.lo,
200 }
201 }
202
203 pub fn mul_f64(self, rhs: f64) -> Self {
205 let (p, e) = two_prod(self.hi, rhs);
206 let e = e + self.lo * rhs;
207 let (hi, lo) = two_sum(p, e);
208 Self { hi, lo }
209 }
210
211 fn compensated_mul(self, other: Self) -> Self {
213 let (p, e) = two_prod(self.hi, other.hi);
214 let e = e + self.hi * other.lo + self.lo * other.hi;
215 let (hi, lo) = two_sum(p, e);
216 Self { hi, lo }
217 }
218}
219
220impl Add for Seconds {
221 type Output = Self;
222 fn add(self, rhs: Self) -> Self::Output {
223 self.compensated_add(rhs)
224 }
225}
226
227impl Sub for Seconds {
228 type Output = Self;
229 fn sub(self, rhs: Self) -> Self::Output {
230 self.compensated_sub(rhs)
231 }
232}
233
234impl Neg for Seconds {
235 type Output = Self;
236 fn neg(self) -> Self::Output {
237 Seconds::neg(self)
238 }
239}
240
241impl Mul<f64> for Seconds {
242 type Output = Self;
243 fn mul(self, rhs: f64) -> Self::Output {
244 self.mul_f64(rhs)
245 }
246}
247
248impl Mul for Seconds {
249 type Output = Self;
250 fn mul(self, rhs: Self) -> Self::Output {
251 self.compensated_mul(rhs)
252 }
253}
254
255impl Mul<Seconds> for f64 {
256 type Output = Seconds;
257 fn mul(self, rhs: Seconds) -> Self::Output {
258 rhs.mul_f64(self)
259 }
260}
261
262impl From<f64> for Seconds {
263 fn from(value: f64) -> Self {
264 Self::from_f64(value)
265 }
266}
267
268#[inline]
272fn two_sum(a: f64, b: f64) -> (f64, f64) {
273 let s = a + b;
274 let v = s - a;
275 let e = (a - (s - v)) + (b - v);
276 (s, e)
277}
278
279#[inline]
283fn two_prod(a: f64, b: f64) -> (f64, f64) {
284 let p = a * b;
285 let e = a.mul_add(b, -p); (p, e)
287}
288
289#[derive(Copy, Clone, Debug, PartialEq, Eq)]
294#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
295pub enum TimeDelta {
296 Valid {
298 seconds: i64,
300 attoseconds: i64,
302 },
303 NaN,
305 PosInf,
307 NegInf,
309}
310
311impl TimeDelta {
312 pub const ZERO: Self = TimeDelta::from_seconds(0);
314
315 pub const fn new(seconds: i64, attoseconds: i64) -> Self {
330 let (seconds, attoseconds) = Self::normalize(seconds, attoseconds);
331 Self::Valid {
332 seconds,
333 attoseconds,
334 }
335 }
336
337 const fn normalize(mut seconds: i64, mut attoseconds: i64) -> (i64, i64) {
339 if attoseconds >= ATTOSECONDS_IN_SECOND {
341 let carry = attoseconds / ATTOSECONDS_IN_SECOND;
342 seconds += carry;
343 attoseconds %= ATTOSECONDS_IN_SECOND;
344 }
345
346 if attoseconds < 0 {
348 let borrow = (-attoseconds + ATTOSECONDS_IN_SECOND - 1) / ATTOSECONDS_IN_SECOND;
350 seconds -= borrow;
351 attoseconds += borrow * ATTOSECONDS_IN_SECOND;
352 }
353
354 (seconds, attoseconds)
355 }
356
357 pub const fn builder() -> TimeDeltaBuilder {
359 TimeDeltaBuilder::new()
360 }
361
362 pub const fn from_seconds_f64(value: f64) -> Self {
366 if value.is_nan() {
367 return TimeDelta::NaN;
368 }
369 if value < i64::MIN as f64 {
370 return TimeDelta::NegInf;
371 }
372 if value > i64::MAX as f64 {
373 return TimeDelta::PosInf;
374 }
375 let seconds = value.round_ties_even();
376 let subseconds = value - seconds;
377 if subseconds.is_sign_negative() {
378 let seconds = seconds as i64 - 1;
379 let attoseconds =
380 (subseconds * ATTOSECONDS_IN_SECOND as f64).round() as i64 + ATTOSECONDS_IN_SECOND;
381 TimeDelta::Valid {
382 seconds,
383 attoseconds,
384 }
385 } else {
386 let seconds = seconds as i64;
387 let attoseconds = (subseconds * ATTOSECONDS_IN_SECOND as f64).round() as i64;
388 TimeDelta::Valid {
389 seconds,
390 attoseconds,
391 }
392 }
393 }
394
395 pub const fn from_seconds(seconds: i64) -> Self {
397 Self::new(seconds, 0)
398 }
399
400 pub const fn from_minutes(minutes: i64) -> Self {
402 Self::from_seconds(minutes * I64_SECONDS_PER_MINUTE)
403 }
404
405 pub const fn from_minutes_f64(value: f64) -> Self {
407 Self::from_seconds_f64(value * f64::consts::SECONDS_PER_MINUTE)
408 }
409
410 pub const fn from_hours(hours: i64) -> Self {
412 Self::from_seconds(hours * I64_SECONDS_PER_HOUR)
413 }
414
415 pub const fn from_hours_f64(value: f64) -> Self {
417 Self::from_seconds_f64(value * f64::consts::SECONDS_PER_HOUR)
418 }
419
420 pub const fn from_days(days: i64) -> Self {
422 Self::from_seconds(days * I64_SECONDS_PER_DAY)
423 }
424
425 pub const fn from_days_f64(value: f64) -> Self {
427 Self::from_seconds_f64(value * f64::consts::SECONDS_PER_DAY)
428 }
429
430 pub const fn from_milliseconds(ms: i64) -> Self {
432 let seconds = ms / 1000;
433 let remainder = ms % 1000;
434 Self::new(seconds, remainder * ATTOSECONDS_IN_MILLISECOND)
435 }
436
437 pub const fn from_microseconds(us: i64) -> Self {
439 let seconds = us / 1_000_000;
440 let remainder = us % 1_000_000;
441 Self::new(seconds, remainder * ATTOSECONDS_IN_MICROSECOND)
442 }
443
444 pub const fn from_nanoseconds(ns: i64) -> Self {
446 let seconds = ns / 1_000_000_000;
447 let remainder = ns % 1_000_000_000;
448 Self::new(seconds, remainder * ATTOSECONDS_IN_NANOSECOND)
449 }
450
451 pub const fn from_picoseconds(ps: i64) -> Self {
453 let seconds = ps / 1_000_000_000_000;
454 let remainder = ps % 1_000_000_000_000;
455 Self::new(seconds, remainder * ATTOSECONDS_IN_PICOSECOND)
456 }
457
458 pub const fn from_femtoseconds(fs: i64) -> Self {
460 let seconds = fs / 1_000_000_000_000_000;
461 let remainder = fs % 1_000_000_000_000_000;
462 Self::new(seconds, remainder * ATTOSECONDS_IN_FEMTOSECOND)
463 }
464
465 pub const fn from_attoseconds(atto: i64) -> Self {
467 let seconds = atto / ATTOSECONDS_IN_SECOND;
468 let remainder = atto % ATTOSECONDS_IN_SECOND;
469 Self::new(seconds, remainder)
470 }
471
472 pub const fn from_julian_years(value: f64) -> Self {
474 Self::from_seconds_f64(value * f64::consts::SECONDS_PER_JULIAN_YEAR)
475 }
476
477 pub const fn from_julian_centuries(value: f64) -> Self {
479 Self::from_seconds_f64(value * f64::consts::SECONDS_PER_JULIAN_CENTURY)
480 }
481
482 pub const fn from_seconds_and_subsecond(seconds: i64, subsecond: Subsecond) -> Self {
484 Self::new(seconds, subsecond.as_attoseconds())
485 }
486
487 pub const fn from_seconds_and_subsecond_f64(seconds: f64, subsecond: f64) -> Self {
489 Self::from_seconds_f64(subsecond).add_const(Self::from_seconds_f64(seconds))
490 }
491
492 pub const fn from_julian_date(julian_date: Days, epoch: Epoch) -> Self {
494 let seconds = julian_date * f64::consts::SECONDS_PER_DAY;
495 let seconds = match epoch {
496 Epoch::JulianDate => seconds - f64::consts::SECONDS_BETWEEN_JD_AND_J2000,
497 Epoch::ModifiedJulianDate => seconds - f64::consts::SECONDS_BETWEEN_MJD_AND_J2000,
498 Epoch::J1950 => seconds - f64::consts::SECONDS_BETWEEN_J1950_AND_J2000,
499 Epoch::J2000 => seconds,
500 };
501 Self::from_seconds_f64(seconds)
502 }
503
504 pub const fn from_two_part_julian_date(jd1: Days, jd2: Days) -> Self {
506 TimeDelta::from_seconds_f64(jd1 * f64::consts::SECONDS_PER_DAY)
507 .add_const(TimeDelta::from_seconds_f64(
508 jd2 * f64::consts::SECONDS_PER_DAY,
509 ))
510 .sub_const(TimeDelta::from_seconds(SECONDS_BETWEEN_JD_AND_J2000))
511 }
512
513 pub const fn as_seconds_and_subsecond(&self) -> Option<(i64, Subsecond)> {
515 match self {
516 TimeDelta::Valid {
517 seconds,
518 attoseconds,
519 } => Some((*seconds, Subsecond::from_attoseconds(*attoseconds))),
520 _ => None,
521 }
522 }
523
524 pub const fn to_seconds(&self) -> Seconds {
532 let (seconds, attoseconds) = match self {
533 TimeDelta::Valid {
534 seconds,
535 attoseconds,
536 } => (*seconds, *attoseconds),
537 TimeDelta::NaN => return Seconds::new(f64::NAN, f64::NAN),
538 TimeDelta::PosInf => return Seconds::new(f64::INFINITY, 0.0),
539 TimeDelta::NegInf => return Seconds::new(f64::NEG_INFINITY, 0.0),
540 };
541 Seconds::new(
542 seconds as f64,
543 attoseconds as f64 / ATTOSECONDS_IN_SECOND as f64,
544 )
545 }
546
547 pub const fn is_negative(&self) -> bool {
549 match self {
550 TimeDelta::Valid { seconds, .. } => *seconds < 0,
551 TimeDelta::NegInf => true,
552 _ => false,
553 }
554 }
555
556 pub const fn is_zero(&self) -> bool {
558 match &self {
559 TimeDelta::Valid {
560 seconds,
561 attoseconds,
562 } => *seconds == 0 && *attoseconds == 0,
563 _ => false,
564 }
565 }
566
567 pub const fn is_positive(&self) -> bool {
569 match self {
570 TimeDelta::Valid {
571 seconds,
572 attoseconds,
573 } => *seconds > 0 || *seconds == 0 && *attoseconds > 0,
574 TimeDelta::PosInf => true,
575 _ => false,
576 }
577 }
578
579 pub const fn is_finite(&self) -> bool {
581 matches!(self, Self::Valid { .. })
582 }
583
584 pub const fn is_nan(&self) -> bool {
586 matches!(self, Self::NaN)
587 }
588
589 pub const fn is_infinite(&self) -> bool {
591 matches!(self, Self::PosInf | Self::NegInf)
592 }
593
594 pub const fn seconds(&self) -> Option<i64> {
596 match self {
597 Self::Valid { seconds, .. } => Some(*seconds),
598 _ => None,
599 }
600 }
601
602 pub const fn subsecond(&self) -> Option<f64> {
604 match self.as_seconds_and_subsecond() {
605 Some((_, subsecond)) => Some(subsecond.as_seconds_f64()),
606 None => None,
607 }
608 }
609
610 pub const fn attoseconds(&self) -> Option<i64> {
612 match self {
613 Self::Valid { attoseconds, .. } => Some(*attoseconds),
614 _ => None,
615 }
616 }
617
618 const fn neg_const(self) -> Self {
619 let (seconds, attoseconds) = match self {
620 TimeDelta::Valid {
621 seconds,
622 attoseconds,
623 } => (seconds, attoseconds),
624 TimeDelta::NaN => return Self::NaN,
625 TimeDelta::PosInf => return Self::NegInf,
626 TimeDelta::NegInf => return Self::PosInf,
627 };
628 if attoseconds == 0 {
629 return Self::Valid {
630 seconds: -seconds,
631 attoseconds,
632 };
633 }
634
635 Self::Valid {
636 seconds: -seconds - 1,
637 attoseconds: ATTOSECONDS_IN_SECOND - attoseconds,
638 }
639 }
640
641 pub const fn add_const(self, rhs: Self) -> Self {
643 let (secs_lhs, attos_lhs, secs_rhs, attos_rhs) = match (self, rhs) {
644 (
645 TimeDelta::Valid {
646 seconds: secs_lhs,
647 attoseconds: attos_lhs,
648 },
649 TimeDelta::Valid {
650 seconds: secs_rhs,
651 attoseconds: attos_rhs,
652 },
653 ) => (secs_lhs, attos_lhs, secs_rhs, attos_rhs),
654 (TimeDelta::PosInf, TimeDelta::Valid { .. })
655 | (TimeDelta::Valid { .. }, TimeDelta::PosInf)
656 | (TimeDelta::PosInf, TimeDelta::PosInf) => return TimeDelta::PosInf,
657 (TimeDelta::NegInf, TimeDelta::Valid { .. })
658 | (TimeDelta::Valid { .. }, TimeDelta::NegInf)
659 | (TimeDelta::NegInf, TimeDelta::NegInf) => return TimeDelta::NegInf,
660 (TimeDelta::PosInf, TimeDelta::NegInf) | (TimeDelta::NegInf, TimeDelta::PosInf) => {
661 return TimeDelta::NaN;
662 }
663 (_, TimeDelta::NaN) | (TimeDelta::NaN, _) => return TimeDelta::NaN,
664 };
665
666 let seconds = secs_lhs + secs_rhs;
667 let attoseconds = attos_lhs + attos_rhs;
668 Self::new(seconds, attoseconds)
669 }
670
671 pub const fn sub_const(self, rhs: Self) -> Self {
673 let (secs_lhs, attos_lhs, secs_rhs, attos_rhs) = match (self, rhs) {
674 (
675 TimeDelta::Valid {
676 seconds: secs_lhs,
677 attoseconds: attos_lhs,
678 },
679 TimeDelta::Valid {
680 seconds: secs_rhs,
681 attoseconds: attos_rhs,
682 },
683 ) => (secs_lhs, attos_lhs, secs_rhs, attos_rhs),
684 (TimeDelta::PosInf, TimeDelta::Valid { .. }) => return TimeDelta::PosInf,
685 (TimeDelta::Valid { .. }, TimeDelta::PosInf) => return TimeDelta::NegInf,
686 (TimeDelta::NegInf, TimeDelta::Valid { .. }) => return TimeDelta::NegInf,
687 (TimeDelta::Valid { .. }, TimeDelta::NegInf) => return TimeDelta::PosInf,
688 (TimeDelta::PosInf, TimeDelta::PosInf) | (TimeDelta::NegInf, TimeDelta::NegInf) => {
689 return TimeDelta::NaN;
690 }
691 (TimeDelta::PosInf, TimeDelta::NegInf) => return TimeDelta::PosInf,
692 (TimeDelta::NegInf, TimeDelta::PosInf) => return TimeDelta::NegInf,
693 (_, TimeDelta::NaN) | (TimeDelta::NaN, _) => return TimeDelta::NaN,
694 };
695
696 let seconds = secs_lhs - secs_rhs;
697 let attoseconds = attos_lhs - attos_rhs;
698 Self::new(seconds, attoseconds)
699 }
700
701 pub const fn mul_const(self, rhs: f64) -> Self {
703 let (seconds, attoseconds) = match self {
704 TimeDelta::Valid {
705 seconds,
706 attoseconds,
707 } => (seconds, attoseconds),
708 TimeDelta::NaN => return TimeDelta::NaN,
709 TimeDelta::PosInf => {
710 return if rhs.is_nan() {
711 TimeDelta::NaN
712 } else if rhs > 0.0 {
713 TimeDelta::PosInf
714 } else if rhs < 0.0 {
715 TimeDelta::NegInf
716 } else {
717 TimeDelta::NaN
718 };
719 }
720 TimeDelta::NegInf => {
721 return if rhs.is_nan() {
722 TimeDelta::NaN
723 } else if rhs > 0.0 {
724 TimeDelta::NegInf
725 } else if rhs < 0.0 {
726 TimeDelta::PosInf
727 } else {
728 TimeDelta::NaN
729 };
730 }
731 };
732
733 if rhs.is_nan() {
734 return TimeDelta::NaN;
735 }
736 if !rhs.is_finite() {
737 return if rhs.is_sign_positive() {
738 TimeDelta::PosInf
739 } else {
740 TimeDelta::NegInf
741 };
742 }
743
744 let seconds_product = rhs * seconds as f64;
746
747 let attoseconds_product = rhs * attoseconds as f64 / ATTOSECONDS_IN_SECOND as f64;
750
751 TimeDelta::from_seconds_f64(attoseconds_product + seconds_product)
753 }
754}
755
756impl Default for TimeDelta {
757 fn default() -> Self {
758 Self::new(0, 0)
759 }
760}
761
762impl Ord for TimeDelta {
763 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
764 use std::cmp::Ordering;
765
766 match (self, other) {
767 (TimeDelta::NaN, TimeDelta::NaN) => Ordering::Equal,
770 (TimeDelta::NaN, _) => Ordering::Less,
771 (_, TimeDelta::NaN) => Ordering::Greater,
772
773 (TimeDelta::NegInf, TimeDelta::NegInf) => Ordering::Equal,
775 (TimeDelta::NegInf, _) => Ordering::Less,
776 (_, TimeDelta::NegInf) => Ordering::Greater,
777
778 (TimeDelta::PosInf, TimeDelta::PosInf) => Ordering::Equal,
779 (TimeDelta::PosInf, _) => Ordering::Greater,
780 (_, TimeDelta::PosInf) => Ordering::Less,
781
782 (
784 TimeDelta::Valid {
785 seconds: s1,
786 attoseconds: a1,
787 },
788 TimeDelta::Valid {
789 seconds: s2,
790 attoseconds: a2,
791 },
792 ) => s1.cmp(s2).then_with(|| a1.cmp(a2)),
793 }
794 }
795}
796
797impl PartialOrd for TimeDelta {
798 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
799 Some(self.cmp(other))
800 }
801}
802
803impl From<f64> for TimeDelta {
804 fn from(value: f64) -> Self {
805 Self::from_seconds_f64(value)
806 }
807}
808
809impl Display for TimeDelta {
810 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
811 write!(f, "{} s", self.to_seconds().to_f64())
812 }
813}
814
815impl JulianDate for TimeDelta {
816 fn julian_date(&self, epoch: Epoch, unit: Unit) -> f64 {
817 let tf = self.to_seconds();
818 let epoch_offset = match epoch {
819 Epoch::JulianDate => f64::consts::SECONDS_BETWEEN_JD_AND_J2000,
820 Epoch::ModifiedJulianDate => f64::consts::SECONDS_BETWEEN_MJD_AND_J2000,
821 Epoch::J1950 => f64::consts::SECONDS_BETWEEN_J1950_AND_J2000,
822 Epoch::J2000 => 0.0,
823 };
824 let adjusted = tf + Seconds::from_f64(epoch_offset);
825 let seconds = adjusted.to_f64();
826 match unit {
827 Unit::Seconds => seconds,
828 Unit::Days => seconds / f64::consts::SECONDS_PER_DAY,
829 Unit::Years => seconds / f64::consts::SECONDS_PER_JULIAN_YEAR,
830 Unit::Centuries => seconds / f64::consts::SECONDS_PER_JULIAN_CENTURY,
831 }
832 }
833}
834
835impl Neg for TimeDelta {
836 type Output = Self;
837
838 fn neg(self) -> Self::Output {
839 self.neg_const()
840 }
841}
842
843impl Add for TimeDelta {
844 type Output = Self;
845
846 fn add(self, rhs: Self) -> Self::Output {
847 self.add_const(rhs)
848 }
849}
850
851impl AddAssign for TimeDelta {
852 fn add_assign(&mut self, rhs: Self) {
853 *self = *self + rhs
854 }
855}
856
857impl Sub for TimeDelta {
858 type Output = Self;
859
860 fn sub(self, rhs: Self) -> Self::Output {
861 self.sub_const(rhs)
862 }
863}
864
865impl SubAssign for TimeDelta {
866 fn sub_assign(&mut self, rhs: Self) {
867 *self = *self - rhs
868 }
869}
870
871impl Mul<TimeDelta> for f64 {
872 type Output = TimeDelta;
873
874 fn mul(self, rhs: TimeDelta) -> Self::Output {
875 rhs.mul_const(self)
876 }
877}
878
879impl From<i64> for TimeDelta {
880 fn from(value: i64) -> Self {
881 TimeDelta::from_seconds(value)
882 }
883}
884
885impl From<i32> for TimeDelta {
886 fn from(value: i32) -> Self {
887 TimeDelta::from_seconds(value as i64)
888 }
889}
890
891impl ApproxEq for TimeDelta {
892 fn approx_eq(
893 &self,
894 rhs: &Self,
895 atol: f64,
896 rtol: f64,
897 ) -> lox_test_utils::approx_eq::ApproxEqResults {
898 self.to_seconds()
899 .to_f64()
900 .approx_eq(&rhs.to_seconds().to_f64(), atol, rtol)
901 }
902}
903
904#[derive(Copy, Clone, Debug, Default)]
906pub struct TimeDeltaBuilder {
907 seconds: i64,
908 subsecond: Subsecond,
909 negative: bool,
910}
911
912impl TimeDeltaBuilder {
913 pub const fn new() -> Self {
915 Self {
916 seconds: 0,
917 subsecond: Subsecond::new(),
918 negative: false,
919 }
920 }
921
922 pub const fn seconds(mut self, seconds: i64) -> Self {
924 self.seconds = seconds;
925 self
926 }
927
928 pub const fn negative(mut self) -> Self {
930 self.negative = true;
931 self
932 }
933
934 pub const fn milliseconds(mut self, milliseconds: u32) -> Self {
936 let extra_seconds = milliseconds / 1000;
937 let milliseconds = milliseconds % 1000;
938 self.seconds += extra_seconds as i64;
939 self.subsecond = self.subsecond.set_milliseconds(milliseconds);
940 self
941 }
942
943 pub const fn microseconds(mut self, microseconds: u32) -> Self {
945 let extra_milliseconds = microseconds / 1000;
946 let microseconds = microseconds % 1000;
947 let current_millis = self.subsecond.milliseconds();
948 self.subsecond = self
949 .subsecond
950 .set_milliseconds(current_millis + extra_milliseconds);
951 self.subsecond = self.subsecond.set_microseconds(microseconds);
952 self
953 }
954
955 pub const fn nanoseconds(mut self, nanoseconds: u32) -> Self {
957 let extra_microseconds = nanoseconds / 1000;
958 let nanoseconds = nanoseconds % 1000;
959 let current_micros = self.subsecond.microseconds();
960 self.subsecond = self
961 .subsecond
962 .set_microseconds(current_micros + extra_microseconds);
963 self.subsecond = self.subsecond.set_nanoseconds(nanoseconds);
964 self
965 }
966
967 pub const fn picoseconds(mut self, picoseconds: u32) -> Self {
969 let extra_nanoseconds = picoseconds / 1000;
970 let picoseconds = picoseconds % 1000;
971 let current_nanos = self.subsecond.nanoseconds();
972 self.subsecond = self
973 .subsecond
974 .set_nanoseconds(current_nanos + extra_nanoseconds);
975 self.subsecond = self.subsecond.set_picoseconds(picoseconds);
976 self
977 }
978
979 pub const fn femtoseconds(mut self, femtoseconds: u32) -> Self {
981 let extra_picoseconds = femtoseconds / 1000;
982 let femtoseconds = femtoseconds % 1000;
983 let current_picos = self.subsecond.picoseconds();
984 self.subsecond = self
985 .subsecond
986 .set_picoseconds(current_picos + extra_picoseconds);
987 self.subsecond = self.subsecond.set_femtoseconds(femtoseconds);
988 self
989 }
990
991 pub const fn attoseconds(mut self, attoseconds: u32) -> Self {
993 let extra_femtoseconds = attoseconds / 1000;
994 let attoseconds = attoseconds % 1000;
995 let current_femtos = self.subsecond.femtoseconds();
996 self.subsecond = self
997 .subsecond
998 .set_femtoseconds(current_femtos + extra_femtoseconds);
999 self.subsecond = self.subsecond.set_attoseconds(attoseconds);
1000 self
1001 }
1002
1003 pub const fn build(self) -> TimeDelta {
1020 let seconds = self.seconds;
1021 let attoseconds = self.subsecond.as_attoseconds();
1022
1023 let is_negative = self.negative || seconds < 0;
1025
1026 if is_negative {
1027 let abs_seconds = if seconds < 0 { -seconds } else { seconds };
1029 let magnitude = TimeDelta::new(abs_seconds, attoseconds);
1030 magnitude.neg_const()
1031 } else {
1032 TimeDelta::new(seconds, attoseconds)
1033 }
1034 }
1035}
1036
1037#[cfg(test)]
1038mod tests {
1039 use super::*;
1040 use crate::i64::consts::ATTOSECONDS_IN_SECOND;
1041
1042 #[test]
1043 fn test_new_normalizes_attoseconds() {
1044 let dt = TimeDelta::new(1, ATTOSECONDS_IN_SECOND + 500);
1046 assert_eq!(dt.seconds(), Some(2));
1047 assert_eq!(dt.attoseconds(), Some(500));
1048
1049 let dt = TimeDelta::new(1, -500);
1051 assert_eq!(dt.seconds(), Some(0));
1052 assert_eq!(dt.attoseconds(), Some(ATTOSECONDS_IN_SECOND - 500));
1053 }
1054
1055 #[test]
1056 fn test_from_seconds() {
1057 let dt = TimeDelta::from_seconds(60);
1058 assert_eq!(dt.seconds(), Some(60));
1059 assert_eq!(dt.attoseconds(), Some(0));
1060 }
1061
1062 #[test]
1063 fn test_from_seconds_f64_positive() {
1064 let dt = TimeDelta::from_seconds_f64(1.5);
1065 assert_eq!(dt.seconds(), Some(1));
1066 assert_eq!(dt.attoseconds(), Some(500_000_000_000_000_000));
1067 }
1068
1069 #[test]
1070 fn test_from_seconds_f64_negative() {
1071 let dt = TimeDelta::from_seconds_f64(-1.5);
1072 assert_eq!(dt.seconds(), Some(-2));
1073 assert_eq!(dt.attoseconds(), Some(500_000_000_000_000_000));
1074 }
1075
1076 #[test]
1077 fn test_from_seconds_f64_special_values() {
1078 assert!(matches!(
1079 TimeDelta::from_seconds_f64(f64::NAN),
1080 TimeDelta::NaN
1081 ));
1082 assert!(matches!(
1083 TimeDelta::from_seconds_f64(f64::INFINITY),
1084 TimeDelta::PosInf
1085 ));
1086 assert!(matches!(
1087 TimeDelta::from_seconds_f64(f64::NEG_INFINITY),
1088 TimeDelta::NegInf
1089 ));
1090 }
1091
1092 #[test]
1093 fn test_from_minutes() {
1094 let dt = TimeDelta::from_minutes_f64(1.0);
1095 assert_eq!(dt.seconds(), Some(60));
1096 }
1097
1098 #[test]
1099 fn test_from_hours() {
1100 let dt = TimeDelta::from_hours_f64(1.0);
1101 assert_eq!(dt.seconds(), Some(3600));
1102 }
1103
1104 #[test]
1105 fn test_from_days() {
1106 let dt = TimeDelta::from_days_f64(1.0);
1107 assert_eq!(dt.seconds(), Some(86400));
1108 }
1109
1110 #[test]
1111 fn test_is_positive() {
1112 assert!(TimeDelta::from_seconds(1).is_positive());
1113 assert!(!TimeDelta::from_seconds(-1).is_positive());
1114 assert!(!TimeDelta::from_seconds(0).is_positive());
1115 assert!(TimeDelta::new(0, 1).is_positive());
1116 assert!(TimeDelta::PosInf.is_positive());
1117 }
1118
1119 #[test]
1120 fn test_is_negative() {
1121 assert!(TimeDelta::from_seconds(-1).is_negative());
1122 assert!(!TimeDelta::from_seconds(1).is_negative());
1123 assert!(!TimeDelta::from_seconds(0).is_negative());
1124 assert!(TimeDelta::NegInf.is_negative());
1125 }
1126
1127 #[test]
1128 fn test_is_zero() {
1129 assert!(TimeDelta::from_seconds(0).is_zero());
1130 assert!(TimeDelta::ZERO.is_zero());
1131 assert!(!TimeDelta::from_seconds(1).is_zero());
1132 assert!(!TimeDelta::new(0, 1).is_zero());
1133 }
1134
1135 #[test]
1136 fn test_neg() {
1137 let dt = TimeDelta::new(1, 500_000_000_000_000_000);
1138 let neg = -dt;
1139 assert_eq!(neg.seconds(), Some(-2));
1140 assert_eq!(neg.attoseconds(), Some(500_000_000_000_000_000));
1141
1142 let dt = TimeDelta::from_seconds(1);
1144 let neg = -dt;
1145 assert_eq!(neg.seconds(), Some(-1));
1146 assert_eq!(neg.attoseconds(), Some(0));
1147
1148 assert!(matches!(-TimeDelta::PosInf, TimeDelta::NegInf));
1150 assert!(matches!(-TimeDelta::NegInf, TimeDelta::PosInf));
1151 assert!(matches!(-TimeDelta::NaN, TimeDelta::NaN));
1152 }
1153
1154 #[test]
1155 fn test_add_positive() {
1156 let a = TimeDelta::new(1, 600_000_000_000_000_000);
1157 let b = TimeDelta::new(1, 600_000_000_000_000_000);
1158 let sum = a + b;
1159 assert_eq!(sum.seconds(), Some(3));
1160 assert_eq!(sum.attoseconds(), Some(200_000_000_000_000_000));
1161 }
1162
1163 #[test]
1164 fn test_add_with_carry() {
1165 let a = TimeDelta::new(1, 700_000_000_000_000_000);
1166 let b = TimeDelta::new(0, 500_000_000_000_000_000);
1167 let sum = a + b;
1168 assert_eq!(sum.seconds(), Some(2));
1169 assert_eq!(sum.attoseconds(), Some(200_000_000_000_000_000));
1170 }
1171
1172 #[test]
1173 fn test_add_infinities() {
1174 assert!(matches!(
1175 TimeDelta::PosInf + TimeDelta::from_seconds(1),
1176 TimeDelta::PosInf
1177 ));
1178 assert!(matches!(
1179 TimeDelta::NegInf + TimeDelta::from_seconds(1),
1180 TimeDelta::NegInf
1181 ));
1182 assert!(matches!(
1183 TimeDelta::PosInf + TimeDelta::NegInf,
1184 TimeDelta::NaN
1185 ));
1186 }
1187
1188 #[test]
1189 fn test_sub_positive() {
1190 let a = TimeDelta::new(3, 200_000_000_000_000_000);
1191 let b = TimeDelta::new(1, 600_000_000_000_000_000);
1192 let diff = a - b;
1193 assert_eq!(diff.seconds(), Some(1));
1194 assert_eq!(diff.attoseconds(), Some(600_000_000_000_000_000));
1195 }
1196
1197 #[test]
1198 fn test_sub_with_borrow() {
1199 let a = TimeDelta::new(2, 200_000_000_000_000_000);
1200 let b = TimeDelta::new(1, 500_000_000_000_000_000);
1201 let diff = a - b;
1202 assert_eq!(diff.seconds(), Some(0));
1203 assert_eq!(diff.attoseconds(), Some(700_000_000_000_000_000));
1204 }
1205
1206 #[test]
1207 fn test_sub_to_negative() {
1208 let a = TimeDelta::from_seconds(1);
1209 let b = TimeDelta::from_seconds(2);
1210 let diff = a - b;
1211 assert_eq!(diff.seconds(), Some(-1));
1212 assert_eq!(diff.attoseconds(), Some(0));
1213 }
1214
1215 #[test]
1216 fn test_sub_infinities() {
1217 assert!(matches!(
1218 TimeDelta::PosInf - TimeDelta::from_seconds(1),
1219 TimeDelta::PosInf
1220 ));
1221 assert!(matches!(
1222 TimeDelta::from_seconds(1) - TimeDelta::PosInf,
1223 TimeDelta::NegInf
1224 ));
1225 assert!(matches!(
1226 TimeDelta::PosInf - TimeDelta::PosInf,
1227 TimeDelta::NaN
1228 ));
1229 }
1230
1231 #[test]
1232 fn test_ord_valid() {
1233 let a = TimeDelta::new(1, 500_000_000_000_000_000);
1234 let b = TimeDelta::new(2, 300_000_000_000_000_000);
1235 let c = TimeDelta::new(1, 500_000_000_000_000_000);
1236
1237 assert!(a < b);
1238 assert!(b > a);
1239 assert_eq!(a, c);
1240 assert!(a <= c);
1241 assert!(a >= c);
1242 }
1243
1244 #[test]
1245 fn test_ord_infinities() {
1246 let valid = TimeDelta::from_seconds(1);
1247
1248 assert!(TimeDelta::NegInf < valid);
1249 assert!(valid < TimeDelta::PosInf);
1250 assert!(TimeDelta::NegInf < TimeDelta::PosInf);
1251 assert!(TimeDelta::NaN < TimeDelta::NegInf);
1252 assert!(TimeDelta::NaN < valid);
1253 assert!(TimeDelta::NaN < TimeDelta::PosInf);
1254 }
1255
1256 #[test]
1257 fn test_builder() {
1258 let dt = TimeDelta::builder()
1259 .seconds(1)
1260 .milliseconds(500)
1261 .microseconds(250)
1262 .build();
1263
1264 assert_eq!(dt.seconds(), Some(1));
1265 assert_eq!(dt.attoseconds(), Some(500_250_000_000_000_000));
1266 }
1267
1268 #[test]
1269 fn test_builder_overflow() {
1270 let dt = TimeDelta::builder().seconds(0).milliseconds(1500).build();
1271
1272 assert_eq!(dt.seconds(), Some(1));
1273 assert_eq!(dt.attoseconds(), Some(500_000_000_000_000_000));
1274 }
1275
1276 #[test]
1277 fn test_to_seconds() {
1278 let dt = TimeDelta::new(1, 500_000_000_000_000_000);
1279 assert_eq!(dt.to_seconds().to_f64(), 1.5);
1280
1281 let dt = TimeDelta::new(-2, 500_000_000_000_000_000);
1282 assert_eq!(dt.to_seconds().to_f64(), -1.5);
1283 }
1284
1285 #[test]
1286 fn test_from_integer() {
1287 let dt: TimeDelta = 42i32.into();
1288 assert_eq!(dt.seconds(), Some(42));
1289
1290 let dt: TimeDelta = 42i64.into();
1291 assert_eq!(dt.seconds(), Some(42));
1292 }
1293
1294 #[test]
1295 fn test_add_assign() {
1296 let mut dt = TimeDelta::from_seconds(1);
1297 dt += TimeDelta::from_seconds(2);
1298 assert_eq!(dt.seconds(), Some(3));
1299 }
1300
1301 #[test]
1302 fn test_sub_assign() {
1303 let mut dt = TimeDelta::from_seconds(5);
1304 dt -= TimeDelta::from_seconds(2);
1305 assert_eq!(dt.seconds(), Some(3));
1306 }
1307
1308 #[test]
1309 fn test_time_delta_julian_date() {
1310 let dt = TimeDelta::builder()
1311 .seconds(-725803232)
1312 .milliseconds(184)
1313 .build();
1314 let exp = -725803232.184;
1315 let act = dt.julian_date(Epoch::J2000, Unit::Seconds);
1316 assert_eq!(act, exp);
1317 }
1318
1319 #[test]
1320 fn test_mul_precision() {
1321 let dt = TimeDelta::new(1000000, 123_456_789_012_345_678);
1323 let factor = 1e-10;
1324
1325 let result = factor * dt;
1326
1327 let result_f64 = result.to_seconds().to_f64();
1330 let expected = 0.0001000000123456789;
1331
1332 assert!((result_f64 - expected).abs() < 1e-17);
1334 }
1335
1336 #[test]
1337 fn test_mul_small_factors() {
1338 let dt = TimeDelta::new(788000833, 145_000_000_000_000_000);
1340 let lg = 6.969290134e-10; let result = lg * dt;
1343
1344 let result_seconds = result.to_seconds().to_f64();
1346
1347 assert!(result_seconds > 0.5 && result_seconds < 0.6);
1349 assert!(result.is_finite());
1350 }
1351
1352 #[test]
1353 fn test_mul_special_values() {
1354 let dt = TimeDelta::from_seconds(100);
1355
1356 let result = 0.0 * dt;
1358 assert!(result.is_zero());
1359
1360 let result = f64::NAN * dt;
1362 assert!(result.is_nan());
1363
1364 let result = f64::INFINITY * dt;
1366 assert_eq!(result, TimeDelta::PosInf);
1367
1368 let result = f64::NEG_INFINITY * dt;
1369 assert_eq!(result, TimeDelta::NegInf);
1370
1371 let result = -2.0 * TimeDelta::PosInf;
1373 assert_eq!(result, TimeDelta::NegInf);
1374
1375 let result = -2.0 * TimeDelta::NegInf;
1376 assert_eq!(result, TimeDelta::PosInf);
1377
1378 let result = 0.0 * TimeDelta::PosInf;
1380 assert!(result.is_nan());
1381 }
1382
1383 #[test]
1384 fn test_builder_negative_subsecond_only() {
1385 let dt = TimeDelta::builder()
1387 .microseconds(65)
1388 .nanoseconds(500)
1389 .negative()
1390 .build();
1391
1392 let expected = -65.5e-6;
1394 assert!(
1395 (dt.to_seconds().to_f64() - expected).abs() < 1e-15,
1396 "expected {} but got {}",
1397 expected,
1398 dt.to_seconds().to_f64()
1399 );
1400 assert!(dt.is_negative());
1401 }
1402
1403 #[test]
1404 fn test_builder_negative_with_seconds() {
1405 let dt = TimeDelta::builder()
1407 .seconds(1)
1408 .milliseconds(500)
1409 .negative()
1410 .build();
1411
1412 assert_eq!(dt.to_seconds().to_f64(), -1.5);
1413 assert!(dt.is_negative());
1414 }
1415
1416 #[test]
1417 fn test_builder_negative_seconds_without_flag() {
1418 let dt = TimeDelta::builder().seconds(-1).milliseconds(500).build();
1420
1421 assert_eq!(dt.to_seconds().to_f64(), -1.5);
1422 assert!(dt.is_negative());
1423 }
1424
1425 #[test]
1426 fn test_builder_negative_flag_with_negative_seconds() {
1427 let dt = TimeDelta::builder()
1429 .seconds(-1)
1430 .milliseconds(500)
1431 .negative()
1432 .build();
1433
1434 assert_eq!(dt.to_seconds().to_f64(), -1.5);
1435 assert!(dt.is_negative());
1436 }
1437
1438 #[test]
1439 fn test_seconds_precision() {
1440 let dt = TimeDelta::builder()
1442 .seconds(-725803167)
1443 .milliseconds(816)
1444 .build();
1445 let tf = dt.to_seconds();
1446
1447 assert_eq!(tf.hi, -725803168.0);
1451 assert!((tf.lo - 0.184).abs() < 1e-15);
1453
1454 assert!((tf.to_f64() - (-725803167.816)).abs() < 1e-9);
1456 }
1457
1458 #[test]
1459 fn test_seconds_arithmetic() {
1460 let a = Seconds::new(1e15, 0.5);
1461 let b = Seconds::new(1.0, 0.25);
1462
1463 let sum = a + b;
1465 assert_eq!(sum.to_f64(), 1e15 + 1.75);
1466
1467 let diff = a - b;
1469 assert_eq!(diff.to_f64(), 1e15 - 1.0 + 0.25);
1470
1471 let prod = a * 2.0;
1473 assert_eq!(prod.to_f64(), 2e15 + 1.0);
1474
1475 let neg = -a;
1477 assert_eq!(neg.hi, -1e15);
1478 assert_eq!(neg.lo, -0.5);
1479 }
1480
1481 #[test]
1482 fn test_time_units_f64() {
1483 assert_eq!(1.0.days(), TimeDelta::from_days_f64(1.0));
1484 assert_eq!(2.0.hours(), TimeDelta::from_hours_f64(2.0));
1485 assert_eq!(30.0.mins(), TimeDelta::from_minutes_f64(30.0));
1486 assert_eq!(60.0.secs(), TimeDelta::from_seconds_f64(60.0));
1487 assert_eq!(500.0.millis(), TimeDelta::from_seconds_f64(0.5));
1488 assert_eq!(1000.0.micros(), TimeDelta::from_seconds_f64(1e-3));
1489 assert_eq!(1000.0.nanos(), TimeDelta::from_seconds_f64(1e-6));
1490 assert_eq!(1000.0.picos(), TimeDelta::from_seconds_f64(1e-9));
1491 assert_eq!(1000.0.femtos(), TimeDelta::from_seconds_f64(1e-12));
1492 assert_eq!(1000.0.attos(), TimeDelta::from_seconds_f64(1e-15));
1493 }
1494
1495 #[test]
1496 fn test_time_units_i64() {
1497 assert_eq!(1_i64.days(), TimeDelta::from_days_f64(1.0));
1498 assert_eq!(2_i64.hours(), TimeDelta::from_hours_f64(2.0));
1499 assert_eq!(30_i64.mins(), TimeDelta::from_minutes_f64(30.0));
1500 assert_eq!(60_i64.secs(), TimeDelta::from_seconds(60));
1501 assert_eq!(500_i64.millis(), TimeDelta::from_milliseconds(500));
1502 assert_eq!(1000_i64.micros(), TimeDelta::from_microseconds(1000));
1503 assert_eq!(1000_i64.nanos(), TimeDelta::from_nanoseconds(1000));
1504 assert_eq!(1000_i64.picos(), TimeDelta::from_picoseconds(1000));
1505 assert_eq!(1000_i64.femtos(), TimeDelta::from_femtoseconds(1000));
1506 assert_eq!(1000_i64.attos(), TimeDelta::from_attoseconds(1000));
1507 }
1508
1509 #[test]
1510 fn test_from_milliseconds() {
1511 let dt = TimeDelta::from_milliseconds(1500);
1512 assert_eq!(dt.seconds(), Some(1));
1513 assert_eq!(dt.attoseconds(), Some(500_000_000_000_000_000));
1514
1515 let dt = TimeDelta::from_milliseconds(-1500);
1516 assert_eq!(dt.seconds(), Some(-2));
1517 assert_eq!(dt.attoseconds(), Some(500_000_000_000_000_000));
1518 }
1519
1520 #[test]
1521 fn test_from_microseconds() {
1522 let dt = TimeDelta::from_microseconds(1_000_000);
1523 assert_eq!(dt.seconds(), Some(1));
1524 assert_eq!(dt.attoseconds(), Some(0));
1525
1526 let dt = TimeDelta::from_microseconds(1_500_000);
1527 assert_eq!(dt.seconds(), Some(1));
1528 assert_eq!(dt.attoseconds(), Some(500_000_000_000_000_000));
1529 }
1530
1531 #[test]
1532 fn test_from_nanoseconds() {
1533 let dt = TimeDelta::from_nanoseconds(500_000_000);
1534 assert_eq!(dt.to_seconds().to_f64(), 0.5);
1535
1536 let dt = TimeDelta::from_nanoseconds(1_500_000_000);
1537 assert_eq!(dt.seconds(), Some(1));
1538 assert_eq!(dt.attoseconds(), Some(500_000_000_000_000_000));
1539 }
1540
1541 #[test]
1542 fn test_from_picoseconds() {
1543 let dt = TimeDelta::from_picoseconds(1_000_000_000_000);
1544 assert_eq!(dt.seconds(), Some(1));
1545 assert_eq!(dt.attoseconds(), Some(0));
1546 }
1547
1548 #[test]
1549 fn test_from_femtoseconds() {
1550 let dt = TimeDelta::from_femtoseconds(1_000_000_000_000_000);
1551 assert_eq!(dt.seconds(), Some(1));
1552 assert_eq!(dt.attoseconds(), Some(0));
1553 }
1554
1555 #[test]
1556 fn test_from_attoseconds() {
1557 let dt = TimeDelta::from_attoseconds(ATTOSECONDS_IN_SECOND);
1558 assert_eq!(dt.seconds(), Some(1));
1559 assert_eq!(dt.attoseconds(), Some(0));
1560
1561 let dt = TimeDelta::from_attoseconds(ATTOSECONDS_IN_SECOND + 42);
1562 assert_eq!(dt.seconds(), Some(1));
1563 assert_eq!(dt.attoseconds(), Some(42));
1564 }
1565}