1use crate::{
2 AsciiStr, Dt, DtErr, GregorianTime, STRFTIME_SIZE, Scale, TSpan, tzdb::offset_info_at_utc,
3};
4
5impl Dt {
6 #[cfg(feature = "alloc")]
8 #[inline]
9 pub fn to_str(&self, fmt: &str) -> Result<alloc::string::String, DtErr> {
10 self.to_str_with_offset(fmt, 0)
11 }
12
13 #[cfg(feature = "alloc")]
15 #[inline]
16 pub fn to_str_with_offset(&self, fmt: &str, secs: i32) -> Result<alloc::string::String, DtErr> {
17 let mut buf = [0u8; STRFTIME_SIZE];
18 let n = self.to_u8_with_offset(fmt, &mut buf, secs)?;
19 Ok(alloc::string::String::from_utf8_lossy(&buf[0..n]).into_owned())
20 }
21
22 #[cfg(feature = "alloc")]
24 #[inline]
25 pub fn to_str_with_tz(&self, fmt: &str, tz_name: &str) -> Result<alloc::string::String, DtErr> {
26 let mut buf = [0u8; STRFTIME_SIZE];
27 let n = self.to_u8_with_tz(fmt, &mut buf, tz_name)?;
28 Ok(alloc::string::String::from_utf8_lossy(&buf[0..n]).into_owned())
29 }
30
31 pub fn to_str_bin(&self, fmt: &str) -> Result<AsciiStr<STRFTIME_SIZE>, DtErr> {
33 let mut gt = self.to_gregorian_time();
34 gt.set_offset(Some(0)).set_tz_abbrev(None);
35 let mut buf = [0u8; STRFTIME_SIZE];
36 let mut pos = 0usize;
37 gt.format_to_buffer(fmt.as_bytes(), &mut buf, &mut pos)?;
38 Ok(AsciiStr::from_filled_buffer(buf))
39 }
40
41 pub fn to_str_bin_with_offset(
43 &self,
44 fmt: &str,
45 secs: i32,
46 ) -> Result<AsciiStr<STRFTIME_SIZE>, DtErr> {
47 let gt = self.gregorian_time_with_offset(secs);
48 let mut buf = [0u8; STRFTIME_SIZE];
49 let mut pos = 0usize;
50 gt.format_to_buffer(fmt.as_bytes(), &mut buf, &mut pos)?;
51 Ok(AsciiStr::from_filled_buffer(buf))
52 }
53
54 pub fn to_str_bin_with_tz(
56 &self,
57 fmt: &str,
58 tz_name: &str,
59 ) -> Result<AsciiStr<STRFTIME_SIZE>, DtErr> {
60 let gt = self.gregorian_time_with_tz(tz_name);
61 let mut buf = [0u8; STRFTIME_SIZE];
62 let mut pos = 0usize;
63 gt.format_to_buffer(fmt.as_bytes(), &mut buf, &mut pos)?;
64 Ok(AsciiStr::from_filled_buffer(buf))
65 }
66
67 #[inline]
69 pub const fn sec_as_hhmm(seconds: i32) -> (bool, u8, u8) {
70 let total = seconds.abs();
71 let hours = (total / 3600) as u8;
72 let minutes = ((total % 3600) / 60) as u8;
73 (seconds < 0, hours, minutes)
74 }
75
76 pub fn to_u8_with_offset(&self, fmt: &str, dest: &mut [u8], secs: i32) -> Result<usize, DtErr> {
78 let gt = self.gregorian_time_with_offset(secs);
79 let mut internal_buf = [0u8; STRFTIME_SIZE];
80 let mut pos = 0usize;
81 gt.format_to_buffer(fmt.as_bytes(), &mut internal_buf, &mut pos)?;
82 let written = pos.min(dest.len());
83 if written > 0 {
84 dest[0..written].copy_from_slice(&internal_buf[0..written]);
85 }
86 Ok(written)
87 }
88
89 pub fn to_u8_with_tz(&self, fmt: &str, dest: &mut [u8], tz_name: &str) -> Result<usize, DtErr> {
91 let gt = self.gregorian_time_with_tz(tz_name);
92 let mut internal_buf = [0u8; STRFTIME_SIZE];
93 let mut pos = 0usize;
94 gt.format_to_buffer(fmt.as_bytes(), &mut internal_buf, &mut pos)?;
95 let written = pos.min(dest.len());
96 if written > 0 {
97 dest[0..written].copy_from_slice(&internal_buf[0..written]);
98 }
99 Ok(written)
100 }
101
102 pub(crate) fn gregorian_time_with_offset(&self, secs: i32) -> GregorianTime {
104 let local_tp = if secs != 0 {
105 *self + TSpan::new(secs as i64, 0)
106 } else {
107 *self
108 };
109 let mut gt = local_tp.to_gregorian_time();
110 gt.set_offset(Some(secs));
111 gt
112 }
113
114 pub(crate) fn gregorian_time_with_tz(&self, tz_name: &str) -> GregorianTime {
120 let utc_unix = self.to_epoch(Dt::UNIX_EPOCH, Scale::UTC).to_sec();
122
123 let (offset_secs, abbrev) = match offset_info_at_utc(tz_name, utc_unix) {
125 Some(info) => (info.offset, info.abbrev),
126 None => (0, "UTC"), };
128
129 let span = TSpan::new(offset_secs as i64, 0);
131 let local_tp = *self + span;
132
133 let mut gt = local_tp.to_gregorian_time();
134 gt.set_offset(Some(offset_secs));
135 gt.set_tz(Some(tz_name));
136 gt.set_tz_abbrev(Some(abbrev));
137 gt
138 }
139}