1pub use std::time::SystemTime as Time;
4pub use time::UtcDateTime;
5
6#[cfg(not(feature = "web"))]
7pub use std::time::{Duration, Instant};
8#[cfg(feature = "web")]
9pub use web_time::{Duration, Instant};
10
11pub fn utc_now() -> UtcDateTime {
13 now().into()
14}
15
16#[derive(Debug, Clone, Copy, Eq, PartialEq)]
18pub struct LocalDatetime {
19 pub datetime: time::PrimitiveDateTime,
21 pub local_offset_minutes: Option<i32>,
26}
27
28impl LocalDatetime {
29 pub fn from_ymd_hms(
31 year: i32,
32 month: u8,
33 day: u8,
34 hour: u8,
35 minute: u8,
36 second: u8,
37 local_offset_minutes: Option<i32>,
38 ) -> Option<Self> {
39 let date =
40 time::Date::from_calendar_date(year, time::Month::try_from(month).ok()?, day).ok()?;
41 let time = time::Time::from_hms(hour, minute, second).ok()?;
42 Some(Self {
43 datetime: time::PrimitiveDateTime::new(date, time),
44 local_offset_minutes,
45 })
46 }
47}
48
49#[cfg(any(feature = "system", feature = "web"))]
54pub fn local_now() -> Option<LocalDatetime> {
55 use chrono::{Datelike, Timelike};
56
57 let now: chrono::DateTime<chrono::Local> = now().into();
58 LocalDatetime::from_ymd_hms(
59 now.year(),
60 now.month().try_into().ok()?,
61 now.day().try_into().ok()?,
62 now.hour().try_into().ok()?,
63 now.minute().try_into().ok()?,
64 now.second().try_into().ok()?,
65 Some(now.offset().local_minus_utc() / 60),
66 )
67}
68
69#[cfg(not(any(feature = "system", feature = "web")))]
71pub fn local_now() -> Option<LocalDatetime> {
72 let now = utc_now();
73 Some(LocalDatetime {
74 datetime: time::PrimitiveDateTime::new(now.date(), now.time()),
75 local_offset_minutes: None,
76 })
77}
78
79#[cfg(any(feature = "system", feature = "web"))]
81pub fn now() -> Time {
82 #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
83 {
84 Time::now()
85 }
86 #[cfg(all(target_family = "wasm", target_os = "unknown"))]
87 {
88 use web_time::web::SystemTimeExt;
89 web_time::SystemTime::now().to_std()
90 }
91}
92
93#[cfg(not(any(feature = "system", feature = "web")))]
95pub fn now() -> Time {
96 Time::UNIX_EPOCH
97}
98
99pub use time::format_description::well_known::Rfc3339;
100
101pub trait ToUtcDateTime {
103 fn to_utc_datetime(self) -> Option<UtcDateTime>;
105}
106
107impl ToUtcDateTime for i64 {
108 fn to_utc_datetime(self) -> Option<UtcDateTime> {
110 UtcDateTime::from_unix_timestamp(self).ok()
111 }
112}
113
114impl ToUtcDateTime for Time {
115 fn to_utc_datetime(self) -> Option<UtcDateTime> {
117 Some(UtcDateTime::from(self))
118 }
119}
120
121#[cfg(feature = "typst")]
123pub fn to_typst_time(timestamp: UtcDateTime) -> typst::foundations::Datetime {
124 let datetime = ::time::PrimitiveDateTime::new(timestamp.date(), timestamp.time());
125 typst::foundations::Datetime::Datetime(datetime)
126}
127
128pub fn yyyy_mm_dd() -> Vec<::time::format_description::BorrowedFormatItem<'static>> {
130 ::time::format_description::parse_borrowed::<2>("[year]-[month]-[day]").unwrap()
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136
137 #[cfg(not(any(feature = "system", feature = "web")))]
138 #[test]
139 fn local_now_uses_utc_epoch_fallback() {
140 assert_eq!(
141 local_now(),
142 LocalDatetime::from_ymd_hms(1970, 1, 1, 0, 0, 0, None)
143 );
144 }
145
146 #[test]
147 fn test_yyyy_mm_dd() {
148 let format = yyyy_mm_dd();
149 assert!(!format.is_empty(), "format should not be empty");
150 }
151}