Skip to main content

windjammer_runtime/
time.rs

1//! Date and time operations
2//!
3//! Windjammer's `std::time` module maps to these functions.
4
5use chrono::{DateTime, Local, Utc};
6use std::time::Instant as StdInstant;
7
8/// Re-export Duration type for use in Windjammer code
9pub use chrono::Duration;
10
11/// Instant wrapper for time measurements (re-exported for Windjammer)
12#[derive(Debug, Clone, Copy)]
13pub struct Instant {
14    inner: StdInstant,
15}
16
17impl Instant {
18    /// Get duration since another instant
19    pub fn duration_since(&self, earlier: &Instant) -> Duration {
20        let elapsed = self.inner.duration_since(earlier.inner);
21        Duration::from_std(elapsed).unwrap_or_else(|_| Duration::zero())
22    }
23}
24
25/// Get current instant for time measurements
26pub fn now() -> Instant {
27    Instant {
28        inner: StdInstant::now(),
29    }
30}
31
32/// Get current timestamp (seconds since epoch)
33pub fn timestamp() -> i64 {
34    Utc::now().timestamp()
35}
36
37/// Get current timestamp (milliseconds since epoch)
38pub fn now_millis() -> i64 {
39    Utc::now().timestamp_millis()
40}
41
42/// Get current date/time as string (ISO 8601)
43pub fn now_string() -> String {
44    Utc::now().to_rfc3339()
45}
46
47/// Get local date/time as string
48pub fn now_local() -> String {
49    Local::now().to_rfc3339()
50}
51
52/// Parse ISO 8601 date string  
53pub fn parse(s: &str) -> Result<i64, String> {
54    s.parse::<DateTime<Utc>>()
55        .map(|dt| dt.timestamp())
56        .map_err(|e| e.to_string())
57}
58
59/// Parse date string with custom format
60pub fn parse_format(s: &str, fmt: &str) -> Result<i64, String> {
61    DateTime::parse_from_str(s, fmt)
62        .map(|dt| dt.timestamp())
63        .map_err(|e| e.to_string())
64}
65
66/// Format timestamp as string
67pub fn format(timestamp: i64, format: &str) -> String {
68    DateTime::from_timestamp(timestamp, 0)
69        .unwrap_or_else(Utc::now)
70        .format(format)
71        .to_string()
72}
73
74/// Sleep for duration (seconds)
75pub fn sleep(secs: u64) {
76    std::thread::sleep(std::time::Duration::from_secs(secs));
77}
78
79/// Sleep for duration (milliseconds)
80pub fn sleep_millis(millis: u64) {
81    std::thread::sleep(std::time::Duration::from_millis(millis));
82}
83
84/// Add seconds to timestamp
85pub fn add_seconds(timestamp: i64, seconds: i64) -> i64 {
86    DateTime::from_timestamp(timestamp, 0)
87        .and_then(|dt| dt.checked_add_signed(Duration::seconds(seconds)))
88        .map(|dt| dt.timestamp())
89        .unwrap_or(timestamp)
90}
91
92/// Add days to timestamp
93pub fn add_days(timestamp: i64, days: i64) -> i64 {
94    DateTime::from_timestamp(timestamp, 0)
95        .and_then(|dt| dt.checked_add_signed(Duration::days(days)))
96        .map(|dt| dt.timestamp())
97        .unwrap_or(timestamp)
98}
99
100/// Calculate duration in seconds between two timestamps
101pub fn duration_secs(start: i64, end: i64) -> i64 {
102    end - start
103}
104
105/// Calculate duration in milliseconds between two timestamps
106pub fn duration_millis(start: i64, end: i64) -> i64 {
107    (end - start) * 1000
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113
114    #[test]
115    fn test_now() {
116        let ts = timestamp();
117        assert!(ts > 1_600_000_000); // After 2020
118    }
119
120    #[test]
121    fn test_now_string() {
122        let s = now_string();
123        assert!(s.contains('T')); // ISO 8601 format has T separator
124                                  // RFC3339 format may have +00:00 instead of Z
125        assert!(s.contains('Z') || s.contains('+'));
126    }
127
128    #[test]
129    fn test_parse() {
130        let result = parse("2024-01-01T00:00:00Z");
131        assert!(result.is_ok());
132    }
133
134    #[test]
135    fn test_add_seconds() {
136        let ts = 1_700_000_000i64;
137        let new_ts = add_seconds(ts, 3600);
138        assert_eq!(new_ts, ts + 3600);
139    }
140
141    #[test]
142    fn test_add_days() {
143        let ts = 1_700_000_000i64;
144        let new_ts = add_days(ts, 1);
145        assert_eq!(new_ts, ts + 86400);
146    }
147}