1use crate::offset::Offset;
2use crate::util::constants::DAYS_TO_1970;
3use crate::{
4 errors::{invalid_format::create_invalid_format, AstrolabeError},
5 util::{
6 constants::{
7 DAYS_TO_1970_I64, NANOS_PER_DAY, NANOS_PER_SEC, SECS_PER_DAY_U64, SECS_PER_HOUR_U64,
8 SECS_PER_MINUTE_U64,
9 },
10 date::{
11 convert::{
12 date_to_days, days_to_date, days_to_doy, days_to_wday, months_between,
13 year_doy_to_days, years_between,
14 },
15 manipulate::{
16 add_days, add_months, add_years, set_day, set_day_of_year, set_month, set_year,
17 sub_days, sub_months, sub_years,
18 },
19 },
20 format::format_part,
21 offset::{add_offset_to_dn, remove_offset_from_dn},
22 parse::{
23 parse_format_string, parse_offset, parse_part, ParseUnit, ParsedDate, ParsedTime,
24 Period,
25 },
26 time::{
27 convert::{
28 days_nanos_to_hours, days_nanos_to_micros, days_nanos_to_millis,
29 days_nanos_to_minutes, days_nanos_to_nanos, days_nanos_to_seconds,
30 days_nanos_to_secs, nanos_to_days_nanos, nanos_to_subhour_nanos,
31 nanos_to_submicro_nanos, nanos_to_submilli_nanos, nanos_to_subminute_nanos,
32 nanos_to_subsecond, nanos_to_subsecond_nanos, nanos_to_time, secs_to_days_nanos,
33 since_i128, since_i64, time_to_day_seconds,
34 },
35 manipulate::{
36 add_hours, add_micros, add_millis, add_minutes, add_seconds,
37 clear_nanos_until_micro, clear_nanos_until_milli, clear_nanos_until_minute,
38 clear_nanos_until_nanos, clear_nanos_until_second, set_hour, set_micro, set_milli,
39 set_minute, set_nano, set_second, sub_hours, sub_micros, sub_millis, sub_minutes,
40 sub_seconds,
41 },
42 },
43 },
44 Date, DateUtilities, OffsetUtilities, Precision, Time, TimeUtilities,
45};
46use std::time::{SystemTime, UNIX_EPOCH};
47use std::{
48 cmp,
49 fmt::Display,
50 ops::{Add, AddAssign, Sub, SubAssign},
51 str::FromStr,
52 time::Duration,
53};
54
55#[derive(Debug, Default, Clone, Copy, Eq)]
64pub struct DateTime {
65 pub(crate) days: i32,
66 pub(crate) nanoseconds: u64,
67 pub(crate) offset: Offset,
68}
69
70impl DateTime {
71 pub fn now() -> Self {
79 let duration = SystemTime::now()
80 .duration_since(UNIX_EPOCH)
81 .expect("Time went backwards");
82
83 let days = duration.as_secs() / SECS_PER_DAY_U64 + DAYS_TO_1970;
84 let nanoseconds =
85 duration.as_secs() % SECS_PER_DAY_U64 * NANOS_PER_SEC + duration.subsec_nanos() as u64;
86
87 Self {
88 days: days as i32,
89 nanoseconds,
90 offset: Offset::default(),
91 }
92 }
93
94 pub fn now_local() -> Self {
103 Self::now().set_offset(Offset::Local)
104 }
105
106 pub fn from_ymdhms(
116 year: i32,
117 month: u32,
118 day: u32,
119 hour: u32,
120 minute: u32,
121 second: u32,
122 ) -> Result<Self, AstrolabeError> {
123 let days = date_to_days(year, month, day)?;
124 let seconds = time_to_day_seconds(hour, minute, second)? as u64;
125 Ok(Self {
126 days,
127 nanoseconds: seconds * NANOS_PER_SEC,
128 offset: Offset::default(),
129 })
130 }
131
132 pub fn as_ymdhms(&self) -> (i32, u32, u32, u32, u32, u32) {
146 let (year, month, day) = self.as_ymd();
147 let (hour, minute, second) = self.as_hms();
148 (year, month, day, hour, minute, second)
149 }
150
151 pub fn from_ymd(year: i32, month: u32, day: u32) -> Result<Self, AstrolabeError> {
161 let days = date_to_days(year, month, day)?;
162
163 Ok(Self {
164 days,
165 nanoseconds: 0,
166 offset: Offset::default(),
167 })
168 }
169
170 pub fn as_ymd(&self) -> (i32, u32, u32) {
181 days_to_date(self.days)
182 }
183
184 pub fn from_hms(hour: u32, minute: u32, second: u32) -> Result<Self, AstrolabeError> {
194 let seconds = time_to_day_seconds(hour, minute, second)? as u64;
195
196 Ok(Self {
197 days: 0,
198 nanoseconds: seconds * NANOS_PER_SEC,
199 offset: Offset::default(),
200 })
201 }
202
203 pub fn as_hms(&self) -> (u32, u32, u32) {
214 let seconds = self.nanoseconds / NANOS_PER_SEC;
215
216 let hour = seconds / 3600;
217 let minute = (seconds % 3600) / 60;
218 let second = seconds % 60;
219
220 (hour as u32, minute as u32, second as u32)
221 }
222
223 pub fn set_time(&self, time: Time) -> Self {
232 Self {
233 days: self.days,
234 nanoseconds: time.as_nanos(),
235 offset: self.offset,
236 }
237 }
238
239 pub fn parse_rfc3339(string: &str) -> Result<Self, AstrolabeError> {
247 if string.len() < 20 {
248 return Err(create_invalid_format(
249 "RFC 3339 string cannot be shorter than 20 chars".to_string(),
250 ));
251 }
252
253 let year = string[0..4].parse::<i32>().map_err(|_| {
254 create_invalid_format("Failed parsing year from RFC 3339 string".to_string())
255 })?;
256 let month = string[5..7].parse::<u32>().map_err(|_| {
257 create_invalid_format("Failed parsing month from RFC 3339 string".to_string())
258 })?;
259 let day = string[8..10].parse::<u32>().map_err(|_| {
260 create_invalid_format("Failed parsing day from RFC 3339 string".to_string())
261 })?;
262 let hour = string[11..13].parse::<u32>().map_err(|_| {
263 create_invalid_format("Failed parsing hour from RFC 3339 string".to_string())
264 })?;
265 let minute = string[14..16].parse::<u32>().map_err(|_| {
266 create_invalid_format("Failed parsing minute from RFC 3339 string".to_string())
267 })?;
268 let second = string[17..19].parse::<u32>().map_err(|_| {
269 create_invalid_format("Failed parsing second from RFC 3339 string".to_string())
270 })?;
271
272 let (nanos, offset) = if string.chars().nth(19).unwrap() == '.' {
273 let nanos_string = string[20..]
274 .chars()
275 .take_while(|&char| char != 'Z' && char != '+' && char != '-')
276 .collect::<String>();
277 let nanos = nanos_string.parse::<u64>().map_err(|_| {
278 create_invalid_format("Failed parsing subseconds from RFC 3339 string".to_string())
279 })? * (1000000000 / 10_u64.pow(nanos_string.len() as u32));
280
281 let offset_substring = string[20..]
282 .chars()
283 .position(|char| char == 'Z' || char == '+' || char == '-')
284 .ok_or_else(|| {
285 create_invalid_format("Failed parsing offset from RFC 3339 string".to_string())
286 })?;
287 let offset = parse_offset(&string[20 + offset_substring..])?;
288
289 (nanos, offset)
290 } else {
291 let offset = parse_offset(&string[19..])?;
292 (0, offset)
293 };
294
295 let days = date_to_days(year, month, day)?;
296 let seconds = time_to_day_seconds(hour, minute, second)? as u64;
297
298 Ok(Self {
299 days,
300 nanoseconds: seconds * NANOS_PER_SEC + nanos,
301 offset: Offset::default(),
302 }
303 .as_offset(Offset::Fixed(offset)))
304 }
305
306 pub fn format_rfc3339(&self, precision: Precision) -> String {
323 match precision {
324 Precision::Seconds => self.format("yyyy-MM-ddTHH:mm:ssXXX"),
325 Precision::Centis => self.format("yyyy-MM-ddTHH:mm:ss.nnXXX"),
326 Precision::Millis => self.format("yyyy-MM-ddTHH:mm:ss.nnnXXX"),
327 Precision::Micros => self.format("yyyy-MM-ddTHH:mm:ss.nnnnXXX"),
328 Precision::Nanos => self.format("yyyy-MM-ddTHH:mm:ss.nnnnnXXX"),
329 }
330 }
331
332 pub fn parse(string: &str, format: &str) -> Result<Self, AstrolabeError> {
342 let parts = parse_format_string(format);
343
344 let mut date = ParsedDate::default();
345 let mut time = ParsedTime::default();
346 let mut string = string.to_string();
347
348 for part in parts {
349 if part.starts_with('\u{0000}') {
351 string.replace_range(0..part.len(), "");
352 continue;
353 }
354
355 if part.starts_with('\'') {
357 string.replace_range(0..part.len() - if part.ends_with('\'') { 2 } else { 1 }, "");
358 continue;
359 }
360
361 let parsed_part = parse_part(&part, &mut string)?;
362 if let Some(parsed_part) = parsed_part {
363 match parsed_part.unit {
364 ParseUnit::Year => date.year = Some(parsed_part.value as i32),
365 ParseUnit::Month => date.month = Some(parsed_part.value as u32),
366 ParseUnit::DayOfMonth => date.day_of_month = Some(parsed_part.value as u32),
367 ParseUnit::DayOfYear => date.day_of_year = Some(parsed_part.value as u32),
368 ParseUnit::Hour => time.hour = Some(parsed_part.value as u64),
369 ParseUnit::PeriodHour => time.period_hour = Some(parsed_part.value as u64),
370 ParseUnit::Period => {
371 time.period = Some(if parsed_part.value == 0 {
372 Period::AM
373 } else {
374 Period::PM
375 })
376 }
377 ParseUnit::Minute => time.minute = Some(parsed_part.value as u64),
378 ParseUnit::Second => time.second = Some(parsed_part.value as u64),
379 ParseUnit::Decis => time.decis = Some(parsed_part.value as u64),
380 ParseUnit::Centis => time.centis = Some(parsed_part.value as u64),
381 ParseUnit::Millis => time.millis = Some(parsed_part.value as u64),
382 ParseUnit::Micros => time.micros = Some(parsed_part.value as u64),
383 ParseUnit::Nanos => time.nanos = Some(parsed_part.value as u64),
384 ParseUnit::Offset => time.offset = Some(parsed_part.value as i32),
385 };
386 };
387 }
388
389 let mut date_time = if date.day_of_year.is_some() {
391 let days = year_doy_to_days(date.year.unwrap_or(1), date.day_of_year.unwrap(), false)?;
392 Self {
393 days,
394 ..Default::default()
395 }
396 } else {
397 Self::from_ymd(
398 date.year.unwrap_or(1),
399 date.month.unwrap_or(1),
400 date.day_of_month.unwrap_or(1),
401 )?
402 };
403
404 let mut nanoseconds = 0;
405
406 if time.hour.is_some() {
407 nanoseconds += time.hour.unwrap_or(0) * SECS_PER_HOUR_U64 * NANOS_PER_SEC;
408 } else {
409 nanoseconds += (time.period_hour.unwrap_or(0)
410 + time.period.unwrap_or(Period::AM) as u64)
411 * SECS_PER_HOUR_U64
412 * NANOS_PER_SEC;
413 }
414 nanoseconds += time.minute.unwrap_or(0) * SECS_PER_MINUTE_U64 * NANOS_PER_SEC;
415 nanoseconds += time.second.unwrap_or(0) * NANOS_PER_SEC;
416 nanoseconds += time.decis.unwrap_or(0) * 100_000_000;
417 nanoseconds += time.centis.unwrap_or(0) * 10_000_000;
418 nanoseconds += time.millis.unwrap_or(0) * 1_000_000;
419 nanoseconds += time.micros.unwrap_or(0) * 1_000;
420 nanoseconds += time.nanos.unwrap_or(0);
421
422 date_time = date_time.set_time(Time::from_nanos(nanoseconds)?);
423
424 if let Some(offset) = time.offset {
425 date_time = date_time.as_offset(Offset::from_seconds(offset)?);
426 }
427
428 Ok(date_time)
429 }
430
431 pub fn format(&self, format: &str) -> String {
525 let offset_seconds = self.offset.resolve();
526 let parts = parse_format_string(format);
527 let (days, nanoseconds) = add_offset_to_dn(self.days, self.nanoseconds, offset_seconds);
528
529 parts
530 .iter()
531 .flat_map(|part| -> Vec<char> {
532 if part.starts_with('\u{0000}') {
534 return part.replace('\u{0000}', "'").chars().collect::<Vec<char>>();
535 }
536
537 if part.starts_with('\'') {
539 let part = part.replace('\u{0000}', "'");
540 return part[1..part.len() - usize::from(part.ends_with('\''))]
541 .chars()
542 .collect::<Vec<char>>();
543 }
544
545 format_part(part, days, nanoseconds, offset_seconds)
546 .chars()
547 .collect::<Vec<char>>()
548 })
549 .collect::<String>()
550 }
551
552 pub fn duration_between(&self, compare: &Self) -> Duration {
554 let lower = cmp::min(self, compare);
555 let upper = cmp::max(self, compare);
556
557 let mut days = upper.days as i64 - lower.days as i64;
558 let mut nanos = upper.nanoseconds as i64 - lower.nanoseconds as i64;
559 if lower.nanoseconds > upper.nanoseconds {
560 days -= 1;
561 nanos += NANOS_PER_DAY as i64;
562 };
563
564 let days_duration = Duration::from_secs(days.unsigned_abs() * SECS_PER_DAY_U64);
565 let nanos_duration = Duration::from_nanos(nanos.unsigned_abs());
566 days_duration + nanos_duration
567 }
568}
569
570impl DateUtilities for DateTime {
577 fn year(&self) -> i32 {
578 let days = add_offset_to_dn(self.days, self.nanoseconds, self.offset.resolve()).0;
579
580 days_to_date(days).0
581 }
582
583 fn month(&self) -> u32 {
584 let days = add_offset_to_dn(self.days, self.nanoseconds, self.offset.resolve()).0;
585
586 days_to_date(days).1
587 }
588
589 fn day(&self) -> u32 {
590 let days = add_offset_to_dn(self.days, self.nanoseconds, self.offset.resolve()).0;
591
592 days_to_date(days).2
593 }
594
595 fn day_of_year(&self) -> u32 {
596 let days = add_offset_to_dn(self.days, self.nanoseconds, self.offset.resolve()).0;
597
598 days_to_doy(days)
599 }
600
601 fn weekday(&self) -> u8 {
602 let days = add_offset_to_dn(self.days, self.nanoseconds, self.offset.resolve()).0;
603
604 days_to_wday(days, false) as u8
605 }
606
607 fn from_timestamp(timestamp: i64) -> Self {
608 let date_time = Self::from_seconds(timestamp + DAYS_TO_1970_I64 * SECS_PER_DAY_U64 as i64);
609 match date_time {
610 Ok(date_time) => date_time,
611 Err(e) => panic!("{}", e),
612 }
613 }
614
615 fn timestamp(&self) -> i64 {
616 self.as_seconds() - DAYS_TO_1970_I64 * SECS_PER_DAY_U64 as i64
617 }
618
619 fn set_year(&self, year: i32) -> Result<Self, AstrolabeError> {
620 let offset_seconds = self.offset.resolve();
621 let (days, nanoseconds) = add_offset_to_dn(self.days, self.nanoseconds, offset_seconds);
622
623 let new_days = set_year(days, year)?;
624
625 Ok(Self {
626 days: remove_offset_from_dn(new_days, nanoseconds, offset_seconds).0,
627 nanoseconds: self.nanoseconds,
628 offset: self.offset,
629 })
630 }
631
632 fn set_month(&self, month: u32) -> Result<Self, AstrolabeError> {
633 let offset_seconds = self.offset.resolve();
634 let (days, nanoseconds) = add_offset_to_dn(self.days, self.nanoseconds, offset_seconds);
635
636 let new_days = set_month(days, month)?;
637
638 Ok(Self {
639 days: remove_offset_from_dn(new_days, nanoseconds, offset_seconds).0,
640 nanoseconds: self.nanoseconds,
641 offset: self.offset,
642 })
643 }
644
645 fn set_day(&self, day: u32) -> Result<Self, AstrolabeError> {
646 let offset_seconds = self.offset.resolve();
647 let (days, nanoseconds) = add_offset_to_dn(self.days, self.nanoseconds, offset_seconds);
648
649 let new_days = set_day(days, day)?;
650
651 Ok(Self {
652 days: remove_offset_from_dn(new_days, nanoseconds, offset_seconds).0,
653 nanoseconds: self.nanoseconds,
654 offset: self.offset,
655 })
656 }
657
658 fn set_day_of_year(&self, day_of_year: u32) -> Result<Self, AstrolabeError> {
659 let offset_seconds = self.offset.resolve();
660 let (days, nanoseconds) = add_offset_to_dn(self.days, self.nanoseconds, offset_seconds);
661
662 let new_days = set_day_of_year(days, day_of_year)?;
663
664 Ok(Self {
665 days: remove_offset_from_dn(new_days, nanoseconds, offset_seconds).0,
666 nanoseconds: self.nanoseconds,
667 offset: self.offset,
668 })
669 }
670
671 fn add_years(&self, years: u32) -> Self {
672 let new_days = add_years(self.days, years);
673
674 let new_days = match new_days {
675 Ok(new_days) => new_days,
676 Err(e) => panic!("{}", e),
677 };
678
679 Self {
680 days: new_days,
681 nanoseconds: self.nanoseconds,
682 offset: self.offset,
683 }
684 }
685
686 fn add_months(&self, months: u32) -> Self {
687 let new_days = add_months(self.days, months);
688
689 let new_days = match new_days {
690 Ok(new_days) => new_days,
691 Err(e) => panic!("{}", e),
692 };
693
694 Self {
695 days: new_days,
696 nanoseconds: self.nanoseconds,
697 offset: self.offset,
698 }
699 }
700
701 fn add_days(&self, days: u32) -> Self {
702 let new_days = add_days(self.days, days);
703
704 let new_days = match new_days {
705 Ok(new_days) => new_days,
706 Err(e) => panic!("{}", e),
707 };
708
709 Self {
710 days: new_days,
711 nanoseconds: self.nanoseconds,
712 offset: self.offset,
713 }
714 }
715
716 fn sub_years(&self, years: u32) -> Self {
717 let new_days = sub_years(self.days, years);
718
719 let new_days = match new_days {
720 Ok(new_days) => new_days,
721 Err(e) => panic!("{}", e),
722 };
723
724 Self {
725 days: new_days,
726 nanoseconds: self.nanoseconds,
727 offset: self.offset,
728 }
729 }
730
731 fn sub_months(&self, months: u32) -> Self {
732 let new_days = sub_months(self.days, months);
733
734 let new_days = match new_days {
735 Ok(new_days) => new_days,
736 Err(e) => panic!("{}", e),
737 };
738
739 Self {
740 days: new_days,
741 nanoseconds: self.nanoseconds,
742 offset: self.offset,
743 }
744 }
745
746 fn sub_days(&self, days: u32) -> Self {
747 let new_days = sub_days(self.days, days);
748
749 let new_days = match new_days {
750 Ok(new_days) => new_days,
751 Err(e) => panic!("{}", e),
752 };
753
754 Self {
755 days: new_days,
756 nanoseconds: self.nanoseconds,
757 offset: self.offset,
758 }
759 }
760
761 fn clear_until_year(&self) -> Self {
762 Self {
763 offset: self.offset,
764 ..Default::default()
765 }
766 }
767
768 fn clear_until_month(&self) -> Self {
769 let year = days_to_date(self.days).0;
770 let new_days = date_to_days(year, 1, 1).unwrap();
771 Self {
772 days: new_days,
773 offset: self.offset,
774 ..Default::default()
775 }
776 }
777
778 fn clear_until_day(&self) -> Self {
779 let (year, month, _) = days_to_date(self.days);
780 let new_days = date_to_days(year, month, 1).unwrap();
781 Self {
782 days: new_days,
783 offset: self.offset,
784 ..Default::default()
785 }
786 }
787
788 fn years_since(&self, compare: &Self) -> i32 {
789 years_between(
790 self.days,
791 self.nanoseconds,
792 compare.days,
793 compare.nanoseconds,
794 )
795 }
796
797 fn months_since(&self, compare: &Self) -> i32 {
798 months_between(
799 self.days,
800 self.nanoseconds,
801 compare.days,
802 compare.nanoseconds,
803 )
804 }
805
806 fn days_since(&self, compare: &Self) -> i64 {
807 let extra_day = if self.days > compare.days && self.nanoseconds < compare.nanoseconds {
808 -1
809 } else if self.days < compare.days && self.nanoseconds > compare.nanoseconds {
810 1
811 } else {
812 0
813 };
814
815 self.days as i64 - compare.days as i64 + extra_day
816 }
817}
818
819impl TimeUtilities for DateTime {
826 fn hour(&self) -> u32 {
827 let nanoseconds = add_offset_to_dn(self.days, self.nanoseconds, self.offset.resolve()).1;
828
829 nanos_to_time(nanoseconds).0
830 }
831
832 fn minute(&self) -> u32 {
833 let nanoseconds = add_offset_to_dn(self.days, self.nanoseconds, self.offset.resolve()).1;
834
835 nanos_to_time(nanoseconds).1
836 }
837
838 fn second(&self) -> u32 {
839 let nanoseconds = add_offset_to_dn(self.days, self.nanoseconds, self.offset.resolve()).1;
840
841 nanos_to_time(nanoseconds).2
842 }
843
844 fn milli(&self) -> u32 {
845 let nanoseconds = add_offset_to_dn(self.days, self.nanoseconds, self.offset.resolve()).1;
846
847 nanos_to_subsecond(nanoseconds).0
848 }
849
850 fn micro(&self) -> u32 {
851 let nanoseconds = add_offset_to_dn(self.days, self.nanoseconds, self.offset.resolve()).1;
852
853 nanos_to_subsecond(nanoseconds).1
854 }
855
856 fn nano(&self) -> u32 {
857 let nanoseconds = add_offset_to_dn(self.days, self.nanoseconds, self.offset.resolve()).1;
858
859 nanos_to_subsecond(nanoseconds).2
860 }
861
862 fn set_hour(&self, hour: u32) -> Result<Self, AstrolabeError> {
863 let offset_seconds = self.offset.resolve();
864
865 let (days, nanos) = add_offset_to_dn(self.days, self.nanoseconds, offset_seconds);
866
867 let new_nanos = set_hour(nanos, hour)?;
868
869 let (new_days, new_nanos) = remove_offset_from_dn(days, new_nanos, offset_seconds);
870
871 Ok(Self {
872 days: new_days,
873 nanoseconds: new_nanos,
874 offset: self.offset,
875 })
876 }
877
878 fn set_minute(&self, minute: u32) -> Result<Self, AstrolabeError> {
879 let offset_seconds = self.offset.resolve();
880
881 let (days, nanos) = add_offset_to_dn(self.days, self.nanoseconds, offset_seconds);
882
883 let new_nanos = set_minute(nanos, minute)?;
884
885 let (new_days, new_nanos) = remove_offset_from_dn(days, new_nanos, offset_seconds);
886
887 Ok(Self {
888 days: new_days,
889 nanoseconds: new_nanos,
890 offset: self.offset,
891 })
892 }
893
894 fn set_second(&self, second: u32) -> Result<Self, AstrolabeError> {
895 let offset_seconds = self.offset.resolve();
896
897 let (days, nanos) = add_offset_to_dn(self.days, self.nanoseconds, offset_seconds);
898
899 let new_nanos = set_second(nanos, second)?;
900
901 let (new_days, new_nanos) = remove_offset_from_dn(days, new_nanos, offset_seconds);
902
903 Ok(Self {
904 days: new_days,
905 nanoseconds: new_nanos,
906 offset: self.offset,
907 })
908 }
909
910 fn set_milli(&self, milli: u32) -> Result<Self, AstrolabeError> {
911 let offset_seconds = self.offset.resolve();
912
913 let (days, nanos) = add_offset_to_dn(self.days, self.nanoseconds, offset_seconds);
914
915 let new_nanos = set_milli(nanos, milli)?;
916
917 let (new_days, new_nanos) = remove_offset_from_dn(days, new_nanos, offset_seconds);
918
919 Ok(Self {
920 days: new_days,
921 nanoseconds: new_nanos,
922 offset: self.offset,
923 })
924 }
925
926 fn set_micro(&self, micro: u32) -> Result<Self, AstrolabeError> {
927 let offset_seconds = self.offset.resolve();
928
929 let (days, nanos) = add_offset_to_dn(self.days, self.nanoseconds, offset_seconds);
930
931 let new_nanos = set_micro(nanos, micro)?;
932
933 let (new_days, new_nanos) = remove_offset_from_dn(days, new_nanos, offset_seconds);
934
935 Ok(Self {
936 days: new_days,
937 nanoseconds: new_nanos,
938 offset: self.offset,
939 })
940 }
941
942 fn set_nano(&self, nano: u32) -> Result<Self, AstrolabeError> {
943 let offset_seconds = self.offset.resolve();
944
945 let (days, nanos) = add_offset_to_dn(self.days, self.nanoseconds, offset_seconds);
946
947 let new_nanos = set_nano(nanos, nano)?;
948
949 let (new_days, new_nanos) = remove_offset_from_dn(days, new_nanos, offset_seconds);
950
951 Ok(Self {
952 days: new_days,
953 nanoseconds: new_nanos,
954 offset: self.offset,
955 })
956 }
957
958 fn add_hours(&self, hours: u32) -> Self {
960 let total_nanos =
961 self.days as i128 * NANOS_PER_DAY as i128 + add_hours(self.nanoseconds, hours) as i128;
962
963 let (days, nanoseconds) = nanos_to_days_nanos(total_nanos).unwrap_or_else(|_| {
964 panic!(
965 "Adding {} hours would result into an out of range datetime",
966 hours
967 )
968 });
969
970 Self {
971 days,
972 nanoseconds,
973 offset: self.offset,
974 }
975 }
976
977 fn add_minutes(&self, minutes: u32) -> Self {
979 let total_nanos = self.days as i128 * NANOS_PER_DAY as i128
980 + add_minutes(self.nanoseconds, minutes) as i128;
981
982 let (days, nanoseconds) = nanos_to_days_nanos(total_nanos).unwrap_or_else(|_| {
983 panic!(
984 "Adding {} minutes would result into an out of range datetime",
985 minutes
986 )
987 });
988
989 Self {
990 days,
991 nanoseconds,
992 offset: self.offset,
993 }
994 }
995
996 fn add_seconds(&self, seconds: u32) -> Self {
998 let total_nanos = self.days as i128 * NANOS_PER_DAY as i128
999 + add_seconds(self.nanoseconds, seconds) as i128;
1000
1001 let (days, nanoseconds) = nanos_to_days_nanos(total_nanos).unwrap_or_else(|_| {
1002 panic!(
1003 "Adding {} seconds would result into an out of range datetime",
1004 seconds
1005 )
1006 });
1007
1008 Self {
1009 days,
1010 nanoseconds,
1011 offset: self.offset,
1012 }
1013 }
1014
1015 fn add_millis(&self, millis: u32) -> Self {
1016 let total_nanos = self.days as i128 * NANOS_PER_DAY as i128
1017 + add_millis(self.nanoseconds, millis) as i128;
1018
1019 let (days, nanoseconds) = nanos_to_days_nanos(total_nanos).unwrap_or_else(|_| {
1020 panic!(
1021 "Adding {} milliseconds would result into an out of range datetime",
1022 millis
1023 )
1024 });
1025
1026 Self {
1027 days,
1028 nanoseconds,
1029 offset: self.offset,
1030 }
1031 }
1032
1033 fn add_micros(&self, micros: u32) -> Self {
1034 let total_nanos = self.days as i128 * NANOS_PER_DAY as i128
1035 + add_micros(self.nanoseconds, micros) as i128;
1036
1037 let (days, nanoseconds) = nanos_to_days_nanos(total_nanos).unwrap_or_else(|_| {
1038 panic!(
1039 "Adding {} microseconds would result into an out of range datetime",
1040 micros
1041 )
1042 });
1043
1044 Self {
1045 days,
1046 nanoseconds,
1047 offset: self.offset,
1048 }
1049 }
1050
1051 fn add_nanos(&self, nanos: u32) -> Self {
1052 let total_nanos =
1053 self.days as i128 * NANOS_PER_DAY as i128 + self.nanoseconds as i128 + nanos as i128;
1054
1055 let (days, nanoseconds) = nanos_to_days_nanos(total_nanos).unwrap_or_else(|_| {
1056 panic!(
1057 "Adding {} nanoseconds would result into an out of range datetime",
1058 nanos
1059 )
1060 });
1061
1062 Self {
1063 days,
1064 nanoseconds,
1065 offset: self.offset,
1066 }
1067 }
1068
1069 fn sub_hours(&self, hours: u32) -> Self {
1070 let total_nanos = self.days as i128 * NANOS_PER_DAY as i128
1071 + sub_hours(self.nanoseconds as i64, hours) as i128;
1072
1073 let (days, nanoseconds) = nanos_to_days_nanos(total_nanos).unwrap_or_else(|_| {
1074 panic!(
1075 "Subtracting {} hours would result into an out of range datetime",
1076 hours
1077 )
1078 });
1079
1080 Self {
1081 days,
1082 nanoseconds,
1083 offset: self.offset,
1084 }
1085 }
1086
1087 fn sub_minutes(&self, minutes: u32) -> Self {
1088 let total_nanos = self.days as i128 * NANOS_PER_DAY as i128
1089 + sub_minutes(self.nanoseconds as i64, minutes) as i128;
1090
1091 let (days, nanoseconds) = nanos_to_days_nanos(total_nanos).unwrap_or_else(|_| {
1092 panic!(
1093 "Subtracting {} minutes would result into an out of range datetime",
1094 minutes
1095 )
1096 });
1097
1098 Self {
1099 days,
1100 nanoseconds,
1101 offset: self.offset,
1102 }
1103 }
1104
1105 fn sub_seconds(&self, seconds: u32) -> Self {
1106 let total_nanos = self.days as i128 * NANOS_PER_DAY as i128
1107 + sub_seconds(self.nanoseconds as i64, seconds) as i128;
1108
1109 let (days, nanoseconds) = nanos_to_days_nanos(total_nanos).unwrap_or_else(|_| {
1110 panic!(
1111 "Subtracting {} seconds would result into an out of range datetime",
1112 seconds
1113 )
1114 });
1115
1116 Self {
1117 days,
1118 nanoseconds,
1119 offset: self.offset,
1120 }
1121 }
1122
1123 fn sub_millis(&self, millis: u32) -> Self {
1124 let total_nanos = self.days as i128 * NANOS_PER_DAY as i128
1125 + sub_millis(self.nanoseconds as i64, millis) as i128;
1126
1127 let (days, nanoseconds) = nanos_to_days_nanos(total_nanos).unwrap_or_else(|_| {
1128 panic!(
1129 "Subtracting {} milliseconds would result into an out of range datetime",
1130 millis
1131 )
1132 });
1133
1134 Self {
1135 days,
1136 nanoseconds,
1137 offset: self.offset,
1138 }
1139 }
1140
1141 fn sub_micros(&self, micros: u32) -> Self {
1142 let total_nanos = self.days as i128 * NANOS_PER_DAY as i128
1143 + sub_micros(self.nanoseconds as i64, micros) as i128;
1144
1145 let (days, nanoseconds) = nanos_to_days_nanos(total_nanos).unwrap_or_else(|_| {
1146 panic!(
1147 "Subtracting {} microseconds would result into an out of range datetime",
1148 micros
1149 )
1150 });
1151
1152 Self {
1153 days,
1154 nanoseconds,
1155 offset: self.offset,
1156 }
1157 }
1158
1159 fn sub_nanos(&self, nanos: u32) -> Self {
1160 let total_nanos =
1161 self.days as i128 * NANOS_PER_DAY as i128 + self.nanoseconds as i128 - nanos as i128;
1162
1163 let (days, nanoseconds) = nanos_to_days_nanos(total_nanos).unwrap_or_else(|_| {
1164 panic!(
1165 "Subtracting {} nanoseconds would result into an out of range datetime",
1166 nanos
1167 )
1168 });
1169
1170 Self {
1171 days,
1172 nanoseconds,
1173 offset: self.offset,
1174 }
1175 }
1176
1177 fn clear_until_hour(&self) -> Self {
1178 let offset_seconds = self.offset.resolve();
1179
1180 let (days, _) = add_offset_to_dn(self.days, self.nanoseconds, offset_seconds);
1181 let (days, nanos) = remove_offset_from_dn(days, 0, offset_seconds);
1182 Self {
1183 days,
1184 nanoseconds: nanos,
1185 offset: self.offset,
1186 }
1187 }
1188
1189 fn clear_until_minute(&self) -> Self {
1190 let offset_seconds = self.offset.resolve();
1191
1192 let (days, nanoseconds) = add_offset_to_dn(self.days, self.nanoseconds, offset_seconds);
1193 let (days, nanoseconds) =
1194 remove_offset_from_dn(days, clear_nanos_until_minute(nanoseconds), offset_seconds);
1195 Self {
1196 days,
1197 nanoseconds,
1198 offset: self.offset,
1199 }
1200 }
1201
1202 fn clear_until_second(&self) -> Self {
1203 let offset_seconds = self.offset.resolve();
1204
1205 let (days, nanoseconds) = add_offset_to_dn(self.days, self.nanoseconds, offset_seconds);
1206 let (days, nanoseconds) =
1207 remove_offset_from_dn(days, clear_nanos_until_second(nanoseconds), offset_seconds);
1208 Self {
1209 days,
1210 nanoseconds,
1211 offset: self.offset,
1212 }
1213 }
1214
1215 fn clear_until_milli(&self) -> Self {
1216 let offset_seconds = self.offset.resolve();
1217
1218 let (days, nanoseconds) = add_offset_to_dn(self.days, self.nanoseconds, offset_seconds);
1219 let (days, nanoseconds) =
1220 remove_offset_from_dn(days, clear_nanos_until_milli(nanoseconds), offset_seconds);
1221 Self {
1222 days,
1223 nanoseconds,
1224 offset: self.offset,
1225 }
1226 }
1227
1228 fn clear_until_micro(&self) -> Self {
1229 let offset_seconds = self.offset.resolve();
1230
1231 let (days, nanoseconds) = add_offset_to_dn(self.days, self.nanoseconds, offset_seconds);
1232 let (days, nanoseconds) =
1233 remove_offset_from_dn(days, clear_nanos_until_micro(nanoseconds), offset_seconds);
1234 Self {
1235 days,
1236 nanoseconds,
1237 offset: self.offset,
1238 }
1239 }
1240
1241 fn clear_until_nano(&self) -> Self {
1242 let offset_seconds = self.offset.resolve();
1243
1244 let (days, nanoseconds) = add_offset_to_dn(self.days, self.nanoseconds, offset_seconds);
1245 let (days, nanoseconds) =
1246 remove_offset_from_dn(days, clear_nanos_until_nanos(nanoseconds), offset_seconds);
1247 Self {
1248 days,
1249 nanoseconds,
1250 offset: self.offset,
1251 }
1252 }
1253
1254 type SubDayReturn = i64;
1255
1256 fn hours_since(&self, compare: &Self) -> Self::SubDayReturn {
1257 let self_total_hours = days_nanos_to_hours(self.days, self.nanoseconds);
1258 let self_subhour_nanos = nanos_to_subhour_nanos(self.nanoseconds);
1259
1260 let compare_total_hours = days_nanos_to_hours(compare.days, compare.nanoseconds);
1261 let compare_subhour_nanos = nanos_to_subhour_nanos(compare.nanoseconds);
1262
1263 since_i64(
1264 self_total_hours,
1265 self_subhour_nanos,
1266 compare_total_hours,
1267 compare_subhour_nanos,
1268 )
1269 }
1270
1271 fn minutes_since(&self, compare: &Self) -> Self::SubDayReturn {
1272 let self_total_minutes = days_nanos_to_minutes(self.days, self.nanoseconds);
1273 let self_subminute_nanos = nanos_to_subminute_nanos(self.nanoseconds);
1274
1275 let compare_total_minutes = days_nanos_to_minutes(compare.days, compare.nanoseconds);
1276 let compare_subminute_nanos = nanos_to_subminute_nanos(compare.nanoseconds);
1277
1278 since_i64(
1279 self_total_minutes,
1280 self_subminute_nanos,
1281 compare_total_minutes,
1282 compare_subminute_nanos,
1283 )
1284 }
1285
1286 fn seconds_since(&self, compare: &Self) -> Self::SubDayReturn {
1287 let self_total_seconds = days_nanos_to_seconds(self.days, self.nanoseconds);
1288 let self_subsecond_nanos = nanos_to_subsecond_nanos(self.nanoseconds);
1289
1290 let compare_total_seconds = days_nanos_to_seconds(compare.days, compare.nanoseconds);
1291 let compare_subsecond_nanos = nanos_to_subsecond_nanos(compare.nanoseconds);
1292
1293 since_i64(
1294 self_total_seconds,
1295 self_subsecond_nanos,
1296 compare_total_seconds,
1297 compare_subsecond_nanos,
1298 )
1299 }
1300
1301 type SubSecReturn = i128;
1302
1303 fn millis_since(&self, compare: &Self) -> Self::SubSecReturn {
1304 let self_total_millis = days_nanos_to_millis(self.days, self.nanoseconds);
1305 let self_submilli_nanos = nanos_to_submilli_nanos(self.nanoseconds);
1306
1307 let compare_total_millis = days_nanos_to_millis(compare.days, compare.nanoseconds);
1308 let compare_submilli_nanos = nanos_to_submilli_nanos(compare.nanoseconds);
1309
1310 since_i128(
1311 self_total_millis,
1312 self_submilli_nanos,
1313 compare_total_millis,
1314 compare_submilli_nanos,
1315 )
1316 }
1317
1318 fn micros_since(&self, compare: &Self) -> Self::SubSecReturn {
1319 let self_total_micros = days_nanos_to_micros(self.days, self.nanoseconds);
1320 let self_submicro_nanos = nanos_to_submicro_nanos(self.nanoseconds);
1321
1322 let compare_total_micros = days_nanos_to_micros(compare.days, compare.nanoseconds);
1323 let compare_submicro_nanos = nanos_to_submicro_nanos(compare.nanoseconds);
1324
1325 since_i128(
1326 self_total_micros,
1327 self_submicro_nanos,
1328 compare_total_micros,
1329 compare_submicro_nanos,
1330 )
1331 }
1332
1333 fn nanos_since(&self, compare: &Self) -> Self::SubSecReturn {
1334 let self_total_nanos = days_nanos_to_nanos(self.days, self.nanoseconds);
1335
1336 let compare_total_nanos = days_nanos_to_nanos(compare.days, compare.nanoseconds);
1337
1338 self_total_nanos - compare_total_nanos
1339 }
1340}
1341
1342impl OffsetUtilities for DateTime {
1349 fn set_offset(&self, offset: Offset) -> Self {
1350 let offset_seconds = offset.resolve();
1351
1352 let offset_days = (self.as_seconds() + offset_seconds as i64) / SECS_PER_DAY_U64 as i64;
1353 let offset_nanos = (self.nanoseconds / NANOS_PER_SEC) as i64 + offset_seconds as i64;
1354 if offset_days < i32::MIN as i64
1355 || offset_days > i32::MAX as i64
1356 || (offset_days == i32::MIN as i64 && offset_nanos.is_negative())
1357 {
1358 panic!("Offset would result in an out of range date");
1359 }
1360
1361 Self {
1362 days: self.days,
1363 nanoseconds: self.nanoseconds,
1364 offset,
1365 }
1366 }
1367
1368 fn as_offset(&self, offset: Offset) -> Self {
1369 let new_nanos = self.as_nanos() - offset.resolve() as i128 * NANOS_PER_SEC as i128;
1370 Self::from_nanos(new_nanos).set_offset(offset)
1371 }
1372
1373 fn get_offset(&self) -> Offset {
1374 self.offset
1375 }
1376}
1377
1378impl DateTime {
1385 pub(crate) fn from_seconds(seconds: i64) -> Result<Self, AstrolabeError> {
1387 let (days, nanoseconds) = secs_to_days_nanos(seconds)?;
1388
1389 Ok(Self {
1390 days,
1391 nanoseconds,
1392 offset: Offset::default(),
1393 })
1394 }
1395
1396 pub(crate) fn as_seconds(&self) -> i64 {
1398 days_nanos_to_secs(self.days, self.nanoseconds)
1399 }
1400
1401 pub(crate) fn from_nanos(nanos: i128) -> Self {
1403 let (days, nanoseconds) = nanos_to_days_nanos(nanos).unwrap();
1404
1405 Self {
1406 days,
1407 nanoseconds,
1408 offset: Offset::default(),
1409 }
1410 }
1411
1412 pub(crate) fn as_nanos(&self) -> i128 {
1414 days_nanos_to_nanos(self.days, self.nanoseconds)
1415 }
1416}
1417
1418impl From<&DateTime> for DateTime {
1425 fn from(date_time: &DateTime) -> Self {
1426 Self {
1427 days: date_time.days,
1428 nanoseconds: date_time.nanoseconds,
1429 offset: date_time.offset,
1430 }
1431 }
1432}
1433
1434impl From<Date> for DateTime {
1435 fn from(value: Date) -> Self {
1436 Self {
1437 days: value.days,
1438 nanoseconds: 0,
1439 offset: Offset::default(),
1440 }
1441 }
1442}
1443impl From<&Date> for DateTime {
1444 fn from(value: &Date) -> Self {
1445 Self {
1446 days: value.days,
1447 nanoseconds: 0,
1448 offset: Offset::default(),
1449 }
1450 }
1451}
1452
1453impl From<Time> for DateTime {
1454 fn from(value: Time) -> Self {
1455 Self {
1456 days: 0,
1457 nanoseconds: value.as_nanos(),
1458 offset: value.get_offset(),
1459 }
1460 }
1461}
1462impl From<&Time> for DateTime {
1463 fn from(time: &Time) -> Self {
1464 Self {
1465 days: 0,
1466 nanoseconds: time.as_nanos(),
1467 offset: time.get_offset(),
1468 }
1469 }
1470}
1471
1472impl Display for DateTime {
1473 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1474 write!(f, "{}", self.format("yyyy/MM/dd HH:mm:ss"))
1475 }
1476}
1477
1478impl PartialEq for DateTime {
1479 fn eq(&self, rhs: &Self) -> bool {
1480 self.as_nanos() == rhs.as_nanos()
1481 }
1482}
1483impl PartialOrd for DateTime {
1484 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
1485 Some(self.cmp(other))
1486 }
1487}
1488
1489impl Ord for DateTime {
1490 fn cmp(&self, other: &Self) -> cmp::Ordering {
1491 self.as_nanos().cmp(&other.as_nanos())
1492 }
1493}
1494
1495impl FromStr for DateTime {
1496 type Err = AstrolabeError;
1497
1498 fn from_str(s: &str) -> Result<Self, Self::Err> {
1499 Self::parse_rfc3339(s)
1500 }
1501}
1502
1503impl Add<Time> for DateTime {
1504 type Output = Self;
1505
1506 fn add(self, rhs: Time) -> Self::Output {
1507 let nanos = self.as_nanos() + rhs.as_nanos() as i128;
1508 Self {
1509 days: (nanos / NANOS_PER_DAY as i128) as i32,
1510 nanoseconds: (nanos % NANOS_PER_DAY as i128) as u64,
1511 offset: self.offset,
1512 }
1513 }
1514}
1515impl AddAssign<Time> for DateTime {
1516 fn add_assign(&mut self, rhs: Time) {
1517 *self = *self + rhs;
1518 }
1519}
1520
1521impl Sub<Time> for DateTime {
1522 type Output = Self;
1523
1524 fn sub(self, rhs: Time) -> Self::Output {
1525 let nanos = self.as_nanos() - rhs.as_nanos() as i128;
1526 Self {
1527 days: (nanos / NANOS_PER_DAY as i128) as i32,
1528 nanoseconds: (nanos % NANOS_PER_DAY as i128) as u64,
1529 offset: self.offset,
1530 }
1531 }
1532}
1533impl SubAssign<Time> for DateTime {
1534 fn sub_assign(&mut self, rhs: Time) {
1535 *self = *self - rhs;
1536 }
1537}
1538
1539impl Add<Duration> for DateTime {
1540 type Output = Self;
1541
1542 fn add(self, rhs: Duration) -> Self::Output {
1543 let nanos = self.as_nanos() + rhs.as_nanos() as i128;
1544 Self {
1545 days: (nanos / NANOS_PER_DAY as i128) as i32,
1546 nanoseconds: (nanos % NANOS_PER_DAY as i128) as u64,
1547 offset: self.offset,
1548 }
1549 }
1550}
1551impl AddAssign<Duration> for DateTime {
1552 fn add_assign(&mut self, rhs: Duration) {
1553 *self = *self + rhs;
1554 }
1555}
1556
1557impl Sub<Duration> for DateTime {
1558 type Output = Self;
1559
1560 fn sub(self, rhs: Duration) -> Self::Output {
1561 let nanos = self.as_nanos() - rhs.as_nanos() as i128;
1562 Self {
1563 days: (nanos / NANOS_PER_DAY as i128) as i32,
1564 nanoseconds: (nanos % NANOS_PER_DAY as i128) as u64,
1565 offset: self.offset,
1566 }
1567 }
1568}
1569impl SubAssign<Duration> for DateTime {
1570 fn sub_assign(&mut self, rhs: Duration) {
1571 *self = *self - rhs;
1572 }
1573}