Skip to content

Commit

Permalink
Store datetimes with fixed offset
Browse files Browse the repository at this point in the history
fixes #376
  • Loading branch information
sharkdp authored and David Peter committed Feb 23, 2024
1 parent b2681ed commit 6f46e2c
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 45 deletions.
19 changes: 7 additions & 12 deletions numbat/src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ use std::collections::HashMap;

use std::sync::OnceLock;

use chrono::Offset;

use crate::currency::ExchangeRatesCache;
use crate::interpreter::RuntimeError;
use crate::pretty_print::PrettyPrint;
Expand Down Expand Up @@ -834,11 +832,9 @@ fn chr(args: &[Value]) -> Result<Value> {

fn now(args: &[Value]) -> Result<Value> {
assert!(args.is_empty());
let now = chrono::Utc::now();

let offset = now.with_timezone(&chrono::Local).offset().fix();
let now = chrono::Local::now().fixed_offset();

Ok(Value::DateTime(now, offset))
Ok(Value::DateTime(now))
}

fn datetime(args: &[Value]) -> Result<Value> {
Expand All @@ -850,9 +846,7 @@ fn datetime(args: &[Value]) -> Result<Value> {
.map_err(RuntimeError::DateParsingError)?
.ok_or(RuntimeError::DateParsingErrorUnknown)?;

let offset = crate::datetime::local_offset_for_datetime(&output);

Ok(Value::DateTime(output.into(), offset))
Ok(Value::DateTime(output))
}

fn format_datetime(args: &[Value]) -> Result<Value> {
Expand Down Expand Up @@ -901,8 +895,9 @@ fn from_unixtime(args: &[Value]) -> Result<Value> {

let timestamp = args[0].unsafe_as_quantity().unsafe_value().to_f64() as i64;

let dt = chrono::DateTime::from_timestamp(timestamp, 0).unwrap();
let offset = dt.offset().fix();
let dt = chrono::DateTime::from_timestamp(timestamp, 0)
.unwrap()
.fixed_offset();

Ok(Value::DateTime(dt, offset))
Ok(Value::DateTime(dt))
}
16 changes: 7 additions & 9 deletions numbat/src/value.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use chrono::FixedOffset;

use crate::{pretty_print::PrettyPrint, quantity::Quantity};

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -26,7 +28,7 @@ pub enum Value {
Boolean(bool),
String(String),
/// A DateTime with an associated offset used when pretty printing
DateTime(chrono::DateTime<chrono::Utc>, chrono::FixedOffset),
DateTime(chrono::DateTime<chrono::FixedOffset>),
FunctionReference(FunctionReference),
}

Expand Down Expand Up @@ -59,8 +61,8 @@ impl Value {
}

#[track_caller]
pub fn unsafe_as_datetime(&self) -> &chrono::DateTime<chrono::Utc> {
if let Value::DateTime(dt, _) = self {
pub fn unsafe_as_datetime(&self) -> &chrono::DateTime<chrono::FixedOffset> {
if let Value::DateTime(dt) = self {
dt
} else {
panic!("Expected value to be a string");
Expand All @@ -83,7 +85,7 @@ impl std::fmt::Display for Value {
Value::Quantity(q) => write!(f, "{}", q),
Value::Boolean(b) => write!(f, "{}", b),
Value::String(s) => write!(f, "\"{}\"", s),
Value::DateTime(dt, _) => write!(f, "datetime(\"{}\")", dt),
Value::DateTime(dt) => write!(f, "datetime(\"{}\")", dt),
Value::FunctionReference(r) => write!(f, "{}", r),
}
}
Expand All @@ -95,11 +97,7 @@ impl PrettyPrint for Value {
Value::Quantity(q) => q.pretty_print(),
Value::Boolean(b) => b.pretty_print(),
Value::String(s) => s.pretty_print(),
Value::DateTime(dt, offset) => {
let l: chrono::DateTime<chrono::FixedOffset> =
chrono::DateTime::from_naive_utc_and_offset(dt.naive_utc(), *offset);
crate::markup::string(l.to_rfc2822())
}
Value::DateTime(dt) => crate::markup::string(dt.to_rfc2822()),
Value::FunctionReference(r) => crate::markup::string(r.to_string()),
}
}
Expand Down
38 changes: 14 additions & 24 deletions numbat/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -533,9 +533,9 @@ impl Vm {
}

#[track_caller]
fn pop_datetime(&mut self) -> chrono::DateTime<chrono::Utc> {
fn pop_datetime(&mut self) -> chrono::DateTime<chrono::FixedOffset> {
match self.pop() {
Value::DateTime(q, _) => q,
Value::DateTime(q) => q,
_ => panic!("Expected datetime to be on the top of the stack"),
}
}
Expand Down Expand Up @@ -664,18 +664,15 @@ impl Vm {
(seconds_f.fract() * 1_000_000_000f64).round() as i64,
);

self.push(Value::DateTime(
match op {
Op::AddToDateTime => lhs
.checked_add_signed(duration)
.ok_or(RuntimeError::DateTimeOutOfRange)?,
Op::SubFromDateTime => lhs
.checked_sub_signed(duration)
.ok_or(RuntimeError::DateTimeOutOfRange)?,
_ => unreachable!(),
},
chrono::Local::now().offset().fix(),
));
self.push(Value::DateTime(match op {
Op::AddToDateTime => lhs
.checked_add_signed(duration)
.ok_or(RuntimeError::DateTimeOutOfRange)?,
Op::SubFromDateTime => lhs
.checked_sub_signed(duration)
.ok_or(RuntimeError::DateTimeOutOfRange)?,
_ => unreachable!(),
}));
}
Op::DiffDateTime => {
let unit = self.pop_quantity();
Expand Down Expand Up @@ -852,9 +849,9 @@ impl Vm {
.parse()
.map_err(|_| RuntimeError::UnknownTimezone(tz_name.into()))?;

let offset = dt.with_timezone(&tz).offset().fix();
let dt = dt.with_timezone(&tz).fixed_offset();

self.push(Value::DateTime(dt, offset));
self.push(Value::DateTime(dt));
}
}
}
Expand All @@ -871,14 +868,7 @@ impl Vm {
Value::Quantity(q) => q.to_string(),
Value::Boolean(b) => b.to_string(),
Value::String(s) => s,
Value::DateTime(dt, offset) => {
let l: chrono::DateTime<chrono::FixedOffset> =
chrono::DateTime::from_naive_utc_and_offset(
dt.naive_utc(),
offset,
);
l.to_rfc2822()
}
Value::DateTime(dt) => dt.to_rfc2822(),
Value::FunctionReference(r) => r.to_string(),
};
joined = part + &joined; // reverse order
Expand Down

0 comments on commit 6f46e2c

Please sign in to comment.