Merge pull request #586 from MarekSpodBiedry:issue-578

This commit is contained in:
Brandon Thomas 2026-10-12 23:35:32 -04:00
commit ca9b3fbbe8
6 changed files with 35 additions and 10 deletions

View File

@ -59,6 +59,14 @@ pub fn serial_from_unix_ms(ms: f64) -> f64 {
25569.0 + ms / 86_400_000.0 25569.0 + ms / 86_400_000.0
} }
/// Converts a 1900-system serial (as the clock supplies it) to the serial of the same instant in `sys`.
pub fn serial_in_system(sys: DateSystem, serial_1900: f64) -> f64 {
match sys {
DateSystem::D1900 => serial_1900,
DateSystem::D1904 => serial_1900 - 1462.0,
}
}
pub fn civil_from_days(z: i64) -> (i32, u32, u32) { pub fn civil_from_days(z: i64) -> (i32, u32, u32) {
let z = z + 719468; let z = z + 719468;
let era = if z >= 0 { z } else { z - 146096 } / 146097; let era = if z >= 0 { z } else { z - 146096 } / 146097;

View File

@ -184,7 +184,7 @@ impl CfCache {
}, },
CfRule::TimePeriod { period, style } => match v.as_f64() { CfRule::TimePeriod { period, style } => match v.as_f64() {
Some(n) => { Some(n) => {
let today = gridcraft_calc::now_serial().floor(); let today = gridcraft_core::date::serial_in_system(wb.date_system, gridcraft_calc::now_serial()).floor();
let d = n.floor(); let d = n.floor();
let wd = gridcraft_core::date::datetime_from_serial(wb.date_system, today).map(|x| x.weekday as f64).unwrap_or(0.0); let wd = gridcraft_core::date::datetime_from_serial(wb.date_system, today).map(|x| x.weekday as f64).unwrap_or(0.0);
let week_start = today - wd; let week_start = today - wd;

View File

@ -391,7 +391,7 @@ pub struct HfContext {
/// Today's date and the current time as headers and footers show them (`&D`, `&T`). /// Today's date and the current time as headers and footers show them (`&D`, `&T`).
pub fn hf_date_time(wb: &Workbook) -> (String, String) { pub fn hf_date_time(wb: &Workbook) -> (String, String) {
let now = gridcraft_calc::now_serial(); let now = gridcraft_core::date::serial_in_system(wb.date_system, gridcraft_calc::now_serial());
let date = crate::display::format(&Value::Number(now.floor()), "m/d/yyyy", wb).text; let date = crate::display::format(&Value::Number(now.floor()), "m/d/yyyy", wb).text;
let time = crate::display::format(&Value::Number(now), "h:mm AM/PM", wb).text; let time = crate::display::format(&Value::Number(now), "h:mm AM/PM", wb).text;
(date, time) (date, time)
@ -1765,6 +1765,14 @@ mod tests {
} }
} }
#[test]
fn header_footer_date_follows_the_workbook_date_system() {
let mut wb = Workbook::new();
let date_1900 = hf_date_time(&wb).0;
wb.date_system = gridcraft_core::DateSystem::D1904;
assert_eq!(hf_date_time(&wb).0, date_1900);
}
#[test] #[test]
fn header_footer_section_edits_are_undoable_and_views_are_per_sheet() { fn header_footer_section_edits_are_undoable_and_views_are_per_sheet() {
let mut s = s(); let mut s = s();

View File

@ -1,6 +1,6 @@
//! Date and time functions. //! Date and time functions.
use gridcraft_core::date::{DateTime, datetime_from_serial, days_in_month, days_in_month_in, is_leap, serial_from_ymd}; use gridcraft_core::date::{DateTime, datetime_from_serial, days_in_month, days_in_month_in, is_leap, serial_from_ymd, serial_in_system};
use gridcraft_core::parse::parse_input; use gridcraft_core::parse::parse_input;
use gridcraft_core::{CellError, DateSystem, Value}; use gridcraft_core::{CellError, DateSystem, Value};
@ -98,10 +98,10 @@ fn second(a: &[Arg], _c: &mut dyn Ctx) -> R<Value> {
} }
fn now(_a: &[Arg], c: &mut dyn Ctx) -> R<Value> { fn now(_a: &[Arg], c: &mut dyn Ctx) -> R<Value> {
num_val(c.now_serial()) num_val(serial_in_system(c.date_system(), c.now_serial()))
} }
fn today(_a: &[Arg], c: &mut dyn Ctx) -> R<Value> { fn today(_a: &[Arg], c: &mut dyn Ctx) -> R<Value> {
num_val(c.now_serial().floor()) num_val(serial_in_system(c.date_system(), c.now_serial()).floor())
} }
fn weekday(a: &[Arg], c: &mut dyn Ctx) -> R<Value> { fn weekday(a: &[Arg], c: &mut dyn Ctx) -> R<Value> {
@ -794,6 +794,11 @@ mod tests {
close(crate::call(spec, &[n(0.0)], &mut ctx), 6.0); close(crate::call(spec, &[n(0.0)], &mut ctx), 6.0);
let spec = crate::lookup("YEAR").unwrap(); let spec = crate::lookup("YEAR").unwrap();
close(crate::call(spec, &[n(0.0)], &mut ctx), 1904.0); close(crate::call(spec, &[n(0.0)], &mut ctx), 1904.0);
// The clock is 2026-10-07 12:00; in the 1904 system that is serial 44840.5.
close(crate::call(crate::lookup("NOW").unwrap(), &[], &mut ctx), 44840.5);
let today = crate::call(crate::lookup("TODAY").unwrap(), &[], &mut ctx);
close(today.clone(), 44840.0);
close(crate::call(spec, &[crate::Arg::val(today)], &mut ctx), 2026.0);
// No fictitious day here: 1904 is a real leap year and 1900 is before the epoch. // No fictitious day here: 1904 is a real leap year and 1900 is before the epoch.
let spec = crate::lookup("DATE").unwrap(); let spec = crate::lookup("DATE").unwrap();
close(crate::call(spec, &[n(1904.0), n(2.0), n(29.0)], &mut ctx), 59.0); close(crate::call(spec, &[n(1904.0), n(2.0), n(29.0)], &mut ctx), 59.0);

View File

@ -179,12 +179,14 @@ pub(crate) fn dispatch(app: &mut SheetApp, ctx: &egui::Context, key: Key, physic
} }
Shortcut::Dialog(name, params) => app.open_dialog(name, params), Shortcut::Dialog(name, params) => app.open_dialog(name, params),
Shortcut::Date | Shortcut::Time => { Shortcut::Date | Shortcut::Time => {
let now = gridcraft_engine::calc::now_serial();
let (value, format) = if shortcut == Shortcut::Date { (now.floor(), "m/d/yyyy") } else { (now.fract(), "h:mm AM/PM") };
let text = app let text = app
.session .session
.active() .active()
.map(|d| gridcraft_engine::display::format(&gridcraft_engine::core::Value::Number(value), format, &d.wb).text) .map(|d| {
let now = gridcraft_engine::core::date::serial_in_system(d.wb.date_system, gridcraft_engine::calc::now_serial());
let (value, format) = if shortcut == Shortcut::Date { (now.floor(), "m/d/yyyy") } else { (now.fract(), "h:mm AM/PM") };
gridcraft_engine::display::format(&gridcraft_engine::core::Value::Number(value), format, &d.wb).text
})
.unwrap_or_default(); .unwrap_or_default();
edit_with(app, text); edit_with(app, text);
} }

View File

@ -2458,11 +2458,13 @@ pub fn shortcut(app: &mut SheetApp, key: Key, m: Modifiers) {
} }
Key::Semicolon => { Key::Semicolon => {
// Insert today's date. // Insert today's date.
let today = gridcraft_engine::calc::now_serial().floor();
let text = app let text = app
.session .session
.active() .active()
.map(|d| gridcraft_engine::display::format(&gridcraft_engine::core::Value::Number(today), "m/d/yyyy", &d.wb).text) .map(|d| {
let today = gridcraft_engine::core::date::serial_in_system(d.wb.date_system, gridcraft_engine::calc::now_serial()).floor();
gridcraft_engine::display::format(&gridcraft_engine::core::Value::Number(today), "m/d/yyyy", &d.wb).text
})
.unwrap_or_default(); .unwrap_or_default();
app.begin_edit(Some(text), false); app.begin_edit(Some(text), false);
None None