deep_time/time_parts/
to_jiff.rs1use {
2 crate::{
3 ATTOS_PER_NS, Meridiem, Offset, TimeParts, Weekday, an_err,
4 error::{DtErr, DtErrKind},
5 },
6 alloc::string::String,
7 core::result::Result,
8 jiff::{
9 Timestamp, Zoned,
10 fmt::strtime::{BrokenDownTime, Meridiem as JiffMeridiem},
11 tz::Offset as JiffOffset,
12 },
13};
14
15impl TimeParts {
16 pub fn to_jiff_broken_down_time(&self) -> Result<BrokenDownTime, DtErr> {
18 let mut bdt = BrokenDownTime::default();
19
20 if let Some(year) = self.yr {
22 let y: i16 = year
23 .try_into()
24 .map_err(|e| an_err!(DtErrKind::InvalidInput, "year: {}: {}", year, e))?;
25 bdt.set_year(Some(y))
26 .map_err(|e| an_err!(DtErrKind::InvalidItem, "year: {}: {}", y, e))?;
27 }
28 if let Some(m) = self.mo {
29 bdt.set_month(Some(m as i8))
30 .map_err(|e| an_err!(DtErrKind::InvalidItem, "month: {}: {}", m, e))?;
31 }
32 if let Some(d) = self.day {
33 bdt.set_day(Some(d as i8))
34 .map_err(|e| an_err!(DtErrKind::InvalidItem, "day: {}: {}", d, e))?;
35 }
36
37 if let Some(doy) = self.day_of_yr {
39 bdt.set_day_of_year(Some(doy as i16))
40 .map_err(|e| an_err!(DtErrKind::InvalidItem, "doy: {}: {}", doy, e))?;
41 }
42 if let Some(y) = self.iso_wk_yr {
43 let y: i16 = y
44 .try_into()
45 .map_err(|e| an_err!(DtErrKind::InvalidInput, "iso wk yr: {}: {}", y, e))?;
46 bdt.set_iso_week_year(Some(y))
47 .map_err(|e| an_err!(DtErrKind::InvalidItem, "iso wk yr: {}: {}", y, e))?;
48 }
49 if let Some(w) = self.iso_wk {
50 bdt.set_iso_week(Some(w as i8))
51 .map_err(|e| an_err!(DtErrKind::InvalidItem, "iso wk: {}: {}", w, e))?;
52 }
53 if let Some(w) = self.wk_sun {
54 bdt.set_sunday_based_week(Some(w as i8))
55 .map_err(|e| an_err!(DtErrKind::InvalidItem, "sun based wk: {}: {}", w, e))?;
56 }
57 if let Some(w) = self.wk_mon {
58 bdt.set_monday_based_week(Some(w as i8))
59 .map_err(|e| an_err!(DtErrKind::InvalidItem, "mon based wk: {}: {}", w, e))?;
60 }
61
62 if let Some(h) = self.hr {
64 bdt.set_hour(Some(h as i8))
65 .map_err(|e| an_err!(DtErrKind::InvalidItem, "hour: {}: {}", h, e))?;
66 }
67 if let Some(m) = self.min {
68 bdt.set_minute(Some(m as i8))
69 .map_err(|e| an_err!(DtErrKind::InvalidItem, "minute: {}: {}", m, e))?;
70 }
71 if let Some(s) = self.sec {
72 let non_ls_s = if s == 60 { 59 } else { s };
73 bdt.set_second(Some(non_ls_s as i8))
74 .map_err(|e| an_err!(DtErrKind::InvalidItem, "second: {}: {}", non_ls_s, e))?;
75 }
76
77 if let Some(attos) = self.attos {
79 let ns_u64 = attos / ATTOS_PER_NS;
80 let ns: i32 = if ns_u64 >= 1_000_000_000 {
81 999_999_999
82 } else {
83 ns_u64 as i32
84 };
85 bdt.set_subsec_nanosecond(Some(ns))
86 .map_err(|e| an_err!(DtErrKind::InvalidItem, "ns: {}: {}", ns, e))?;
87 }
88
89 if let Some(wd) = self.wkday {
91 let jwd = match wd {
92 Weekday::Sunday => jiff::civil::Weekday::Sunday,
93 Weekday::Monday => jiff::civil::Weekday::Monday,
94 Weekday::Tuesday => jiff::civil::Weekday::Tuesday,
95 Weekday::Wednesday => jiff::civil::Weekday::Wednesday,
96 Weekday::Thursday => jiff::civil::Weekday::Thursday,
97 Weekday::Friday => jiff::civil::Weekday::Friday,
98 Weekday::Saturday => jiff::civil::Weekday::Saturday,
99 };
100 bdt.set_weekday(Some(jwd));
101 }
102 if let Some(mer) = self.meridiem {
103 let jmer = match mer {
104 Meridiem::AM => JiffMeridiem::AM,
105 Meridiem::PM => JiffMeridiem::PM,
106 };
107 bdt.set_meridiem(Some(jmer));
108 }
109
110 if let Some(secs) = self.unix_timestamp_seconds {
112 let ts = Timestamp::from_second(secs)
113 .map_err(|e| an_err!(DtErrKind::InvalidInput, "timestamp: {}: {}", secs, e))?;
114 bdt.set_timestamp(Some(ts));
115 }
116
117 if let Some(name) = &self.iana_name {
119 match name.as_str() {
120 Ok(s) if !s.is_empty() => bdt.set_iana_time_zone(Some(String::from(s))),
121 Ok(_) => {} Err(e) => {
123 return Err(an_err!(
124 DtErrKind::InvalidBytes,
125 "invalid iana ascii: {:?}: {}",
126 name,
127 e
128 ));
129 }
130 }
131 } else if let Some(Offset::Fixed(secs)) = self.offset {
132 if let Ok(jiff_offset) = JiffOffset::from_seconds(secs) {
133 bdt.set_offset(Some(jiff_offset));
134 } else {
135 return Err(an_err!(
136 DtErrKind::InvalidTimezoneOffset,
137 "offset secs: {}",
138 secs
139 ));
140 }
141 } else {
142 bdt.set_offset(Some(JiffOffset::UTC));
144 }
145
146 Ok(bdt)
147 }
148
149 pub fn to_jiff_zoned(&self) -> Result<Zoned, DtErr> {
151 let bdt = self.to_jiff_broken_down_time()?;
152 if let Ok(zoned) = bdt.to_zoned() {
153 return Ok(zoned);
154 }
155 if let Ok(ts) = bdt.to_timestamp()
156 && let Ok(zoned) = ts.in_tz("UTC")
157 {
158 return Ok(zoned);
159 }
160 if let Ok(dt) = bdt.to_datetime()
161 && let Ok(zoned) = dt.in_tz("UTC")
162 {
163 return Ok(zoned);
164 }
165 if let Ok(date) = bdt.to_date()
166 && let Ok(dt) = date.at(0, 0, 0, 0).in_tz("UTC")
167 {
168 return Ok(dt);
169 }
170
171 Err(an_err!(
172 DtErrKind::InvalidInput,
173 "could not convert to jiff zoned"
174 ))
175 }
176
177 #[inline]
179 pub fn to_jiff_timestamp(&self) -> Result<Timestamp, DtErr> {
180 self.to_jiff_zoned().map(|z| z.timestamp())
181 }
182}