siglus_scene_vm/
platform_time.rs1pub use std::time::Duration;
8
9#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
10pub use web_time::Instant;
11
12#[cfg(all(
13 not(all(target_arch = "wasm32", target_os = "unknown")),
14 not(feature = "virtual-clock")
15))]
16pub use std::time::Instant;
17
18#[cfg(feature = "virtual-clock")]
19pub use virtual_clock::{Instant, advance_virtual_clock};
20
21#[cfg(feature = "virtual-clock")]
25mod virtual_clock {
26 use std::ops::{Add, AddAssign, Sub, SubAssign};
27 use std::sync::atomic::{AtomicU64, Ordering};
28 use std::time::Duration;
29
30 static NOW_NS: AtomicU64 = AtomicU64::new(86_400_000_000_000);
33
34 pub fn advance_virtual_clock(by: Duration) {
35 NOW_NS.fetch_add(by.as_nanos() as u64, Ordering::SeqCst);
36 }
37
38 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
39 pub struct Instant(u64);
40
41 impl Instant {
42 pub fn now() -> Self {
43 Self(NOW_NS.load(Ordering::SeqCst))
44 }
45
46 pub fn elapsed(&self) -> Duration {
47 Self::now().saturating_duration_since(*self)
48 }
49
50 pub fn duration_since(&self, earlier: Self) -> Duration {
51 self.saturating_duration_since(earlier)
52 }
53
54 pub fn saturating_duration_since(&self, earlier: Self) -> Duration {
55 Duration::from_nanos(self.0.saturating_sub(earlier.0))
56 }
57
58 pub fn checked_duration_since(&self, earlier: Self) -> Option<Duration> {
59 self.0.checked_sub(earlier.0).map(Duration::from_nanos)
60 }
61
62 pub fn checked_add(&self, d: Duration) -> Option<Self> {
63 self.0.checked_add(d.as_nanos() as u64).map(Self)
64 }
65
66 pub fn checked_sub(&self, d: Duration) -> Option<Self> {
67 self.0.checked_sub(d.as_nanos() as u64).map(Self)
68 }
69 }
70
71 impl Add<Duration> for Instant {
72 type Output = Self;
73 fn add(self, d: Duration) -> Self {
74 self.checked_add(d).expect("virtual instant overflow")
75 }
76 }
77
78 impl AddAssign<Duration> for Instant {
79 fn add_assign(&mut self, d: Duration) {
80 *self = *self + d;
81 }
82 }
83
84 impl Sub<Duration> for Instant {
85 type Output = Self;
86 fn sub(self, d: Duration) -> Self {
87 self.checked_sub(d).expect("virtual instant underflow")
88 }
89 }
90
91 impl SubAssign<Duration> for Instant {
92 fn sub_assign(&mut self, d: Duration) {
93 *self = *self - d;
94 }
95 }
96
97 impl Sub<Instant> for Instant {
98 type Output = Duration;
99 fn sub(self, other: Instant) -> Duration {
100 self.saturating_duration_since(other)
101 }
102 }
103}
104
105#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
106pub fn unix_time_millis() -> u128 {
107 let ms = js_sys::Date::now();
108 if ms.is_finite() && ms > 0.0 {
109 ms as u128
110 } else {
111 0
112 }
113}
114
115#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
116pub fn unix_time_millis() -> u128 {
117 std::time::SystemTime::now()
118 .duration_since(std::time::UNIX_EPOCH)
119 .unwrap_or_default()
120 .as_millis()
121}
122
123pub fn unix_time_secs() -> u64 {
124 (unix_time_millis() / 1000) as u64
125}
126
127#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
128pub struct LocalTimeFields {
129 pub year: i32,
130 pub month: u32,
131 pub day: u32,
132 pub weekday_sunday0: u32,
134 pub hour: u32,
135 pub minute: u32,
136 pub second: u32,
137 pub millisecond: u32,
138}
139
140#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
141pub fn local_time_fields() -> LocalTimeFields {
142 let now = js_sys::Date::new_0();
143 LocalTimeFields {
144 year: now.get_full_year() as i32,
145 month: now.get_month() + 1,
146 day: now.get_date(),
147 weekday_sunday0: now.get_day(),
148 hour: now.get_hours(),
149 minute: now.get_minutes(),
150 second: now.get_seconds(),
151 millisecond: now.get_milliseconds(),
152 }
153}
154
155#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
156pub fn local_time_fields() -> LocalTimeFields {
157 use chrono::{Datelike, Timelike};
158
159 let now = chrono::Local::now();
160 LocalTimeFields {
161 year: now.year(),
162 month: now.month(),
163 day: now.day(),
164 weekday_sunday0: now.weekday().num_days_from_sunday(),
165 hour: now.hour(),
166 minute: now.minute(),
167 second: now.second(),
168 millisecond: now.timestamp_subsec_millis(),
169 }
170}
171
172pub fn local_log_timestamp() -> String {
173 let t = local_time_fields();
174 format!(
175 "[{year:04}-{month:02}-{day:02} {hour:02}:{minute:02}:{second:02}]",
176 year = t.year,
177 month = t.month,
178 day = t.day,
179 hour = t.hour,
180 minute = t.minute,
181 second = t.second,
182 )
183}