1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

time: store time with nanosecond resolution in time.Time, deprecate Time.microsecond, add utility methods and tests (#19062)

This commit is contained in:
Delyan Angelov 2023-08-05 23:41:23 +03:00 committed by GitHub
parent cc97b8df1e
commit b9a523cefd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 265 additions and 199 deletions

View File

@ -74,12 +74,12 @@ fn on_frame(mut app App) {
// draw minute hand // draw minute hand
mut j := f32(n.minute) mut j := f32(n.minute)
if n.second == 59 { // make minute hand move smoothly if n.second == 59 { // make minute hand move smoothly
j += f32(math.sin(f32(n.microsecond) / 1e6 * math.pi / 2.0)) j += f32(math.sin(f32(n.nanosecond) / 1e9 * math.pi / 2.0))
} }
draw_convex_poly_rotate(mut app.gg, app.dpi_scale, app.minute_hand, hand_color, j * 6) draw_convex_poly_rotate(mut app.gg, app.dpi_scale, app.minute_hand, hand_color, j * 6)
// draw second hand with smooth transition // draw second hand with smooth transition
k := f32(n.second) + f32(math.sin(f32(n.microsecond) / 1e6 * math.pi / 2.0)) k := f32(n.second) + f32(math.sin(f32(n.nanosecond) / 1e9 * math.pi / 2.0))
draw_convex_poly_rotate(mut app.gg, app.dpi_scale, app.second_hand, second_hand_color, draw_convex_poly_rotate(mut app.gg, app.dpi_scale, app.second_hand, second_hand_color,
0 + k * 6) 0 + k * 6)

View File

@ -28,7 +28,7 @@ const time_to_test = time.Time{
hour: 21 hour: 21
minute: 23 minute: 23
second: 42 second: 42
microsecond: 123456 nanosecond: 123456789
unix: 332198622 unix: 332198622
} }
@ -38,6 +38,7 @@ assert '1980-07-11 21:23' == time_to_test.format()
assert '1980-07-11 21:23:42' == time_to_test.format_ss() assert '1980-07-11 21:23:42' == time_to_test.format_ss()
assert '1980-07-11 21:23:42.123' == time_to_test.format_ss_milli() assert '1980-07-11 21:23:42.123' == time_to_test.format_ss_milli()
assert '1980-07-11 21:23:42.123456' == time_to_test.format_ss_micro() assert '1980-07-11 21:23:42.123456' == time_to_test.format_ss_micro()
assert '1980-07-11 21:23:42.123456789' == time_to_test.format_ss_nano()
``` ```
You can also parse strings to produce time.Time values, You can also parse strings to produce time.Time values,

View File

@ -31,3 +31,9 @@ fn test_duration_str() {
assert time.Duration(1 * time.hour + 5 * time.second).str() == '1:00:05' assert time.Duration(1 * time.hour + 5 * time.second).str() == '1:00:05'
assert time.Duration(168 * time.hour + 5 * time.minute + 7 * time.second).str() == '168:05:07' assert time.Duration(168 * time.hour + 5 * time.minute + 7 * time.second).str() == '168:05:07'
} }
fn test_duration_debug() {
assert time.Duration(1 * time.nanosecond).debug() == 'Duration: 1ns'
assert time.Duration(169 * time.hour + 5 * time.minute + 7 * time.second).debug() == 'Duration: 7days, 1h, 5m, 7s'
assert (-time.Duration(169 * time.hour + 5 * time.minute + 7 * time.second)).debug() == 'Duration: - 7days, 1h, 5m, 7s'
}

View File

@ -17,7 +17,7 @@ pub fn (t Time) format_ss() string {
// format_ss_milli returns a date string in "YYYY-MM-DD HH:mm:ss.123" format (24h). // format_ss_milli returns a date string in "YYYY-MM-DD HH:mm:ss.123" format (24h).
pub fn (t Time) format_ss_milli() string { pub fn (t Time) format_ss_milli() string {
return '${t.year:04d}-${t.month:02d}-${t.day:02d} ${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${(t.microsecond / 1000):03d}' return '${t.year:04d}-${t.month:02d}-${t.day:02d} ${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${(t.nanosecond / 1_000_000):03d}'
} }
// format_rfc3339 returns a date string in "YYYY-MM-DDTHH:mm:ss.123Z" format (24 hours, see https://www.rfc-editor.org/rfc/rfc3339.html) // format_rfc3339 returns a date string in "YYYY-MM-DDTHH:mm:ss.123Z" format (24 hours, see https://www.rfc-editor.org/rfc/rfc3339.html)
@ -25,12 +25,17 @@ pub fn (t Time) format_ss_milli() string {
// It is intended to improve consistency and interoperability, when representing and using date and time in Internet protocols. // It is intended to improve consistency and interoperability, when representing and using date and time in Internet protocols.
pub fn (t Time) format_rfc3339() string { pub fn (t Time) format_rfc3339() string {
u := t.local_to_utc() u := t.local_to_utc()
return '${u.year:04d}-${u.month:02d}-${u.day:02d}T${u.hour:02d}:${u.minute:02d}:${u.second:02d}.${(u.microsecond / 1000):03d}Z' return '${u.year:04d}-${u.month:02d}-${u.day:02d}T${u.hour:02d}:${u.minute:02d}:${u.second:02d}.${(u.nanosecond / 1_000_000):03d}Z'
} }
// format_ss_micro returns a date string in "YYYY-MM-DD HH:mm:ss.123456" format (24h). // format_ss_micro returns a date string in "YYYY-MM-DD HH:mm:ss.123456" format (24h).
pub fn (t Time) format_ss_micro() string { pub fn (t Time) format_ss_micro() string {
return '${t.year:04d}-${t.month:02d}-${t.day:02d} ${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${t.microsecond:06d}' return '${t.year:04d}-${t.month:02d}-${t.day:02d} ${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${(t.nanosecond / 1_000):06d}'
}
// format_ss_nano returns a date string in "YYYY-MM-DD HH:mm:ss.123456789" format (24h).
pub fn (t Time) format_ss_nano() string {
return '${t.year:04d}-${t.month:02d}-${t.day:02d} ${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${t.nanosecond:09d}'
} }
// hhmm returns a date string in "HH:mm" format (24h). // hhmm returns a date string in "HH:mm" format (24h).
@ -381,8 +386,9 @@ pub fn (t Time) get_fmt_time_str(fmt_time FormatTime) string {
.hhmm24 { '${t.hour:02d}:${t.minute:02d}' } .hhmm24 { '${t.hour:02d}:${t.minute:02d}' }
.hhmmss12 { '${hour_}:${t.minute:02d}:${t.second:02d} ${tp}' } .hhmmss12 { '${hour_}:${t.minute:02d}:${t.second:02d} ${tp}' }
.hhmmss24 { '${t.hour:02d}:${t.minute:02d}:${t.second:02d}' } .hhmmss24 { '${t.hour:02d}:${t.minute:02d}:${t.second:02d}' }
.hhmmss24_milli { '${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${(t.microsecond / 1000):03d}' } .hhmmss24_milli { '${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${(t.nanosecond / 1_000_000):03d}' }
.hhmmss24_micro { '${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${t.microsecond:06d}' } .hhmmss24_micro { '${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${(t.nanosecond / 1_000):06d}' }
.hhmmss24_nano { '${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${t.nanosecond:06d}' }
else { 'unknown enumeration ${fmt_time}' } else { 'unknown enumeration ${fmt_time}' }
} }
} }

View File

@ -3,19 +3,22 @@ module time
// operator `==` returns true if provided time is equal to time // operator `==` returns true if provided time is equal to time
[inline] [inline]
pub fn (t1 Time) == (t2 Time) bool { pub fn (t1 Time) == (t2 Time) bool {
return t1.unix == t2.unix && t1.microsecond == t2.microsecond return t1.unix == t2.unix && t1.nanosecond == t2.nanosecond
} }
// operator `<` returns true if provided time is less than time // operator `<` returns true if provided time is less than time
[inline] [inline]
pub fn (t1 Time) < (t2 Time) bool { pub fn (t1 Time) < (t2 Time) bool {
return t1.unix < t2.unix || (t1.unix == t2.unix && t1.microsecond < t2.microsecond) return t1.unix < t2.unix || (t1.unix == t2.unix && t1.nanosecond < t2.nanosecond)
} }
// 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 * 1_000_000 + lhs.microsecond // lhs.unix * 1_000_000_000 + i64(lhs.nanosecond) will overflow i64, for years > 3000 .
rhs_micro := rhs.unix * 1_000_000 + rhs.microsecond // Doing the diff first, and *then* multiplying by `second`, is less likely to overflow,
return (lhs_micro - rhs_micro) * microsecond // since lhs and rhs will be likely close to each other.
unixs := i64(lhs.unix - rhs.unix) * second
nanos := lhs.nanosecond - rhs.nanosecond
return unixs + nanos
} }

View File

@ -39,7 +39,7 @@ fn test_time1_should_be_same_as_time2() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 100 nanosecond: 100
}) })
t2 := new_time(Time{ t2 := new_time(Time{
year: 2000 year: 2000
@ -48,7 +48,7 @@ fn test_time1_should_be_same_as_time2() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 100 nanosecond: 100
}) })
assert t1 == t2 assert t1 == t2
} }
@ -61,9 +61,9 @@ fn test_time1_should_not_be_same_as_time2() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 100 nanosecond: 100
}) })
// Difference is one microsecond // Difference is one nanosecond
t2 := new_time(Time{ t2 := new_time(Time{
year: 2000 year: 2000
month: 5 month: 5
@ -71,7 +71,7 @@ fn test_time1_should_not_be_same_as_time2() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 101 nanosecond: 101
}) })
t3 := new_time(Time{ t3 := new_time(Time{
year: 2000 year: 2000
@ -80,7 +80,7 @@ fn test_time1_should_not_be_same_as_time2() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 0 nanosecond: 0
}) })
// Difference is one second // Difference is one second
t4 := new_time(Time{ t4 := new_time(Time{
@ -90,7 +90,7 @@ fn test_time1_should_not_be_same_as_time2() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 4 second: 4
microsecond: 0 nanosecond: 0
}) })
assert t1 != t2 assert t1 != t2
assert t3 != t4 assert t3 != t4
@ -104,9 +104,9 @@ fn test_time1_should_be_greater_than_time2() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 102 nanosecond: 102
}) })
// Difference is one microsecond // Difference is one nanosecond
t2 := new_time(Time{ t2 := new_time(Time{
year: 2000 year: 2000
month: 5 month: 5
@ -114,7 +114,7 @@ fn test_time1_should_be_greater_than_time2() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 101 nanosecond: 101
}) })
t3 := new_time(Time{ t3 := new_time(Time{
year: 2000 year: 2000
@ -123,7 +123,7 @@ fn test_time1_should_be_greater_than_time2() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 5 second: 5
microsecond: 0 nanosecond: 0
}) })
// Difference is one second // Difference is one second
t4 := new_time(Time{ t4 := new_time(Time{
@ -133,7 +133,7 @@ fn test_time1_should_be_greater_than_time2() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 4 second: 4
microsecond: 0 nanosecond: 0
}) })
assert t1 > t2 assert t1 > t2
assert t3 > t4 assert t3 > t4
@ -147,9 +147,9 @@ fn test_time2_should_be_less_than_time1() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 102 nanosecond: 102
}) })
// Difference is one microsecond // Difference is one nanosecond
t2 := new_time(Time{ t2 := new_time(Time{
year: 2000 year: 2000
month: 5 month: 5
@ -157,7 +157,7 @@ fn test_time2_should_be_less_than_time1() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 101 nanosecond: 101
}) })
t3 := new_time(Time{ t3 := new_time(Time{
year: 2000 year: 2000
@ -166,7 +166,7 @@ fn test_time2_should_be_less_than_time1() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 0 nanosecond: 0
}) })
// Difference is one second // Difference is one second
t4 := new_time(Time{ t4 := new_time(Time{
@ -176,7 +176,7 @@ fn test_time2_should_be_less_than_time1() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 2 second: 2
microsecond: 0 nanosecond: 0
}) })
assert t2 < t1 assert t2 < t1
assert t4 < t3 assert t4 < t3
@ -190,9 +190,9 @@ fn test_time1_should_be_greater_or_equal_to_time2_when_gt() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 102 nanosecond: 102
}) })
// Difference is one microsecond // Difference is one nanosecond
t2 := new_time(Time{ t2 := new_time(Time{
year: 2000 year: 2000
month: 5 month: 5
@ -200,7 +200,7 @@ fn test_time1_should_be_greater_or_equal_to_time2_when_gt() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 101 nanosecond: 101
}) })
t3 := new_time(Time{ t3 := new_time(Time{
year: 2000 year: 2000
@ -209,7 +209,7 @@ fn test_time1_should_be_greater_or_equal_to_time2_when_gt() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 5 second: 5
microsecond: 0 nanosecond: 0
}) })
// Difference is one second // Difference is one second
t4 := new_time(Time{ t4 := new_time(Time{
@ -219,7 +219,7 @@ fn test_time1_should_be_greater_or_equal_to_time2_when_gt() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 4 second: 4
microsecond: 0 nanosecond: 0
}) })
assert t1 >= t2 assert t1 >= t2
assert t3 >= t4 assert t3 >= t4
@ -233,9 +233,9 @@ fn test_time1_should_be_greater_or_equal_to_time2_when_eq() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 100 nanosecond: 100
}) })
// Difference is one microsecond // Difference is one nanosecond
t2 := new_time(Time{ t2 := new_time(Time{
year: 2000 year: 2000
month: 5 month: 5
@ -243,7 +243,7 @@ fn test_time1_should_be_greater_or_equal_to_time2_when_eq() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 100 nanosecond: 100
}) })
t3 := new_time(Time{ t3 := new_time(Time{
year: 2000 year: 2000
@ -252,7 +252,7 @@ fn test_time1_should_be_greater_or_equal_to_time2_when_eq() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 0 nanosecond: 0
}) })
// Difference is one second // Difference is one second
t4 := new_time(Time{ t4 := new_time(Time{
@ -262,7 +262,7 @@ fn test_time1_should_be_greater_or_equal_to_time2_when_eq() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 0 nanosecond: 0
}) })
assert t1 >= t2 assert t1 >= t2
assert t3 >= t4 assert t3 >= t4
@ -276,9 +276,9 @@ fn test_time1_should_be_less_or_equal_to_time2_when_lt() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 100 nanosecond: 100
}) })
// Difference is one microsecond // Difference is one nanosecond
t2 := new_time(Time{ t2 := new_time(Time{
year: 2000 year: 2000
month: 5 month: 5
@ -286,7 +286,7 @@ fn test_time1_should_be_less_or_equal_to_time2_when_lt() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 101 nanosecond: 101
}) })
t3 := new_time(Time{ t3 := new_time(Time{
year: 2000 year: 2000
@ -295,7 +295,7 @@ fn test_time1_should_be_less_or_equal_to_time2_when_lt() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 0 nanosecond: 0
}) })
// Difference is one second // Difference is one second
t4 := new_time(Time{ t4 := new_time(Time{
@ -305,7 +305,7 @@ fn test_time1_should_be_less_or_equal_to_time2_when_lt() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 4 second: 4
microsecond: 0 nanosecond: 0
}) })
assert t1 <= t2 assert t1 <= t2
assert t3 <= t4 assert t3 <= t4
@ -319,9 +319,9 @@ fn test_time1_should_be_less_or_equal_to_time2_when_eq() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 100 nanosecond: 100
}) })
// Difference is one microsecond // Difference is one nanosecond
t2 := new_time(Time{ t2 := new_time(Time{
year: 2000 year: 2000
month: 5 month: 5
@ -329,7 +329,7 @@ fn test_time1_should_be_less_or_equal_to_time2_when_eq() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 100 nanosecond: 100
}) })
t3 := new_time(Time{ t3 := new_time(Time{
year: 2000 year: 2000
@ -338,7 +338,7 @@ fn test_time1_should_be_less_or_equal_to_time2_when_eq() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 0 nanosecond: 0
}) })
// Difference is one second // Difference is one second
t4 := new_time(Time{ t4 := new_time(Time{
@ -348,7 +348,7 @@ fn test_time1_should_be_less_or_equal_to_time2_when_eq() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 0 nanosecond: 0
}) })
assert t1 <= t2 assert t1 <= t2
assert t3 <= t4 assert t3 <= t4
@ -362,7 +362,7 @@ fn test_time2_copied_from_time1_should_be_equal() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 100 nanosecond: 100
}) })
t2 := new_time(t1) t2 := new_time(t1)
assert t2 == t1 assert t2 == t1
@ -370,8 +370,8 @@ fn test_time2_copied_from_time1_should_be_equal() {
fn test_subtract() { fn test_subtract() {
d_seconds := 3 d_seconds := 3
d_microseconds := 13 d_nanoseconds := 13
duration := d_seconds * second + d_microseconds * microsecond duration := d_seconds * second + d_nanoseconds * nanosecond
t1 := new_time(Time{ t1 := new_time(Time{
year: 2000 year: 2000
month: 5 month: 5
@ -379,9 +379,9 @@ fn test_subtract() {
hour: 22 hour: 22
minute: 11 minute: 11
second: 3 second: 3
microsecond: 100 nanosecond: 100
}) })
t2 := unix2(i64(t1.unix) + d_seconds, t1.microsecond + d_microseconds) t2 := unix_nanosecond(i64(t1.unix) + d_seconds, t1.nanosecond + d_nanoseconds)
d1 := t2 - t1 d1 := t2 - t1
d2 := t1 - t2 d2 := t1 - t2
assert d1 > 0 assert d1 > 0

View File

@ -35,13 +35,13 @@ pub fn parse_rfc3339(s string) !Time {
} }
// Check if sn is time only // Check if sn is time only
if !parts[0].contains('-') && parts[0].contains(':') { if !parts[0].contains('-') && parts[0].contains(':') {
mut hour_, mut minute_, mut second_, mut microsecond_, mut unix_offset, mut is_local_time := 0, 0, 0, 0, i64(0), true mut hour_, mut minute_, mut second_, mut microsecond_, mut nanosecond_, mut unix_offset, mut is_local_time := 0, 0, 0, 0, 0, i64(0), true
hour_, minute_, second_, microsecond_, unix_offset, is_local_time = parse_iso8601_time(parts[0])! hour_, minute_, second_, microsecond_, nanosecond_, unix_offset, is_local_time = parse_iso8601_time(parts[0])!
t = new_time(Time{ t = new_time(Time{
hour: hour_ hour: hour_
minute: minute_ minute: minute_
second: second_ second: second_
microsecond: microsecond_ nanosecond: nanosecond_
}) })
if is_local_time { if is_local_time {
return t // Time is already local time return t // Time is already local time
@ -52,7 +52,7 @@ pub fn parse_rfc3339(s string) !Time {
} else if unix_offset > 0 { } else if unix_offset > 0 {
unix_time += unix_offset unix_time += unix_offset
} }
t = unix2(i64(unix_time), t.microsecond) t = unix_nanosecond(i64(unix_time), t.nanosecond)
return t return t
} }
@ -171,9 +171,9 @@ pub fn parse_iso8601(s string) !Time {
return error_invalid_time(12, 'malformed date') return error_invalid_time(12, 'malformed date')
} }
year, month, day := parse_iso8601_date(parts[0])! year, month, day := parse_iso8601_date(parts[0])!
mut hour_, mut minute_, mut second_, mut microsecond_, mut unix_offset, mut is_local_time := 0, 0, 0, 0, i64(0), true mut hour_, mut minute_, mut second_, mut microsecond_, mut nanosecond_, mut unix_offset, mut is_local_time := 0, 0, 0, 0, 0, i64(0), true
if parts.len == 2 { if parts.len == 2 {
hour_, minute_, second_, microsecond_, unix_offset, is_local_time = parse_iso8601_time(parts[1])! hour_, minute_, second_, microsecond_, nanosecond_, unix_offset, is_local_time = parse_iso8601_time(parts[1])!
} }
mut t := new_time( mut t := new_time(
year: year year: year
@ -182,7 +182,7 @@ pub fn parse_iso8601(s string) !Time {
hour: hour_ hour: hour_
minute: minute_ minute: minute_
second: second_ second: second_
microsecond: microsecond_ nanosecond: nanosecond_
) )
if is_local_time { if is_local_time {
return t // Time already local time return t // Time already local time
@ -193,7 +193,7 @@ pub fn parse_iso8601(s string) !Time {
} else if unix_offset > 0 { } else if unix_offset > 0 {
unix_time += unix_offset unix_time += unix_offset
} }
t = unix2(i64(unix_time), t.microsecond) t = unix_nanosecond(i64(unix_time), t.nanosecond)
return t return t
} }
@ -237,7 +237,7 @@ fn parse_iso8601_date(s string) !(int, int, int) {
return year, month, day return year, month, day
} }
fn parse_iso8601_time(s string) !(int, int, int, int, i64, bool) { fn parse_iso8601_time(s string) !(int, int, int, int, int, i64, bool) {
hour_ := 0 hour_ := 0
minute_ := 0 minute_ := 0
second_ := 0 second_ := 0
@ -281,6 +281,7 @@ fn parse_iso8601_time(s string) !(int, int, int, int, i64, bool) {
if count < 4 { if count < 4 {
return error_invalid_time(10, 'malformed date') return error_invalid_time(10, 'malformed date')
} }
nanosecond_ = microsecond_ * 1000
} }
is_local_time := plus_min_z == `a` && count == 4 is_local_time := plus_min_z == `a` && count == 4
is_utc := plus_min_z == `Z` && count == 5 is_utc := plus_min_z == `Z` && count == 5
@ -300,5 +301,6 @@ fn parse_iso8601_time(s string) !(int, int, int, int, i64, bool) {
if plus_min_z == `+` { if plus_min_z == `+` {
unix_offset *= -1 unix_offset *= -1
} }
return hour_, minute_, second_, microsecond_, unix_offset, is_local_time // eprintln('parse_iso8601_time s: $s | hour_: $hour_ | minute_: $minute_ | second_: $second_ | microsecond_: $microsecond_ | nanosecond_: $nanosecond_ | unix_offset: $unix_offset | is_local_time: $is_local_time')
return hour_, minute_, second_, microsecond_, nanosecond_, unix_offset, is_local_time
} }

View File

@ -65,11 +65,11 @@ fn test_parse_iso8601() {
] ]
times := [ times := [
[2020, 6, 5, 15, 38, 6, 0], [2020, 6, 5, 15, 38, 6, 0],
[2020, 6, 5, 15, 38, 6, 15959], [2020, 6, 5, 15, 38, 6, 15959000],
[2020, 6, 5, 15, 38, 6, 15959], [2020, 6, 5, 15, 38, 6, 15959000],
[2020, 6, 5, 13, 38, 6, 15959], [2020, 6, 5, 13, 38, 6, 15959000],
[2020, 6, 5, 17, 38, 6, 15959], [2020, 6, 5, 17, 38, 6, 15959000],
[2020, 11, 5, 15, 38, 6, 15959], [2020, 11, 5, 15, 38, 6, 15959000],
] ]
for i, format in formats { for i, format in formats {
t := time.parse_iso8601(format) or { t := time.parse_iso8601(format) or {
@ -89,8 +89,8 @@ fn test_parse_iso8601() {
assert t.minute == minute assert t.minute == minute
second := times[i][5] second := times[i][5]
assert t.second == second assert t.second == second
microsecond := times[i][6] nanosecond := times[i][6]
assert t.microsecond == microsecond assert t.nanosecond == nanosecond
} }
} }
@ -107,7 +107,7 @@ fn test_parse_iso8601_local() {
assert t.hour == 15 assert t.hour == 15
assert t.minute == 38 assert t.minute == 38
assert t.second == 6 assert t.second == 6
assert t.microsecond == 15959 assert t.nanosecond == 15959_000
} }
fn test_parse_iso8601_invalid() { fn test_parse_iso8601_invalid() {
@ -145,7 +145,7 @@ fn test_parse_iso8601_date_only() {
assert t.hour == 0 assert t.hour == 0
assert t.minute == 0 assert t.minute == 0
assert t.second == 0 assert t.second == 0
assert t.microsecond == 0 assert t.nanosecond == 0
} }
fn check_invalid_date(s string) { fn check_invalid_date(s string) {

View File

@ -53,13 +53,6 @@ pub fn utc() Time {
return solaris_utc() return solaris_utc()
} }
return linux_utc() return linux_utc()
/*
// defaults to most common feature, the microsecond precision is not available
// in this API call
t := C.time(0)
_ = C.time(&t)
return unix2(i64(t), 0)
*/
} }
// new_time returns a time struct with the calculated Unix time. // new_time returns a time struct with the calculated Unix time.
@ -90,7 +83,7 @@ pub fn ticks() i64 {
} $else { } $else {
ts := C.timeval{} ts := C.timeval{}
C.gettimeofday(&ts, 0) C.gettimeofday(&ts, 0)
return i64(ts.tv_sec * u64(1000) + (ts.tv_usec / u64(1000))) return i64(ts.tv_sec * u64(1000) + (ts.tv_usec / u64(1_000)))
} }
// t := i64(C.mach_absolute_time()) // t := i64(C.mach_absolute_time())
// # Nanoseconds elapsedNano = AbsoluteToNanoseconds( *(AbsoluteTime *) &t ); // # Nanoseconds elapsedNano = AbsoluteToNanoseconds( *(AbsoluteTime *) &t );
@ -105,7 +98,7 @@ pub fn (t Time) str() string {
} }
// 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, nanosecond int) Time {
return Time{ return Time{
year: t.tm_year + 1900 year: t.tm_year + 1900
month: t.tm_mon + 1 month: t.tm_mon + 1
@ -113,7 +106,7 @@ fn convert_ctime(t C.tm, microsecond int) Time {
hour: t.tm_hour hour: t.tm_hour
minute: t.tm_min minute: t.tm_min
second: t.tm_sec second: t.tm_sec
microsecond: microsecond nanosecond: nanosecond
unix: make_unix_time(t) unix: make_unix_time(t)
// for the actual code base when we // for the actual code base when we
// call convert_ctime, it is always // call convert_ctime, it is always

View File

@ -46,9 +46,11 @@ pub:
hour int hour int
minute int minute int
second int second int
microsecond int nanosecond int
unix i64 unix i64
is_local bool // used to make time.now().local().local() == time.now().local() is_local bool // used to make time.now().local().local() == time.now().local()
//
microsecond int [deprecated: 'use t.nanosecond / 1000 instead'; deprecated_after: '2023-08-05']
} }
// FormatDelimiter contains different time formats. // FormatDelimiter contains different time formats.
@ -59,6 +61,7 @@ pub enum FormatTime {
hhmmss24 hhmmss24
hhmmss24_milli hhmmss24_milli
hhmmss24_micro hhmmss24_micro
hhmmss24_nano
no_time no_time
} }
@ -99,7 +102,7 @@ pub fn (t Time) smonth() string {
return time.months_string[i * 3..(i + 1) * 3] return time.months_string[i * 3..(i + 1) * 3]
} }
// unix_time returns the UNIX time. // unix_time returns the UNIX time with second resolution.
[inline] [inline]
pub fn (t Time) unix_time() i64 { pub fn (t Time) unix_time() i64 {
return t.unix return t.unix
@ -108,18 +111,39 @@ pub fn (t Time) unix_time() i64 {
// unix_time_milli returns the UNIX time with millisecond resolution. // unix_time_milli returns the UNIX time with millisecond resolution.
[inline] [inline]
pub fn (t Time) unix_time_milli() i64 { pub fn (t Time) unix_time_milli() i64 {
return t.unix * 1000 + (t.microsecond / 1000) return t.unix * 1_000 + (i64(t.nanosecond) / 1_000_000)
}
// unix_time_micro returns the UNIX time with microsecond resolution.
[inline]
pub fn (t Time) unix_time_micro() i64 {
return t.unix * 1_000_000 + (i64(t.nanosecond) / 1_000)
}
// unix_time_nano returns the UNIX time with nanosecond resolution.
[inline]
pub fn (t Time) unix_time_nano() i64 {
// TODO: use i128 here, when V supports it, since the following expression overflows for years like 3001:
return t.unix * 1_000_000_000 + i64(t.nanosecond)
} }
// add returns a new time with the given duration added. // add returns a new time with the given duration added.
pub fn (t Time) add(d Duration) Time { pub fn (t Time) add(d Duration) Time {
microseconds := i64(t.unix) * 1_000_000 + t.microsecond + d.microseconds() // This expression overflows i64 for big years (and we do not have i128 yet):
unix := microseconds / 1_000_000 // nanos := t.unix * 1_000_000_000 + i64(t.nanosecond) <-
micro := microseconds % 1_000_000 // ... so instead, handle the addition manually in parts ¯\_(ツ)_/¯
if t.is_local { mut unixs := t.unix
return unix2(unix, int(micro)).as_local() mut nanos := i64(t.nanosecond) + d.nanoseconds()
unixs += nanos / time.second
nanos = nanos % time.second
if nanos < 0 {
unixs--
nanos += time.second
} }
return unix2(unix, int(micro)) if t.is_local {
return unix_nanosecond(unixs, int(nanos)).as_local()
}
return unix_nanosecond(unixs, int(nanos))
} }
// add_seconds returns a new time struct with an added number of seconds. // add_seconds returns a new time struct with an added number of seconds.
@ -311,9 +335,9 @@ pub fn days_in_month(month int, year int) !int {
return res return res
} }
// debug returns detailed breakdown of time (`Time{ year: YYYY month: MM day: dd hour: HH: minute: mm second: ss microsecond: micros unix: unix }`) // debug returns detailed breakdown of time (`Time{ year: YYYY month: MM day: dd hour: HH: minute: mm second: ss nanosecond: nanos unix: unix }`)
pub fn (t Time) debug() string { 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} }' 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} nanosecond: ${t.nanosecond:09} unix: ${t.unix:07} }'
} }
// A lot of these are taken from the Go library. // A lot of these are taken from the Go library.
@ -326,6 +350,7 @@ pub const (
second = Duration(1000 * millisecond) second = Duration(1000 * millisecond)
minute = Duration(60 * second) minute = Duration(60 * second)
hour = Duration(60 * minute) hour = Duration(60 * minute)
// day = Duration(24 * hour)
infinite = Duration(i64(9223372036854775807)) infinite = Duration(i64(9223372036854775807))
) )
@ -348,23 +373,22 @@ pub fn (d Duration) milliseconds() i64 {
// consider all of them in sub-one intervals // consider all of them in sub-one intervals
// seconds returns the duration as a floating point number of seconds. // seconds returns the duration as a floating point number of seconds.
pub fn (d Duration) seconds() f64 { pub fn (d Duration) seconds() f64 {
sec := d / time.second return f64(d) / f64(time.second)
nsec := d % time.second
return f64(sec) + f64(nsec) / time.second
} }
// minutes returns the duration as a floating point number of minutes. // minutes returns the duration as a floating point number of minutes.
pub fn (d Duration) minutes() f64 { pub fn (d Duration) minutes() f64 {
min := d / time.minute return f64(d) / f64(time.minute)
nsec := d % time.minute
return f64(min) + f64(nsec) / time.minute
} }
// hours returns the duration as a floating point number of hours. // hours returns the duration as a floating point number of hours.
pub fn (d Duration) hours() f64 { pub fn (d Duration) hours() f64 {
hr := d / time.hour return f64(d) / f64(time.hour)
nsec := d % time.hour }
return f64(hr) + f64(nsec) / time.hour
// days returns the duration as a floating point number of days.
pub fn (d Duration) days() f64 {
return f64(d) / f64(time.hour * 24)
} }
// str pretty prints the duration // str pretty prints the duration
@ -412,6 +436,35 @@ pub fn (d Duration) str() string {
return '${ns}ns' return '${ns}ns'
} }
// debug returns a detailed breakdown of the Duration, as: 'Duration: - 50days, 4h, 3m, 7s, 541ms, 78us, 9ns'
pub fn (d Duration) debug() string {
mut res := []string{}
mut x := i64(d)
mut sign := ''
if x < 0 {
sign = '- '
x = -x
}
for label, v in {
'days': 24 * time.hour
'h': time.hour
'm': time.minute
's': time.second
'ms': time.millisecond
'us': time.microsecond
} {
if x > v {
xx := x / v
x = x % v
res << xx.str() + label
}
}
if x > 0 {
res << '${x}ns'
}
return 'Duration: ${sign}${res.join(', ')}'
}
// offset returns time zone UTC offset in seconds. // offset returns time zone UTC offset in seconds.
pub fn offset() int { pub fn offset() int {
t := utc() t := utc()

View File

@ -3,8 +3,6 @@ import time
fn test_add_to_day_in_the_previous_century() { fn test_add_to_day_in_the_previous_century() {
a := time.parse_iso8601('1900-01-01')! a := time.parse_iso8601('1900-01-01')!
aa := a.add_days(180) aa := a.add_days(180)
dump(a.debug())
dump(aa.debug())
assert aa.ymmdd() == '1900-06-30' assert aa.ymmdd() == '1900-06-30'
} }
@ -23,6 +21,8 @@ fn test_add_to_day_in_the_recent_past() {
fn test_add_to_day_in_the_future_1() { fn test_add_to_day_in_the_future_1() {
a := time.parse_iso8601('3000-11-01')! a := time.parse_iso8601('3000-11-01')!
aa := a.add_days(180) aa := a.add_days(180)
dump(a.debug())
dump(aa.debug())
assert aa.ymmdd() == '3001-04-30' assert aa.ymmdd() == '3001-04-30'
} }

View File

@ -2,11 +2,10 @@ module time
#include <mach/mach_time.h> #include <mach/mach_time.h>
const (
// start_time is needed on Darwin and Windows because of potential overflows // start_time is needed on Darwin and Windows because of potential overflows
start_time = C.mach_absolute_time() const start_time = C.mach_absolute_time()
time_base = init_time_base()
) const time_base = init_time_base()
[typedef] [typedef]
struct C.mach_timebase_info_data_t { struct C.mach_timebase_info_data_t {
@ -25,11 +24,6 @@ struct InternalTimeBase {
denom u32 = 1 denom u32 = 1
} }
pub struct C.timeval {
tv_sec u64
tv_usec u64
}
fn init_time_base() C.mach_timebase_info_data_t { fn init_time_base() C.mach_timebase_info_data_t {
tb := C.mach_timebase_info_data_t{} tb := C.mach_timebase_info_data_t{}
C.mach_timebase_info(&tb) C.mach_timebase_info(&tb)
@ -62,29 +56,22 @@ fn vpc_now_darwin() u64 {
return (tm - time.start_time) * time.time_base.numer / time.time_base.denom return (tm - time.start_time) * time.time_base.numer / time.time_base.denom
} }
// darwin_now returns a better precision current time for Darwin based operating system // darwin_now returns a better precision current time for macos
// this should be implemented with native system calls eventually
// but for now a bit tweaky. It uses the deprecated gettimeofday clock to get
// the microseconds seconds part and converts to local time
fn darwin_now() Time { fn darwin_now() Time {
// get the high precision time as UTC clock // get the high precision time as UTC realtime clock, and use the nanoseconds part
tv := C.timeval{} mut ts := C.timespec{}
C.gettimeofday(&tv, 0) C.clock_gettime(C.CLOCK_REALTIME, &ts)
loc_tm := C.tm{} loc_tm := C.tm{}
asec := voidptr(&tv.tv_sec) C.localtime_r(voidptr(&ts.tv_sec), &loc_tm)
C.localtime_r(asec, &loc_tm) return convert_ctime(loc_tm, int(ts.tv_nsec))
return convert_ctime(loc_tm, int(tv.tv_usec))
} }
// darwin_utc returns a better precision current time for Darwin based operating system // darwin_utc returns a better precision current time for macos
// this should be implemented with native system calls eventually
// but for now a bit tweaky. It uses the deprecated gettimeofday clock to get
// the microseconds seconds part and normal local time to get correct local time
fn darwin_utc() Time { fn darwin_utc() Time {
// get the high precision time as UTC clock // get the high precision time as UTC clock
tv := C.timeval{} mut ts := C.timespec{}
C.gettimeofday(&tv, 0) C.clock_gettime(C.CLOCK_REALTIME, &ts)
return unix2(i64(tv.tv_sec), int(tv.tv_usec)) return unix_nanosecond(i64(ts.tv_sec), int(ts.tv_nsec))
} }
// dummy to compile with all compilers // dummy to compile with all compilers

View File

@ -36,7 +36,7 @@ pub fn (t Time) local() Time {
} }
loc_tm := C.tm{} loc_tm := C.tm{}
C.localtime_r(voidptr(&t.unix), &loc_tm) C.localtime_r(voidptr(&t.unix), &loc_tm)
return convert_ctime(loc_tm, t.microsecond) return convert_ctime(loc_tm, t.nanosecond)
} }
// in most systems, these are __quad_t, which is an i64 // in most systems, these are __quad_t, which is an i64
@ -58,7 +58,7 @@ pub fn sys_mono_now() u64 {
} $else { } $else {
ts := C.timespec{} ts := C.timespec{}
C.clock_gettime(C.CLOCK_MONOTONIC, &ts) C.clock_gettime(C.CLOCK_MONOTONIC, &ts)
return u64(ts.tv_sec) * 1000000000 + u64(ts.tv_nsec) return u64(ts.tv_sec) * 1_000_000_000 + u64(ts.tv_nsec)
} }
} }
@ -68,7 +68,7 @@ pub fn sys_mono_now() u64 {
fn vpc_now() u64 { fn vpc_now() u64 {
ts := C.timespec{} ts := C.timespec{}
C.clock_gettime(C.CLOCK_MONOTONIC, &ts) C.clock_gettime(C.CLOCK_MONOTONIC, &ts)
return u64(ts.tv_sec) * 1000000000 + u64(ts.tv_nsec) return u64(ts.tv_sec) * 1_000_000_000 + u64(ts.tv_nsec)
} }
// The linux_* functions are placed here, since they're used on Android as well // The linux_* functions are placed here, since they're used on Android as well
@ -83,7 +83,7 @@ fn linux_now() Time {
C.clock_gettime(C.CLOCK_REALTIME, &ts) C.clock_gettime(C.CLOCK_REALTIME, &ts)
loc_tm := C.tm{} loc_tm := C.tm{}
C.localtime_r(voidptr(&ts.tv_sec), &loc_tm) C.localtime_r(voidptr(&ts.tv_sec), &loc_tm)
return convert_ctime(loc_tm, int(ts.tv_nsec / 1000)) return convert_ctime(loc_tm, int(ts.tv_nsec))
} }
fn linux_utc() Time { fn linux_utc() Time {
@ -91,7 +91,7 @@ fn linux_utc() Time {
// and use the nanoseconds part // and use the nanoseconds part
mut ts := C.timespec{} mut ts := C.timespec{}
C.clock_gettime(C.CLOCK_REALTIME, &ts) C.clock_gettime(C.CLOCK_REALTIME, &ts)
return unix2(i64(ts.tv_sec), int(ts.tv_nsec / 1000)) return unix_nanosecond(i64(ts.tv_sec), int(ts.tv_nsec))
} }
// dummy to compile with all compilers // dummy to compile with all compilers
@ -104,12 +104,6 @@ fn win_utc() Time {
return Time{} return Time{}
} }
// dummy to compile with all compilers
pub struct C.timeval {
tv_sec u64
tv_usec u64
}
// return absolute timespec for now()+d // return absolute timespec for now()+d
pub fn (d Duration) timespec() C.timespec { pub fn (d Duration) timespec() C.timespec {
mut ts := C.timespec{} mut ts := C.timespec{}

View File

@ -10,7 +10,7 @@ fn solaris_now() Time {
C.clock_gettime(C.CLOCK_REALTIME, &ts) C.clock_gettime(C.CLOCK_REALTIME, &ts)
loc_tm := C.tm{} loc_tm := C.tm{}
C.localtime_r(voidptr(&ts.tv_sec), &loc_tm) C.localtime_r(voidptr(&ts.tv_sec), &loc_tm)
return convert_ctime(loc_tm, int(ts.tv_nsec / 1000)) return convert_ctime(loc_tm, int(ts.tv_nsec))
} }
fn solaris_utc() Time { fn solaris_utc() Time {
@ -18,7 +18,7 @@ fn solaris_utc() Time {
// and use the nanoseconds part // and use the nanoseconds part
mut ts := C.timespec{} mut ts := C.timespec{}
C.clock_gettime(C.CLOCK_REALTIME, &ts) C.clock_gettime(C.CLOCK_REALTIME, &ts)
return unix2(i64(ts.tv_sec), int(ts.tv_nsec / 1000)) return unix_nanosecond(i64(ts.tv_sec), int(ts.tv_nsec))
} }
// dummy to compile with all compilers // dummy to compile with all compilers

View File

@ -1,18 +1,16 @@
import time import time
import math import math
const ( const time_to_test = time.Time{
time_to_test = time.Time{
year: 1980 year: 1980
month: 7 month: 7
day: 11 day: 11
hour: 21 hour: 21
minute: 23 minute: 23
second: 42 second: 42
microsecond: 123456 nanosecond: 123456789
unix: 332198622 unix: 332198622
} }
)
fn test_is_leap_year() { fn test_is_leap_year() {
// 1996 % 4 = 0 and 1996 % 100 > 0 // 1996 % 4 = 0 and 1996 % 100 > 0
@ -83,6 +81,14 @@ fn test_unix() {
assert t6.second == 29 assert t6.second == 29
} }
fn test_format_rfc3339() {
// assert '1980-07-11T19:23:42.123Z'
res := time_to_test.format_rfc3339()
assert res.ends_with('23:42.123Z')
assert res.starts_with('1980-07-1')
assert res.contains('T')
}
fn test_format_ss() { fn test_format_ss() {
assert '11.07.1980 21:23:42' == time_to_test.get_fmt_str(.dot, .hhmmss24, .ddmmyyyy) assert '11.07.1980 21:23:42' == time_to_test.get_fmt_str(.dot, .hhmmss24, .ddmmyyyy)
} }
@ -93,20 +99,18 @@ fn test_format_ss_milli() {
assert '1980-07-11 21:23:42.123' == time_to_test.format_ss_milli() assert '1980-07-11 21:23:42.123' == time_to_test.format_ss_milli()
} }
fn test_format_rfc3339() {
// assert '1980-07-11T19:23:42.123Z'
res := time_to_test.format_rfc3339()
assert res.ends_with('23:42.123Z')
assert res.starts_with('1980-07-1')
assert res.contains('T')
}
fn test_format_ss_micro() { fn test_format_ss_micro() {
assert '11.07.1980 21:23:42.123456' == time_to_test.get_fmt_str(.dot, .hhmmss24_micro, assert '11.07.1980 21:23:42.123456' == time_to_test.get_fmt_str(.dot, .hhmmss24_micro,
.ddmmyyyy) .ddmmyyyy)
assert '1980-07-11 21:23:42.123456' == time_to_test.format_ss_micro() assert '1980-07-11 21:23:42.123456' == time_to_test.format_ss_micro()
} }
fn test_format_ss_nano() {
assert '11.07.1980 21:23:42.123456789' == time_to_test.get_fmt_str(.dot, .hhmmss24_nano,
.ddmmyyyy)
assert '1980-07-11 21:23:42.123456789' == time_to_test.format_ss_nano()
}
fn test_smonth() { fn test_smonth() {
month_names := ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', month_names := ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov',
'Dec'] 'Dec']
@ -180,21 +184,29 @@ fn test_weekday_str() {
fn test_add() { fn test_add() {
d_seconds := 3 d_seconds := 3
d_microseconds := 13 d_nanoseconds := 13
duration := time.Duration(d_seconds * time.second + d_microseconds * time.microsecond) duration := time.Duration(d_seconds * time.second + d_nanoseconds * time.nanosecond)
// dump(duration.debug())
t1 := time_to_test t1 := time_to_test
// dump(t1.debug())
t2 := time_to_test.add(duration) t2 := time_to_test.add(duration)
// dump(t2.debug())
assert t2.second == t1.second + d_seconds assert t2.second == t1.second + d_seconds
assert t2.microsecond == t1.microsecond + d_microseconds assert t2.nanosecond == t1.nanosecond + d_nanoseconds
assert t2.unix == t1.unix + d_seconds assert t2.unix == t1.unix + d_seconds
assert t2.is_local == t1.is_local assert t2.is_local == t1.is_local
//
t3 := time_to_test.add(-duration) t3 := time_to_test.add(-duration)
// dump(t3.debug())
assert t3.second == t1.second - d_seconds assert t3.second == t1.second - d_seconds
assert t3.microsecond == t1.microsecond - d_microseconds assert t3.nanosecond == t1.nanosecond - d_nanoseconds
assert t3.unix == t1.unix - d_seconds assert t3.unix == t1.unix - d_seconds
assert t3.is_local == t1.is_local assert t3.is_local == t1.is_local
//
t4 := time_to_test.as_local() t4 := time_to_test.as_local()
// dump(t4.debug())
t5 := t4.add(duration) t5 := t4.add(duration)
// dump(t5.debug())
assert t5.is_local == t4.is_local assert t5.is_local == t4.is_local
} }
@ -220,13 +232,14 @@ fn test_now() {
assert now.minute < 60 assert now.minute < 60
assert now.second >= 0 assert now.second >= 0
assert now.second <= 60 // <= 60 cause of leap seconds assert now.second <= 60 // <= 60 cause of leap seconds
assert now.microsecond >= 0 assert now.nanosecond >= 0
assert now.microsecond < 1000000 assert now.nanosecond < time.second
} }
fn test_utc() { fn test_utc() {
now := time.utc() now := time.utc()
// The year the test was built // The year the test was built
// dump(now.debug())
assert now.year >= 2020 assert now.year >= 2020
assert now.month > 0 assert now.month > 0
assert now.month <= 12 assert now.month <= 12
@ -234,8 +247,8 @@ fn test_utc() {
assert now.minute < 60 assert now.minute < 60
assert now.second >= 0 assert now.second >= 0
assert now.second <= 60 // <= 60 cause of leap seconds assert now.second <= 60 // <= 60 cause of leap seconds
assert now.microsecond >= 0 assert now.nanosecond >= 0
assert now.microsecond < 1000000 assert now.nanosecond < time.second
} }
fn test_unix_time() { fn test_unix_time() {

View File

@ -39,6 +39,8 @@ fn C.SystemTimeToTzSpecificLocalTime(lpTimeZoneInformation &C.TIME_ZONE_INFORMAT
fn C.localtime_s(t &C.time_t, tm &C.tm) fn C.localtime_s(t &C.time_t, tm &C.tm)
fn C.timespec_get(t &C.timespec, base int) int
const ( const (
// start_time is needed on Darwin and Windows because of potential overflows // start_time is needed on Darwin and Windows because of potential overflows
start_time = init_win_time_start() start_time = init_win_time_start()
@ -107,7 +109,7 @@ pub fn (t Time) local() Time {
hour: u16(t.hour) hour: u16(t.hour)
minute: u16(t.minute) minute: u16(t.minute)
second: u16(t.second) second: u16(t.second)
millisecond: u16(t.microsecond / 1000) millisecond: u16(t.nanosecond / 1_000_000)
} }
st_local := SystemTime{} st_local := SystemTime{}
C.SystemTimeToTzSpecificLocalTime(unsafe { nil }, &st_utc, &st_local) C.SystemTimeToTzSpecificLocalTime(unsafe { nil }, &st_utc, &st_local)
@ -118,7 +120,7 @@ pub fn (t Time) local() Time {
hour: st_local.hour hour: st_local.hour
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: int(st_local.millisecond) * 1000 nanosecond: int(st_local.millisecond) * 1_000_000
unix: st_local.unix_time() unix: st_local.unix_time()
} }
return t_local return t_local
@ -141,7 +143,7 @@ fn win_now() Time {
hour: st_local.hour hour: st_local.hour
minute: st_local.minute minute: st_local.minute
second: st_local.second second: st_local.second
microsecond: int(st_local.millisecond) * 1000 nanosecond: int(st_local.millisecond) * 1_000_000
unix: st_local.unix_time() unix: st_local.unix_time()
is_local: true is_local: true
} }
@ -163,7 +165,7 @@ fn win_utc() Time {
hour: st_utc.hour hour: st_utc.hour
minute: st_utc.minute minute: st_utc.minute
second: st_utc.second second: st_utc.second
microsecond: int(st_utc.millisecond) * 1000 nanosecond: int(st_utc.millisecond) * 1_000_000
unix: st_utc.unix_time() unix: st_utc.unix_time()
is_local: false is_local: false
} }
@ -213,12 +215,6 @@ fn solaris_utc() Time {
return Time{} return Time{}
} }
// dummy to compile with all compilers
pub struct C.timeval {
tv_sec u64
tv_usec u64
}
// sleep makes the calling thread sleep for a given duration (in nanoseconds). // sleep makes the calling thread sleep for a given duration (in nanoseconds).
pub fn sleep(duration Duration) { pub fn sleep(duration Duration) {
C.Sleep(int(duration / millisecond)) C.Sleep(int(duration / millisecond))

View File

@ -3,7 +3,7 @@
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module time module time
// unix returns a time struct from Unix time. // unix returns a time struct from an Unix timestamp (number of seconds since 1970-01-01)
pub fn unix(abs i64) Time { pub fn unix(abs i64) Time {
// Split into day and time // Split into day and time
mut day_offset := abs / seconds_per_day mut day_offset := abs / seconds_per_day
@ -24,8 +24,20 @@ pub fn unix(abs i64) Time {
} }
} }
// unix2 returns a time struct from Unix time and microsecond value // unix2 returns a Time struct, given an Unix timestamp in seconds, and a microsecond value
[deprecated: 'use unix_microsecond(unix_ts, us) instead']
[deprecated_after: '2023-09-05']
pub fn unix2(abs i64, microsecond int) Time { pub fn unix2(abs i64, microsecond int) Time {
return unix_nanosecond(abs, microsecond * 1000)
}
// unix_microsecond returns a Time struct, given an Unix timestamp in seconds, and a microsecond value
pub fn unix_microsecond(abs i64, microsecond int) Time {
return unix_nanosecond(abs, microsecond * 1000)
}
// unix_nanosecond returns a Time struct, given an Unix timestamp in seconds, and a nanosecond value
pub fn unix_nanosecond(abs i64, nanosecond int) Time {
// Split into day and time // Split into day and time
mut day_offset := abs / seconds_per_day mut day_offset := abs / seconds_per_day
if abs % seconds_per_day < 0 { if abs % seconds_per_day < 0 {
@ -41,7 +53,7 @@ pub fn unix2(abs i64, microsecond int) Time {
hour: hr hour: hr
minute: min minute: min
second: sec second: sec
microsecond: microsecond nanosecond: nanosecond
unix: abs unix: abs
} }
} }