mailang_stdlib/stdlib/
time.rs1use mailang_bytecode::Value;
4use std::time::{SystemTime, UNIX_EPOCH};
5
6pub fn builtin_time_now(_args: &[Value]) -> Result<Value, String> {
7 let duration = SystemTime::now()
8 .duration_since(UNIX_EPOCH)
9 .map_err(|e| e.to_string())?;
10 Ok(Value::Int(duration.as_millis() as i64))
11}
12
13pub fn builtin_time_now_secs(_args: &[Value]) -> Result<Value, String> {
14 let duration = SystemTime::now()
15 .duration_since(UNIX_EPOCH)
16 .map_err(|e| e.to_string())?;
17 Ok(Value::Int(duration.as_secs() as i64))
18}
19
20pub fn builtin_time_year(_args: &[Value]) -> Result<Value, String> {
21 let secs = get_epoch_secs()?;
22 let (year, _, _) = epoch_to_ymd(secs);
23 Ok(Value::Int(year))
24}
25
26pub fn builtin_time_month(_args: &[Value]) -> Result<Value, String> {
27 let secs = get_epoch_secs()?;
28 let (_, month, _) = epoch_to_ymd(secs);
29 Ok(Value::Int(month))
30}
31
32pub fn builtin_time_day(_args: &[Value]) -> Result<Value, String> {
33 let secs = get_epoch_secs()?;
34 let (_, _, day) = epoch_to_ymd(secs);
35 Ok(Value::Int(day))
36}
37
38pub fn builtin_time_hour(_args: &[Value]) -> Result<Value, String> {
39 let secs = get_epoch_secs()?;
40 let (_, h, _, _) = epoch_to_hms(secs);
41 Ok(Value::Int(h))
42}
43
44pub fn builtin_time_minute(_args: &[Value]) -> Result<Value, String> {
45 let secs = get_epoch_secs()?;
46 let (_, _, m, _) = epoch_to_hms(secs);
47 Ok(Value::Int(m))
48}
49
50pub fn builtin_time_second(_args: &[Value]) -> Result<Value, String> {
51 let secs = get_epoch_secs()?;
52 let (_, _, _, s) = epoch_to_hms(secs);
53 Ok(Value::Int(s))
54}
55
56pub fn builtin_time_date(_args: &[Value]) -> Result<Value, String> {
57 let secs = get_epoch_secs()?;
58 let (year, month, day) = epoch_to_ymd(secs);
59 Ok(Value::Str(
60 format!("{:04}-{:02}-{:02}", year, month, day).into(),
61 ))
62}
63
64pub fn builtin_time_datetime(_args: &[Value]) -> Result<Value, String> {
65 let secs = get_epoch_secs()?;
66 let (year, month, day) = epoch_to_ymd(secs);
67 let (_, hour, minute, second) = epoch_to_hms(secs);
68 Ok(Value::Str(
69 format!(
70 "{:04}-{:02}-{:02} {:02}:{:02}:{:02}",
71 year, month, day, hour, minute, second
72 )
73 .into(),
74 ))
75}
76
77pub fn builtin_time_elapsed(args: &[Value]) -> Result<Value, String> {
78 let start = match &args[0] {
79 Value::Int(n) => *n,
80 _ => return Err("elapsed expects an integer timestamp".to_string()),
81 };
82 let now = builtin_time_now(&[])?;
83 match now {
84 Value::Int(now_ms) => Ok(Value::Int(now_ms - start)),
85 _ => Err("Failed to get current time".to_string()),
86 }
87}
88
89pub fn builtin_time_sleep(args: &[Value]) -> Result<Value, String> {
90 let ms = match &args[0] {
91 Value::Int(n) => *n as u64,
92 Value::Float(n) => *n as u64,
93 _ => return Err("sleep expects a number".to_string()),
94 };
95 std::thread::sleep(std::time::Duration::from_millis(ms));
96 Ok(Value::Null)
97}
98
99fn get_epoch_secs() -> Result<i64, String> {
100 let duration = SystemTime::now()
101 .duration_since(UNIX_EPOCH)
102 .map_err(|e| e.to_string())?;
103 Ok(duration.as_secs() as i64)
104}
105
106fn epoch_to_ymd(epoch: i64) -> (i64, i64, i64) {
108 let days = epoch / 86400;
109 let mut y = 1970;
110 let mut remaining_days = days;
111
112 loop {
113 let days_in_year = if is_leap_year(y) { 366 } else { 365 };
114 if remaining_days < days_in_year {
115 break;
116 }
117 remaining_days -= days_in_year;
118 y += 1;
119 }
120
121 let leap = is_leap_year(y);
122 let month_days = [
123 31,
124 if leap { 29 } else { 28 },
125 31,
126 30,
127 31,
128 30,
129 31,
130 31,
131 30,
132 31,
133 30,
134 31,
135 ];
136 let mut m = 1;
137 for &days_in_month in &month_days {
138 if remaining_days < days_in_month {
139 break;
140 }
141 remaining_days -= days_in_month;
142 m += 1;
143 }
144
145 (y, m, remaining_days + 1)
146}
147
148fn epoch_to_hms(epoch: i64) -> (i64, i64, i64, i64) {
150 let secs_in_day = epoch % 86400;
151 let hour = secs_in_day / 3600;
152 let minute = (secs_in_day % 3600) / 60;
153 let second = secs_in_day % 60;
154 (0, hour, minute, second)
155}
156
157fn is_leap_year(year: i64) -> bool {
158 (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)
159}