From 68a21aeaf8c1d17298efd2655c5ac0805930ec76 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Thu, 23 Apr 2026 23:29:37 +0300 Subject: [PATCH] time: fix `time.Time{}` value is wrong? (fixes #25346) --- vlib/time/time.c.v | 29 ++++++++++++++++++++--------- vlib/time/time_test.v | 14 +++++++++++++- vlib/time/utc_vs_local_time_test.v | 2 +- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/vlib/time/time.c.v b/vlib/time/time.c.v index afb8e7cfb..c9c769fef 100644 --- a/vlib/time/time.c.v +++ b/vlib/time/time.c.v @@ -60,21 +60,32 @@ fn time_with_unix(t Time) Time { if t.unix != 0 { return t } - tt := C.tm{ - tm_sec: t.second - tm_min: t.minute - tm_hour: t.hour - tm_mday: t.day - tm_mon: t.month - 1 - tm_year: t.year - 1900 + normalized := normalize_zero_date_parts(t) + return Time{ + ...normalized + unix: time_fields_to_unix(normalized) + } +} + +@[inline] +fn normalize_zero_date_parts(t Time) Time { + if t.month != 0 && t.day != 0 { + return t } - utime := make_unix_time(tt) return Time{ ...t - unix: utime + month: if t.month == 0 { 1 } else { t.month } + day: if t.day == 0 { 1 } else { t.day } } } +@[inline] +fn time_fields_to_unix(t Time) i64 { + return i64(t.days_from_unix_epoch()) * i64(seconds_per_day) + + i64(t.hour) * i64(seconds_per_hour) + i64(t.minute) * i64(seconds_per_minute) + + i64(t.second) +} + // ticks returns the number of milliseconds since the UNIX epoch. // On Windows ticks returns the number of milliseconds elapsed since system start. pub fn ticks() i64 { diff --git a/vlib/time/time_test.v b/vlib/time/time_test.v index 9ffd8409f..44f7e4abd 100644 --- a/vlib/time/time_test.v +++ b/vlib/time/time_test.v @@ -502,6 +502,18 @@ fn test_parse_weekday() { fn test_empty_time() { t := time.Time{} - // assert t.unix() == -62169984000 + assert t.unix() == -62167132800 + assert t.format_rfc3339() == '0000-01-01T00:00:00.000Z' + assert t == time.parse_rfc3339(t.format_rfc3339())! assert t.custom_format('MMMM YYYY') == 'January 0' } + +fn test_pre_epoch_unix_calculation() { + assert time.new(time.Time{}).unix() == -62167132800 + assert time.new( + year: 1 + month: 1 + day: 1 + ).unix() == -62135596800 + assert time.parse_rfc3339('0001-01-01T00:00:00Z')!.unix() == -62135596800 +} diff --git a/vlib/time/utc_vs_local_time_test.v b/vlib/time/utc_vs_local_time_test.v index 685664ab6..a0fd10be7 100644 --- a/vlib/time/utc_vs_local_time_test.v +++ b/vlib/time/utc_vs_local_time_test.v @@ -44,5 +44,5 @@ fn test_utc_to_local() { } sz := z.format_rfc3339() dump(sz) - assert sz == '0000-00-00T00:00:00.000Z' + assert sz == '0000-01-01T00:00:00.000Z' } -- 2.39.5