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
 | ||||
| 	logger            &log.Log // logger used to log messages
 | ||||
| 	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
 | ||||
|  |  | |||
|  | @ -747,6 +747,6 @@ fn test_utime() { | |||
| 	f.write_string(hello) or { panic(err) } | ||||
| 	atime := time.now().add_days(2).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 | ||||
| } | ||||
|  |  | |||
|  | @ -275,7 +275,7 @@ const ( | |||
| // users or business transactions.
 | ||||
| // (https://news.ycombinator.com/item?id=14526173)
 | ||||
| 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`.
 | ||||
|  |  | |||
|  | @ -37,7 +37,7 @@ fn test_ulids_max_start_character_is_ok() { | |||
| } | ||||
| 
 | ||||
| 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 ulid2 := '' | ||||
| 	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*.
 | ||||
| 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.
 | ||||
| [inline] | ||||
| pub fn (lhs Time) - (rhs Time) Duration { | ||||
| 	lhs_micro := lhs.unix * 1000 * 1000 + u64(lhs.microsecond) | ||||
| 	rhs_micro := rhs.unix * 1000 * 1000 + u64(rhs.microsecond) | ||||
| 	return (i64(lhs_micro) - i64(rhs_micro)) * microsecond | ||||
| 	lhs_micro := lhs.unix * 1_000_000 + lhs.microsecond | ||||
| 	rhs_micro := rhs.unix * 1_000_000 + rhs.microsecond | ||||
| 	return (lhs_micro - rhs_micro) * microsecond | ||||
| } | ||||
|  |  | |||
|  | @ -131,9 +131,9 @@ pub fn parse_iso8601(s string) ?Time { | |||
| 	} | ||||
| 	mut unix_time := t.unix | ||||
| 	if unix_offset < 0 { | ||||
| 		unix_time -= u64(-unix_offset) | ||||
| 		unix_time -= (-unix_offset) | ||||
| 	} else if unix_offset > 0 { | ||||
| 		unix_time += u64(unix_offset) | ||||
| 		unix_time += unix_offset | ||||
| 	} | ||||
| 	t = unix2(i64(unix_time), t.microsecond) | ||||
| 	return t | ||||
|  |  | |||
|  | @ -50,7 +50,7 @@ pub: | |||
| 	minute      int | ||||
| 	second      int | ||||
| 	microsecond int | ||||
| 	unix        u64 | ||||
| 	unix        i64 | ||||
| } | ||||
| 
 | ||||
| // FormatDelimiter contains different time formats.
 | ||||
|  | @ -162,7 +162,7 @@ pub fn new_time(t Time) Time { | |||
| 		tm_mon: t.month - 1 | ||||
| 		tm_year: t.year - 1900 | ||||
| 	} | ||||
| 	utime := u64(make_unix_time(tt)) | ||||
| 	utime := make_unix_time(tt) | ||||
| 	return Time{ | ||||
| 		...t | ||||
| 		unix: utime | ||||
|  | @ -171,21 +171,21 @@ pub fn new_time(t Time) Time { | |||
| 
 | ||||
| // unix_time returns Unix time.
 | ||||
| [inline] | ||||
| pub fn (t Time) unix_time() int { | ||||
| 	return int(t.unix) | ||||
| pub fn (t Time) unix_time() i64 { | ||||
| 	return t.unix | ||||
| } | ||||
| 
 | ||||
| // unix_time_milli returns Unix time with millisecond resolution.
 | ||||
| [inline] | ||||
| pub fn (t Time) unix_time_milli() u64 { | ||||
| 	return t.unix * 1000 + u64(t.microsecond / 1000) | ||||
| pub fn (t Time) unix_time_milli() i64 { | ||||
| 	return t.unix * 1000 + (t.microsecond / 1000) | ||||
| } | ||||
| 
 | ||||
| // add returns a new time that duration is added
 | ||||
| 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) | ||||
| 	microseconds := i64(t.unix) * 1_000_000 + t.microsecond + d.microseconds() | ||||
| 	unix := microseconds / 1_000_000 | ||||
| 	micro := microseconds % 1_000_000 | ||||
| 	return unix2(unix, int(micro)) | ||||
| } | ||||
| 
 | ||||
|  | @ -358,6 +358,11 @@ pub fn (t Time) str() string { | |||
| 	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.
 | ||||
| fn convert_ctime(t C.tm, microsecond int) Time { | ||||
| 	return Time{ | ||||
|  | @ -368,7 +373,7 @@ fn convert_ctime(t C.tm, microsecond int) Time { | |||
| 		minute: t.tm_min | ||||
| 		second: t.tm_sec | ||||
| 		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.localtime_r(t &time_t, tm &C.tm) | ||||
| 
 | ||||
| fn make_unix_time(t C.tm) int { | ||||
| 	return int(C.timegm(&t)) | ||||
| fn make_unix_time(t C.tm) i64 { | ||||
| 	return i64(C.timegm(&t)) | ||||
| } | ||||
| 
 | ||||
| // local returns t with the location set to local time.
 | ||||
|  |  | |||
|  | @ -160,18 +160,18 @@ fn test_add() { | |||
| 	t2 := time_to_test.add(duration) | ||||
| 	assert t2.second == t1.second + d_seconds | ||||
| 	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) | ||||
| 	assert t3.second == t1.second - d_seconds | ||||
| 	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() { | ||||
| 	num_of_days := 3 | ||||
| 	t := time_to_test.add_days(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() { | ||||
|  | @ -217,8 +217,8 @@ fn test_unix_time() { | |||
| 	//
 | ||||
| 	utm1 := t1.unix_time_milli() | ||||
| 	utm2 := t2.unix_time_milli() | ||||
| 	assert (utm1 - u64(ut1) * 1000) < 1000 | ||||
| 	assert (utm2 - u64(ut2) * 1000) < 1000 | ||||
| 	assert (utm1 - ut1 * 1000) < 1000 | ||||
| 	assert (utm2 - ut2 * 1000) < 1000 | ||||
| 	//
 | ||||
| 	// println('utm1: $utm1 | utm2: $utm2')
 | ||||
| 	assert utm2 - utm1 > 2 | ||||
|  |  | |||
|  | @ -52,14 +52,12 @@ struct C.timespec { | |||
| 	tv_nsec i64 | ||||
| } | ||||
| 
 | ||||
| fn C._mkgmtime(&C.tm) C.time_t | ||||
| 
 | ||||
| fn C.QueryPerformanceCounter(&u64) C.BOOL | ||||
| 
 | ||||
| fn C.QueryPerformanceFrequency(&u64) C.BOOL | ||||
| 
 | ||||
| fn make_unix_time(t C.tm) int { | ||||
| 	return int(C._mkgmtime(&t)) | ||||
| fn make_unix_time(t C.tm) i64 { | ||||
| 	return portable_timegm(&t) | ||||
| } | ||||
| 
 | ||||
| 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
 | ||||
| fn local_as_unix_time() int { | ||||
| fn local_as_unix_time() i64 { | ||||
| 	t := C.time(0) | ||||
| 	tm := C.localtime(&t) | ||||
| 	return make_unix_time(tm) | ||||
|  | @ -117,7 +115,7 @@ pub fn (t Time) local() Time { | |||
| 		minute: st_local.minute | ||||
| 		second: st_local.second // These are the same
 | ||||
| 		microsecond: st_local.millisecond * 1000 | ||||
| 		unix: u64(st_local.unix_time()) | ||||
| 		unix: st_local.unix_time() | ||||
| 	} | ||||
| 	return t_local | ||||
| } | ||||
|  | @ -140,7 +138,7 @@ fn win_now() Time { | |||
| 		minute: st_local.minute | ||||
| 		second: st_local.second | ||||
| 		microsecond: st_local.millisecond * 1000 | ||||
| 		unix: u64(st_local.unix_time()) | ||||
| 		unix: st_local.unix_time() | ||||
| 	} | ||||
| 	return t | ||||
| } | ||||
|  | @ -161,13 +159,13 @@ fn win_utc() Time { | |||
| 		minute: st_utc.minute | ||||
| 		second: st_utc.second | ||||
| 		microsecond: st_utc.millisecond * 1000 | ||||
| 		unix: u64(st_utc.unix_time()) | ||||
| 		unix: st_utc.unix_time() | ||||
| 	} | ||||
| 	return t | ||||
| } | ||||
| 
 | ||||
| // unix_time returns Unix time.
 | ||||
| pub fn (st SystemTime) unix_time() int { | ||||
| pub fn (st SystemTime) unix_time() i64 { | ||||
| 	tt := C.tm{ | ||||
| 		tm_sec: st.second | ||||
| 		tm_min: st.minute | ||||
|  |  | |||
|  | @ -20,7 +20,7 @@ pub fn unix(abs int) Time { | |||
| 		hour: hr | ||||
| 		minute: min | ||||
| 		second: sec | ||||
| 		unix: u64(abs) | ||||
| 		unix: abs | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -42,7 +42,7 @@ pub fn unix2(abs i64, microsecond int) Time { | |||
| 		minute: min | ||||
| 		second: sec | ||||
| 		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 { | ||||
| 	mut files_salt := '' | ||||
| 	mut latest_modified := u64(0) | ||||
| 	mut latest_modified := i64(0) | ||||
| 	for asset in am.get_assets(asset_type) { | ||||
| 		files_salt += asset.file_path | ||||
| 		if asset.last_modified.unix > latest_modified { | ||||
|  | @ -151,7 +151,7 @@ fn (mut am AssetManager) add(asset_type string, file string) bool { | |||
| 	asset := Asset{ | ||||
| 		file_path: file | ||||
| 		last_modified: time.Time{ | ||||
| 			unix: u64(os.file_last_mod_unix(file)) | ||||
| 			unix: os.file_last_mod_unix(file) | ||||
| 		} | ||||
| 	} | ||||
| 	if asset_type == 'css' { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue