time: turn Time.unix to i64, so it can represent times before 1970-01-01, fix time operators, add more tests (#11050)
parent
1bf6d04e37
commit
efa8dcf4d2
|
@ -38,7 +38,7 @@ pub mut:
|
||||||
state State // current state of connection
|
state State // current state of connection
|
||||||
logger &log.Log // logger used to log messages
|
logger &log.Log // logger used to log messages
|
||||||
resource_name string // name of current resource
|
resource_name string // name of current resource
|
||||||
last_pong_ut u64 // last time in unix time we got a pong message
|
last_pong_ut i64 // last time in unix time we got a pong message
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flag represents different types of headers in websocket handshake
|
// Flag represents different types of headers in websocket handshake
|
||||||
|
|
|
@ -747,6 +747,6 @@ fn test_utime() {
|
||||||
f.write_string(hello) or { panic(err) }
|
f.write_string(hello) or { panic(err) }
|
||||||
atime := time.now().add_days(2).unix_time()
|
atime := time.now().add_days(2).unix_time()
|
||||||
mtime := time.now().add_days(4).unix_time()
|
mtime := time.now().add_days(4).unix_time()
|
||||||
os.utime(filename, atime, mtime) or { panic(err) }
|
os.utime(filename, int(atime), int(mtime)) or { panic(err) }
|
||||||
assert os.file_last_mod_unix(filename) == mtime
|
assert os.file_last_mod_unix(filename) == mtime
|
||||||
}
|
}
|
||||||
|
|
|
@ -275,7 +275,7 @@ const (
|
||||||
// users or business transactions.
|
// users or business transactions.
|
||||||
// (https://news.ycombinator.com/item?id=14526173)
|
// (https://news.ycombinator.com/item?id=14526173)
|
||||||
pub fn ulid() string {
|
pub fn ulid() string {
|
||||||
return ulid_at_millisecond(time.utc().unix_time_milli())
|
return ulid_at_millisecond(u64(time.utc().unix_time_milli()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ulid_at_millisecond does the same as `ulid` but takes a custom Unix millisecond timestamp via `unix_time_milli`.
|
// ulid_at_millisecond does the same as `ulid` but takes a custom Unix millisecond timestamp via `unix_time_milli`.
|
||||||
|
|
|
@ -37,7 +37,7 @@ fn test_ulids_max_start_character_is_ok() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_ulids_generated_in_the_same_millisecond_have_the_same_prefix() {
|
fn test_ulids_generated_in_the_same_millisecond_have_the_same_prefix() {
|
||||||
t := time.utc().unix_time_milli()
|
t := u64(time.utc().unix_time_milli())
|
||||||
mut ulid1 := ''
|
mut ulid1 := ''
|
||||||
mut ulid2 := ''
|
mut ulid2 := ''
|
||||||
mut ulid3 := ''
|
mut ulid3 := ''
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
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 }
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// portable_timegm does the same as C._mkgmtime, but unlike it,
|
||||||
|
// can work with dates before the Unix epoch of 1970-01-01 .
|
||||||
|
pub fn portable_timegm(t &C.tm) i64 {
|
||||||
|
mut year := t.tm_year + 1900
|
||||||
|
mut month := t.tm_mon // 0-11
|
||||||
|
if month > 11 {
|
||||||
|
year += month / 12
|
||||||
|
month %= 12
|
||||||
|
} else if month < 0 {
|
||||||
|
years_diff := (11 - month) / 12
|
||||||
|
year -= years_diff
|
||||||
|
month += 12 * years_diff
|
||||||
|
}
|
||||||
|
days_since_1970 := i64(days_from_civil(year, month + 1, t.tm_mday))
|
||||||
|
return 60 * (60 * (24 * days_since_1970 + t.tm_hour) + t.tm_min) + t.tm_sec
|
||||||
|
}
|
|
@ -9,5 +9,5 @@ const (
|
||||||
|
|
||||||
// random returns a random time struct in *the past*.
|
// random returns a random time struct in *the past*.
|
||||||
pub fn random() time.Time {
|
pub fn random() time.Time {
|
||||||
return time.unix(int(rand.u64n(misc.start_time_unix)))
|
return time.unix(int(rand.i64n(misc.start_time_unix)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ pub fn (t1 Time) < (t2 Time) bool {
|
||||||
// Time subtract using operator overloading.
|
// Time subtract using operator overloading.
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (lhs Time) - (rhs Time) Duration {
|
pub fn (lhs Time) - (rhs Time) Duration {
|
||||||
lhs_micro := lhs.unix * 1000 * 1000 + u64(lhs.microsecond)
|
lhs_micro := lhs.unix * 1_000_000 + lhs.microsecond
|
||||||
rhs_micro := rhs.unix * 1000 * 1000 + u64(rhs.microsecond)
|
rhs_micro := rhs.unix * 1_000_000 + rhs.microsecond
|
||||||
return (i64(lhs_micro) - i64(rhs_micro)) * microsecond
|
return (lhs_micro - rhs_micro) * microsecond
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,9 +131,9 @@ pub fn parse_iso8601(s string) ?Time {
|
||||||
}
|
}
|
||||||
mut unix_time := t.unix
|
mut unix_time := t.unix
|
||||||
if unix_offset < 0 {
|
if unix_offset < 0 {
|
||||||
unix_time -= u64(-unix_offset)
|
unix_time -= (-unix_offset)
|
||||||
} else if unix_offset > 0 {
|
} else if unix_offset > 0 {
|
||||||
unix_time += u64(unix_offset)
|
unix_time += unix_offset
|
||||||
}
|
}
|
||||||
t = unix2(i64(unix_time), t.microsecond)
|
t = unix2(i64(unix_time), t.microsecond)
|
||||||
return t
|
return t
|
||||||
|
|
|
@ -50,7 +50,7 @@ pub:
|
||||||
minute int
|
minute int
|
||||||
second int
|
second int
|
||||||
microsecond int
|
microsecond int
|
||||||
unix u64
|
unix i64
|
||||||
}
|
}
|
||||||
|
|
||||||
// FormatDelimiter contains different time formats.
|
// FormatDelimiter contains different time formats.
|
||||||
|
@ -162,7 +162,7 @@ pub fn new_time(t Time) Time {
|
||||||
tm_mon: t.month - 1
|
tm_mon: t.month - 1
|
||||||
tm_year: t.year - 1900
|
tm_year: t.year - 1900
|
||||||
}
|
}
|
||||||
utime := u64(make_unix_time(tt))
|
utime := make_unix_time(tt)
|
||||||
return Time{
|
return Time{
|
||||||
...t
|
...t
|
||||||
unix: utime
|
unix: utime
|
||||||
|
@ -171,21 +171,21 @@ pub fn new_time(t Time) Time {
|
||||||
|
|
||||||
// unix_time returns Unix time.
|
// unix_time returns Unix time.
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (t Time) unix_time() int {
|
pub fn (t Time) unix_time() i64 {
|
||||||
return int(t.unix)
|
return t.unix
|
||||||
}
|
}
|
||||||
|
|
||||||
// unix_time_milli returns Unix time with millisecond resolution.
|
// unix_time_milli returns Unix time with millisecond resolution.
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (t Time) unix_time_milli() u64 {
|
pub fn (t Time) unix_time_milli() i64 {
|
||||||
return t.unix * 1000 + u64(t.microsecond / 1000)
|
return t.unix * 1000 + (t.microsecond / 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
// add returns a new time that duration is added
|
// add returns a new time that duration is added
|
||||||
pub fn (t Time) add(d Duration) Time {
|
pub fn (t Time) add(d Duration) Time {
|
||||||
microseconds := i64(t.unix) * 1000 * 1000 + t.microsecond + d.microseconds()
|
microseconds := i64(t.unix) * 1_000_000 + t.microsecond + d.microseconds()
|
||||||
unix := microseconds / (1000 * 1000)
|
unix := microseconds / 1_000_000
|
||||||
micro := microseconds % (1000 * 1000)
|
micro := microseconds % 1_000_000
|
||||||
return unix2(unix, int(micro))
|
return unix2(unix, int(micro))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,6 +358,11 @@ pub fn (t Time) str() string {
|
||||||
return t.format_ss()
|
return t.format_ss()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// str returns time in the same format as `parse` expects ("YYYY-MM-DD HH:MM:SS").
|
||||||
|
pub fn (t Time) debug() string {
|
||||||
|
return 'Time{ year: ${t.year:04} month: ${t.month:02} day: ${t.day:02} hour: ${t.hour:02} minute: ${t.minute:02} second: ${t.second:02} microsecond: ${t.microsecond:06} unix: ${t.unix:07} }'
|
||||||
|
}
|
||||||
|
|
||||||
// convert_ctime converts a C time to V time.
|
// convert_ctime converts a C time to V time.
|
||||||
fn convert_ctime(t C.tm, microsecond int) Time {
|
fn convert_ctime(t C.tm, microsecond int) Time {
|
||||||
return Time{
|
return Time{
|
||||||
|
@ -368,7 +373,7 @@ fn convert_ctime(t C.tm, microsecond int) Time {
|
||||||
minute: t.tm_min
|
minute: t.tm_min
|
||||||
second: t.tm_sec
|
second: t.tm_sec
|
||||||
microsecond: time.microsecond
|
microsecond: time.microsecond
|
||||||
unix: u64(make_unix_time(t))
|
unix: make_unix_time(t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import time
|
||||||
|
|
||||||
|
fn test_add_to_day_in_the_previous_century() ? {
|
||||||
|
a := time.parse_iso8601('1900-01-01') ?
|
||||||
|
aa := a.add_days(180)
|
||||||
|
dump(a.debug())
|
||||||
|
dump(aa.debug())
|
||||||
|
assert aa.ymmdd() == '1900-06-29'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_add_to_day_in_the_past() ? {
|
||||||
|
a := time.parse_iso8601('1990-03-01') ?
|
||||||
|
aa := a.add_days(180)
|
||||||
|
assert aa.ymmdd() == '1990-08-27'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_add_to_day_in_the_recent_past() ? {
|
||||||
|
a := time.parse_iso8601('2021-03-01') ?
|
||||||
|
aa := a.add_days(180)
|
||||||
|
assert aa.ymmdd() == '2021-08-28'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_add_to_day_in_the_future_1() ? {
|
||||||
|
a := time.parse_iso8601('3000-11-01') ?
|
||||||
|
aa := a.add_days(180)
|
||||||
|
assert aa.ymmdd() == '3001-04-30'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_add_to_day_in_the_future_2() ? {
|
||||||
|
a := time.parse_iso8601('3000-12-30') ?
|
||||||
|
aa := a.add_days(180)
|
||||||
|
assert aa.ymmdd() == '3001-06-28'
|
||||||
|
}
|
|
@ -23,8 +23,8 @@ fn C.timegm(&C.tm) C.time_t
|
||||||
// fn C.gmtime_r(&tm, &gbuf)
|
// fn C.gmtime_r(&tm, &gbuf)
|
||||||
fn C.localtime_r(t &time_t, tm &C.tm)
|
fn C.localtime_r(t &time_t, tm &C.tm)
|
||||||
|
|
||||||
fn make_unix_time(t C.tm) int {
|
fn make_unix_time(t C.tm) i64 {
|
||||||
return int(C.timegm(&t))
|
return i64(C.timegm(&t))
|
||||||
}
|
}
|
||||||
|
|
||||||
// local returns t with the location set to local time.
|
// local returns t with the location set to local time.
|
||||||
|
|
|
@ -160,18 +160,18 @@ fn test_add() {
|
||||||
t2 := time_to_test.add(duration)
|
t2 := time_to_test.add(duration)
|
||||||
assert t2.second == t1.second + d_seconds
|
assert t2.second == t1.second + d_seconds
|
||||||
assert t2.microsecond == t1.microsecond + d_microseconds
|
assert t2.microsecond == t1.microsecond + d_microseconds
|
||||||
assert t2.unix == t1.unix + u64(d_seconds)
|
assert t2.unix == t1.unix + d_seconds
|
||||||
t3 := time_to_test.add(-duration)
|
t3 := time_to_test.add(-duration)
|
||||||
assert t3.second == t1.second - d_seconds
|
assert t3.second == t1.second - d_seconds
|
||||||
assert t3.microsecond == t1.microsecond - d_microseconds
|
assert t3.microsecond == t1.microsecond - d_microseconds
|
||||||
assert t3.unix == t1.unix - u64(d_seconds)
|
assert t3.unix == t1.unix - d_seconds
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_add_days() {
|
fn test_add_days() {
|
||||||
num_of_days := 3
|
num_of_days := 3
|
||||||
t := time_to_test.add_days(num_of_days)
|
t := time_to_test.add_days(num_of_days)
|
||||||
assert t.day == time_to_test.day + num_of_days
|
assert t.day == time_to_test.day + num_of_days
|
||||||
assert t.unix == time_to_test.unix + 86400 * u64(num_of_days)
|
assert t.unix == time_to_test.unix + 86400 * num_of_days
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_str() {
|
fn test_str() {
|
||||||
|
@ -217,8 +217,8 @@ fn test_unix_time() {
|
||||||
//
|
//
|
||||||
utm1 := t1.unix_time_milli()
|
utm1 := t1.unix_time_milli()
|
||||||
utm2 := t2.unix_time_milli()
|
utm2 := t2.unix_time_milli()
|
||||||
assert (utm1 - u64(ut1) * 1000) < 1000
|
assert (utm1 - ut1 * 1000) < 1000
|
||||||
assert (utm2 - u64(ut2) * 1000) < 1000
|
assert (utm2 - ut2 * 1000) < 1000
|
||||||
//
|
//
|
||||||
// println('utm1: $utm1 | utm2: $utm2')
|
// println('utm1: $utm1 | utm2: $utm2')
|
||||||
assert utm2 - utm1 > 2
|
assert utm2 - utm1 > 2
|
||||||
|
|
|
@ -52,14 +52,12 @@ struct C.timespec {
|
||||||
tv_nsec i64
|
tv_nsec i64
|
||||||
}
|
}
|
||||||
|
|
||||||
fn C._mkgmtime(&C.tm) C.time_t
|
|
||||||
|
|
||||||
fn C.QueryPerformanceCounter(&u64) C.BOOL
|
fn C.QueryPerformanceCounter(&u64) C.BOOL
|
||||||
|
|
||||||
fn C.QueryPerformanceFrequency(&u64) C.BOOL
|
fn C.QueryPerformanceFrequency(&u64) C.BOOL
|
||||||
|
|
||||||
fn make_unix_time(t C.tm) int {
|
fn make_unix_time(t C.tm) i64 {
|
||||||
return int(C._mkgmtime(&t))
|
return portable_timegm(&t)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_win_time_freq() u64 {
|
fn init_win_time_freq() u64 {
|
||||||
|
@ -91,7 +89,7 @@ fn vpc_now() u64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// local_as_unix_time returns the current local time as unix time
|
// local_as_unix_time returns the current local time as unix time
|
||||||
fn local_as_unix_time() int {
|
fn local_as_unix_time() i64 {
|
||||||
t := C.time(0)
|
t := C.time(0)
|
||||||
tm := C.localtime(&t)
|
tm := C.localtime(&t)
|
||||||
return make_unix_time(tm)
|
return make_unix_time(tm)
|
||||||
|
@ -117,7 +115,7 @@ pub fn (t Time) local() Time {
|
||||||
minute: st_local.minute
|
minute: st_local.minute
|
||||||
second: st_local.second // These are the same
|
second: st_local.second // These are the same
|
||||||
microsecond: st_local.millisecond * 1000
|
microsecond: st_local.millisecond * 1000
|
||||||
unix: u64(st_local.unix_time())
|
unix: st_local.unix_time()
|
||||||
}
|
}
|
||||||
return t_local
|
return t_local
|
||||||
}
|
}
|
||||||
|
@ -140,7 +138,7 @@ fn win_now() Time {
|
||||||
minute: st_local.minute
|
minute: st_local.minute
|
||||||
second: st_local.second
|
second: st_local.second
|
||||||
microsecond: st_local.millisecond * 1000
|
microsecond: st_local.millisecond * 1000
|
||||||
unix: u64(st_local.unix_time())
|
unix: st_local.unix_time()
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
@ -161,13 +159,13 @@ fn win_utc() Time {
|
||||||
minute: st_utc.minute
|
minute: st_utc.minute
|
||||||
second: st_utc.second
|
second: st_utc.second
|
||||||
microsecond: st_utc.millisecond * 1000
|
microsecond: st_utc.millisecond * 1000
|
||||||
unix: u64(st_utc.unix_time())
|
unix: st_utc.unix_time()
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
// unix_time returns Unix time.
|
// unix_time returns Unix time.
|
||||||
pub fn (st SystemTime) unix_time() int {
|
pub fn (st SystemTime) unix_time() i64 {
|
||||||
tt := C.tm{
|
tt := C.tm{
|
||||||
tm_sec: st.second
|
tm_sec: st.second
|
||||||
tm_min: st.minute
|
tm_min: st.minute
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub fn unix(abs int) Time {
|
||||||
hour: hr
|
hour: hr
|
||||||
minute: min
|
minute: min
|
||||||
second: sec
|
second: sec
|
||||||
unix: u64(abs)
|
unix: abs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ pub fn unix2(abs i64, microsecond int) Time {
|
||||||
minute: min
|
minute: min
|
||||||
second: sec
|
second: sec
|
||||||
microsecond: microsecond
|
microsecond: microsecond
|
||||||
unix: u64(abs)
|
unix: abs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,7 @@ fn (am AssetManager) combine(asset_type string, to_file bool) string {
|
||||||
|
|
||||||
fn (am AssetManager) get_cache_key(asset_type string) string {
|
fn (am AssetManager) get_cache_key(asset_type string) string {
|
||||||
mut files_salt := ''
|
mut files_salt := ''
|
||||||
mut latest_modified := u64(0)
|
mut latest_modified := i64(0)
|
||||||
for asset in am.get_assets(asset_type) {
|
for asset in am.get_assets(asset_type) {
|
||||||
files_salt += asset.file_path
|
files_salt += asset.file_path
|
||||||
if asset.last_modified.unix > latest_modified {
|
if asset.last_modified.unix > latest_modified {
|
||||||
|
@ -151,7 +151,7 @@ fn (mut am AssetManager) add(asset_type string, file string) bool {
|
||||||
asset := Asset{
|
asset := Asset{
|
||||||
file_path: file
|
file_path: file
|
||||||
last_modified: time.Time{
|
last_modified: time.Time{
|
||||||
unix: u64(os.file_last_mod_unix(file))
|
unix: os.file_last_mod_unix(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if asset_type == 'css' {
|
if asset_type == 'css' {
|
||||||
|
|
Loading…
Reference in New Issue