From 55eeb701a9bce3d47cf5c9ff9ae9f012010f13a7 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 6 Jul 2021 18:51:47 +0300 Subject: [PATCH] time: fix `time.parse_iso8601(2037-07-23)?.add_days(181).str() == "1901-12-13 17:31:44"` --- vlib/time/Y2K38_test.v | 13 +++++++++++++ vlib/time/operator_test.v | 2 +- vlib/time/parse.v | 2 +- vlib/time/time.v | 4 ++-- vlib/time/time_darwin.c.v | 2 +- vlib/time/time_nix.c.v | 2 +- vlib/time/time_solaris.c.v | 2 +- vlib/time/unix.v | 18 +++++++++--------- 8 files changed, 29 insertions(+), 16 deletions(-) create mode 100644 vlib/time/Y2K38_test.v diff --git a/vlib/time/Y2K38_test.v b/vlib/time/Y2K38_test.v new file mode 100644 index 0000000000..0ebc0ef92b --- /dev/null +++ b/vlib/time/Y2K38_test.v @@ -0,0 +1,13 @@ +import time + +fn test_time_after_2038_works() { + after_time := time.parse_iso8601('2037-07-23') or { time.now() } + dump(after_time) + error_time := after_time.add_days(180) + dump(error_time) + assert error_time.str() == '2038-01-19 00:00:00' + // NB: the next date is after Y2K38, it should NOT wrap: + error_time2 := after_time.add_days(181) + dump(error_time2) + assert error_time2.str() == '2038-01-20 00:00:00' +} diff --git a/vlib/time/operator_test.v b/vlib/time/operator_test.v index 424322f48f..add305a96e 100644 --- a/vlib/time/operator_test.v +++ b/vlib/time/operator_test.v @@ -381,7 +381,7 @@ fn test_subtract() { second: 3 microsecond: 100 }) - t2 := unix2(int(t1.unix) + d_seconds, t1.microsecond + d_microseconds) + t2 := unix2(i64(t1.unix) + d_seconds, t1.microsecond + d_microseconds) d1 := t2 - t1 d2 := t1 - t2 assert d1 > 0 diff --git a/vlib/time/parse.v b/vlib/time/parse.v index 5233476ca5..95c5352429 100644 --- a/vlib/time/parse.v +++ b/vlib/time/parse.v @@ -135,6 +135,6 @@ pub fn parse_iso8601(s string) ?Time { } else if unix_offset > 0 { unix_time += u64(unix_offset) } - t = unix2(int(unix_time), t.microsecond) + t = unix2(i64(unix_time), t.microsecond) return t } diff --git a/vlib/time/time.v b/vlib/time/time.v index 43b5511e32..8cb14757cd 100644 --- a/vlib/time/time.v +++ b/vlib/time/time.v @@ -137,7 +137,7 @@ pub fn utc() Time { // in this API call t := C.time(0) _ = C.time(&t) - return unix2(int(t), 0) + return unix2(i64(t), 0) } // smonth returns month name. @@ -186,7 +186,7 @@ pub fn (t Time) add(d Duration) Time { microseconds := i64(t.unix) * 1000 * 1000 + t.microsecond + d.microseconds() unix := microseconds / (1000 * 1000) micro := microseconds % (1000 * 1000) - return unix2(int(unix), int(micro)) + return unix2(unix, int(micro)) } // add_seconds returns a new time struct with an added number of seconds. diff --git a/vlib/time/time_darwin.c.v b/vlib/time/time_darwin.c.v index 3a173a9d35..d16c66b275 100644 --- a/vlib/time/time_darwin.c.v +++ b/vlib/time/time_darwin.c.v @@ -80,5 +80,5 @@ fn darwin_utc() Time { // get the high precision time as UTC clock tv := C.timeval{} C.gettimeofday(&tv, 0) - return unix2(int(tv.tv_sec), int(tv.tv_usec)) + return unix2(i64(tv.tv_sec), int(tv.tv_usec)) } diff --git a/vlib/time/time_nix.c.v b/vlib/time/time_nix.c.v index 438b72d44f..c96d4e7a49 100644 --- a/vlib/time/time_nix.c.v +++ b/vlib/time/time_nix.c.v @@ -86,7 +86,7 @@ fn linux_utc() Time { // and use the nanoseconds part mut ts := C.timespec{} C.clock_gettime(C.CLOCK_REALTIME, &ts) - return unix2(int(ts.tv_sec), int(ts.tv_nsec / 1000)) + return unix2(i64(ts.tv_sec), int(ts.tv_nsec / 1000)) } // dummy to compile with all compilers diff --git a/vlib/time/time_solaris.c.v b/vlib/time/time_solaris.c.v index be02862387..b4dee546ce 100644 --- a/vlib/time/time_solaris.c.v +++ b/vlib/time/time_solaris.c.v @@ -18,7 +18,7 @@ fn solaris_utc() Time { // and use the nanoseconds part mut ts := C.timespec{} C.clock_gettime(C.CLOCK_REALTIME, &ts) - return unix2(int(ts.tv_sec), int(ts.tv_nsec / 1000)) + return unix2(i64(ts.tv_sec), int(ts.tv_nsec / 1000)) } // dummy to compile with all compilers diff --git a/vlib/time/unix.v b/vlib/time/unix.v index 65c745436d..ac9d0100b6 100644 --- a/vlib/time/unix.v +++ b/vlib/time/unix.v @@ -25,7 +25,7 @@ pub fn unix(abs int) Time { } // unix2 returns a time struct from Unix time and microsecond value -pub fn unix2(abs int, microsecond int) Time { +pub fn unix2(abs i64, microsecond int) Time { // Split into day and time mut day_offset := abs / seconds_per_day if abs % seconds_per_day < 0 { @@ -46,7 +46,7 @@ pub fn unix2(abs int, microsecond int) Time { } } -fn calculate_date_from_offset(day_offset_ int) (int, int, int) { +fn calculate_date_from_offset(day_offset_ i64) (int, int, int) { mut day_offset := day_offset_ // Move offset to year 2001 as it's the start of a new 400-year cycle // Code below this rely on the fact that the day_offset is lined up with the 400-year cycle @@ -54,14 +54,14 @@ fn calculate_date_from_offset(day_offset_ int) (int, int, int) { mut year := 2001 day_offset -= 31 * 365 + 8 // Account for 400 year cycle - year += (day_offset / days_per_400_years) * 400 + year += int(day_offset / days_per_400_years) * 400 day_offset %= days_per_400_years // Account for 100 year cycle if day_offset == days_per_100_years * 4 { year += 300 day_offset -= days_per_100_years * 3 } else { - year += (day_offset / days_per_100_years) * 100 + year += int(day_offset / days_per_100_years) * 100 day_offset %= days_per_100_years } // Account for 4 year cycle @@ -69,7 +69,7 @@ fn calculate_date_from_offset(day_offset_ int) (int, int, int) { year += 96 day_offset -= days_per_4_years * 24 } else { - year += (day_offset / days_per_4_years) * 4 + year += int(day_offset / days_per_4_years) * 4 day_offset %= days_per_4_years } // Account for every year @@ -77,7 +77,7 @@ fn calculate_date_from_offset(day_offset_ int) (int, int, int) { year += 3 day_offset -= 365 * 3 } else { - year += (day_offset / 365) + year += int(day_offset / 365) day_offset %= 365 } if day_offset < 0 { @@ -108,10 +108,10 @@ fn calculate_date_from_offset(day_offset_ int) (int, int, int) { estimated_month-- } day_offset -= days_before[estimated_month] - return year, estimated_month + 1, day_offset + 1 + return year, int(estimated_month + 1), int(day_offset + 1) } -fn calculate_time_from_offset(second_offset_ int) (int, int, int) { +fn calculate_time_from_offset(second_offset_ i64) (int, int, int) { mut second_offset := second_offset_ if second_offset < 0 { second_offset += seconds_per_day @@ -120,5 +120,5 @@ fn calculate_time_from_offset(second_offset_ int) (int, int, int) { second_offset %= seconds_per_hour min := second_offset / seconds_per_minute second_offset %= seconds_per_minute - return hour_, min, second_offset + return int(hour_), int(min), int(second_offset) }