diff --git a/vlib/time/chrono.c.v b/vlib/time/chrono.c.v index 4d6de7d99f..f95dc8d230 100644 --- a/vlib/time/chrono.c.v +++ b/vlib/time/chrono.c.v @@ -13,6 +13,6 @@ pub fn portable_timegm(t &C.tm) i64 { year -= years_diff month += 12 * years_diff } - days_since_1970 := i64(days_from_civil(year, month + 1, t.tm_mday)) + days_since_1970 := i64(days_from_unix_epoch(year, month + 1, t.tm_mday)) return 60 * (60 * (24 * days_since_1970 + t.tm_hour) + t.tm_min) + t.tm_sec } diff --git a/vlib/time/chrono.v b/vlib/time/chrono.v index 58f1ef8c76..1bdf5a49f4 100644 --- a/vlib/time/chrono.v +++ b/vlib/time/chrono.v @@ -1,14 +1,44 @@ module time -// days_from_civil - return the number of days since the -// Unix epoch 1970-01-01. A detailed description of the algorithm here -// is in: http://howardhinnant.github.io/date_algorithms.html -// Note that it will return negative values for days before 1970-01-01. -pub fn days_from_civil(oy int, m int, d int) int { - y := if m <= 2 { oy - 1 } else { oy } +// days_from_unix_epoch - return the number of days since the Unix epoch 1970-01-01. +// A detailed description of the algorithm here is in: +// http://howardhinnant.github.io/date_algorithms.html +// Note that function will return negative values for days before 1970-01-01. +pub fn days_from_unix_epoch(year int, month int, day int) int { + y := if month <= 2 { year - 1 } else { year } era := y / 400 - yoe := y - era * 400 // [0, 399] - doy := (153 * (m + (if m > 2 { -3 } else { 9 })) + 2) / 5 + d - 1 // [0, 365] - doe := yoe * 365 + yoe / 4 - yoe / 100 + doy // [0, 146096] - return era * 146097 + doe - 719468 + year_of_the_era := y - era * 400 // [0, 399] + day_of_year := (153 * (month + (if month > 2 { -3 } else { 9 })) + 2) / 5 + day - 1 // [0, 365] + day_of_the_era := year_of_the_era * 365 + year_of_the_era / 4 - year_of_the_era / 100 + + day_of_year // [0, 146096] + return era * 146097 + day_of_the_era - 719468 +} + +// days_from_civil - return the number of days since the +// Unix epoch 1970-01-01. +// deprecated: use time.days_from_unix_epoch instead +[deprecated: 'use time.days_from_unix_epoch instead'] +[deprecated_after: '2022-11-23'] +pub fn days_from_civil(year int, month int, day int) int { + return days_from_unix_epoch(year, month, day) +} + +// days_from_unix_epoch - return the number of days since the Unix epoch 1970-01-01. +// A detailed description of the algorithm here is in: +// http://howardhinnant.github.io/date_algorithms.html +// Note that method will return negative values for days before 1970-01-01. +[inline] +pub fn (t Time) days_from_unix_epoch() int { + return days_from_unix_epoch(t.year, t.month, t.day) +} + +// date_from_days_after_unix_epoch - convert number of `days` after the unix epoch 1970-01-01, to a Time. +// Only the year, month and day of the returned Time will be set, everything else will be 0. +pub fn date_from_days_after_unix_epoch(days int) Time { + year, month, day := calculate_date_from_offset(i64(days)) + return Time{ + year: year + month: month + day: day + } } diff --git a/vlib/time/chrono_test.v b/vlib/time/chrono_test.v new file mode 100644 index 0000000000..a6fc0f3f35 --- /dev/null +++ b/vlib/time/chrono_test.v @@ -0,0 +1,35 @@ +module time + +fn test_days_from_unix_epoch() { + s := '2000-05-10 22:11:03' + time_test := parse(s) or { + eprintln('> failing format: $s | err: $err') + assert false + return + } + one_day_in_seconds := 86400 + + assert time_test.days_from_unix_epoch() == 11087 + assert time_test.days_from_unix_epoch() == int(time_test.unix / one_day_in_seconds) + assert days_from_unix_epoch(1970, 1, 1) == 0 + assert days_from_unix_epoch(1970, 2, 1) == 31 + assert days_from_unix_epoch(1970, 3, 1) == 59 + assert days_from_unix_epoch(2022, 11, 10) == 19306 +} + +fn test_date_from_days_after_unix_epoch() { + assert date_from_days_after_unix_epoch(11087).year == 2000 + assert date_from_days_after_unix_epoch(11087).month == 5 + assert date_from_days_after_unix_epoch(11087).day == 10 + assert date_from_days_after_unix_epoch(1).year == 1970 + assert date_from_days_after_unix_epoch(1).month == 1 + assert date_from_days_after_unix_epoch(1).day == 2 + + assert date_from_days_after_unix_epoch(31).year == 1970 + assert date_from_days_after_unix_epoch(31).month == 2 + assert date_from_days_after_unix_epoch(31).day == 1 + + assert date_from_days_after_unix_epoch(59).year == 1970 + assert date_from_days_after_unix_epoch(59).month == 3 + assert date_from_days_after_unix_epoch(59).day == 1 +}