Add DateTime type and operations
This commit introduces the `DateTime` type to the language, enabling
users to work with dates and times. It includes:
- A new `DateTime` variant in the `Value` and `StaticType` enums.
- A `date` function for parsing date strings into `DateTime` values.
- Overloads for `+` and `-` operators to support `DateTime` arithmetic.
- Comparison operators (`>`, `<`) for `DateTime` values.
- Corresponding unit tests for `DateTime` operations.
- Updates to the `gemini.md` documentation to reflect the new
functionality.
Add DateTime type and operations
Introduce a new `DateTime` type to the language, allowing for date and
time manipulation. This includes:
* Parsing dates and datetimes from strings.
* Performing arithmetic operations (addition and subtraction) between
`DateTime` and `Int` (representing milliseconds) and between two
`DateTime` values (resulting in an `Int` duration).
* Enabling comparison operations (`>`, `<`) between `DateTime` values.
This commit is contained in:
+29
-1
@@ -89,11 +89,31 @@ impl Environment {
|
||||
|
||||
fn register_stdlib(&self) {
|
||||
use crate::ast::types::Signature;
|
||||
use chrono::{NaiveDate, NaiveDateTime};
|
||||
|
||||
self.register_native("date", StaticType::Function(Box::new(Signature {
|
||||
params: vec![StaticType::Text],
|
||||
ret: StaticType::DateTime
|
||||
})), |args| {
|
||||
if let Value::Text(s) = &args[0] {
|
||||
// Try parse YYYY-MM-DD
|
||||
if let Ok(dt) = NaiveDate::parse_from_str(s, "%Y-%m-%d") {
|
||||
let ts = dt.and_hms_opt(0, 0, 0).unwrap().and_utc().timestamp_millis();
|
||||
return Value::DateTime(ts);
|
||||
}
|
||||
// Try parse YYYY-MM-DD HH:MM:SS
|
||||
if let Ok(dt) = NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S") {
|
||||
return Value::DateTime(dt.and_utc().timestamp_millis());
|
||||
}
|
||||
}
|
||||
Value::Void
|
||||
});
|
||||
|
||||
let plus_ty = StaticType::FunctionOverloads(vec![
|
||||
Signature { params: vec![StaticType::Int, StaticType::Int], ret: StaticType::Int },
|
||||
Signature { params: vec![StaticType::Float, StaticType::Float], ret: StaticType::Float },
|
||||
Signature { params: vec![StaticType::Text, StaticType::Text], ret: StaticType::Text },
|
||||
Signature { params: vec![StaticType::DateTime, StaticType::Int], ret: StaticType::DateTime },
|
||||
]);
|
||||
self.register_native("+", plus_ty, |args| {
|
||||
if args.len() == 2 {
|
||||
@@ -106,7 +126,8 @@ impl Environment {
|
||||
let mut res = a.to_string();
|
||||
res.push_str(b);
|
||||
Value::Text(Rc::from(res))
|
||||
}
|
||||
},
|
||||
(Value::DateTime(ts), Value::Int(ms)) => Value::DateTime(ts + ms),
|
||||
_ => Value::Void,
|
||||
}
|
||||
} else {
|
||||
@@ -124,6 +145,8 @@ impl Environment {
|
||||
Signature { params: vec![StaticType::Float, StaticType::Float], ret: StaticType::Float },
|
||||
Signature { params: vec![StaticType::Int], ret: StaticType::Int },
|
||||
Signature { params: vec![StaticType::Float], ret: StaticType::Float },
|
||||
Signature { params: vec![StaticType::DateTime, StaticType::DateTime], ret: StaticType::Int },
|
||||
Signature { params: vec![StaticType::DateTime, StaticType::Int], ret: StaticType::DateTime },
|
||||
]);
|
||||
self.register_native("-", minus_ty, |args| {
|
||||
if args.is_empty() { return Value::Void; }
|
||||
@@ -140,6 +163,8 @@ impl Environment {
|
||||
(Value::Float(a), Value::Float(b)) => Value::Float(a - b),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Float(*a as f64 - b),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Float(a - *b as f64),
|
||||
(Value::DateTime(a), Value::DateTime(b)) => Value::Int(a - b),
|
||||
(Value::DateTime(a), Value::Int(b)) => Value::DateTime(a - b),
|
||||
_ => Value::Void,
|
||||
};
|
||||
}
|
||||
@@ -192,6 +217,7 @@ impl Environment {
|
||||
let cmp_ty = StaticType::FunctionOverloads(vec![
|
||||
Signature { params: vec![StaticType::Int, StaticType::Int], ret: StaticType::Bool },
|
||||
Signature { params: vec![StaticType::Float, StaticType::Float], ret: StaticType::Bool },
|
||||
Signature { params: vec![StaticType::DateTime, StaticType::DateTime], ret: StaticType::Bool },
|
||||
]);
|
||||
self.register_native(">", cmp_ty.clone(), |args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
@@ -200,6 +226,7 @@ impl Environment {
|
||||
(Value::Int(a), Value::Float(b)) => Value::Bool((*a as f64) > *b),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Bool(*a > (*b as f64)),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Bool(a > b),
|
||||
(Value::DateTime(a), Value::DateTime(b)) => Value::Bool(a > b),
|
||||
_ => Value::Bool(false),
|
||||
}
|
||||
});
|
||||
@@ -211,6 +238,7 @@ impl Environment {
|
||||
(Value::Int(a), Value::Float(b)) => Value::Bool((*a as f64) < *b),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Bool(*a < (*b as f64)),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Bool(a < b),
|
||||
(Value::DateTime(a), Value::DateTime(b)) => Value::Bool(a < b),
|
||||
_ => Value::Bool(false),
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user