diff options
Diffstat (limited to 'v_windows/v/old/vlib/time')
20 files changed, 2449 insertions, 0 deletions
diff --git a/v_windows/v/old/vlib/time/Y2K38_test.v b/v_windows/v/old/vlib/time/Y2K38_test.v new file mode 100644 index 0000000..0ebc0ef --- /dev/null +++ b/v_windows/v/old/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/v_windows/v/old/vlib/time/format.v b/v_windows/v/old/vlib/time/format.v new file mode 100644 index 0000000..6304cbc --- /dev/null +++ b/v_windows/v/old/vlib/time/format.v @@ -0,0 +1,172 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module time + +// format returns a date string in "YYYY-MM-DD HH:MM" format (24h). +pub fn (t Time) format() string { +	return t.get_fmt_str(.hyphen, .hhmm24, .yyyymmdd) +} + +// format_ss returns a date string in "YYYY-MM-DD HH:MM:SS" format (24h). +pub fn (t Time) format_ss() string { +	return t.get_fmt_str(.hyphen, .hhmmss24, .yyyymmdd) +} + +// 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 { +	return t.get_fmt_str(.hyphen, .hhmmss24_milli, .yyyymmdd) +} + +// 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 { +	return t.get_fmt_str(.hyphen, .hhmmss24_micro, .yyyymmdd) +} + +// hhmm returns a date string in "HH:MM" format (24h). +pub fn (t Time) hhmm() string { +	return t.get_fmt_time_str(.hhmm24) +} + +// hhmmss returns a date string in "HH:MM:SS" format (24h). +pub fn (t Time) hhmmss() string { +	return t.get_fmt_time_str(.hhmmss24) +} + +// hhmm12 returns a date string in "HH:MM" format (12h). +pub fn (t Time) hhmm12() string { +	return t.get_fmt_time_str(.hhmm12) +} + +// ymmdd returns a date string in "YYYY-MM-DD" format. +pub fn (t Time) ymmdd() string { +	return t.get_fmt_date_str(.hyphen, .yyyymmdd) +} + +// ddmmy returns a date string in "DD.MM.YYYY" format. +pub fn (t Time) ddmmy() string { +	return t.get_fmt_date_str(.dot, .ddmmyyyy) +} + +// md returns a date string in "MMM D" format. +pub fn (t Time) md() string { +	return t.get_fmt_date_str(.space, .mmmd) +} + +// clean returns a date string in a following format: +// - a date string in "HH:MM" format (24h) for current day +// - a date string in "MMM D HH:MM" format (24h) for date of current year +// - a date string formatted with format function for other dates +pub fn (t Time) clean() string { +	znow := now() +	// Today +	if t.month == znow.month && t.year == znow.year && t.day == znow.day { +		return t.get_fmt_time_str(.hhmm24) +	} +	// This year +	if t.year == znow.year { +		return t.get_fmt_str(.space, .hhmm24, .mmmd) +	} +	return t.format() +} + +// clean12 returns a date string in a following format: +// - a date string in "HH:MM" format (12h) for current day +// - a date string in "MMM D HH:MM" format (12h) for date of current year +// - a date string formatted with format function for other dates +pub fn (t Time) clean12() string { +	znow := now() +	// Today +	if t.month == znow.month && t.year == znow.year && t.day == znow.day { +		return t.get_fmt_time_str(.hhmm12) +	} +	// This year +	if t.year == znow.year { +		return t.get_fmt_str(.space, .hhmm12, .mmmd) +	} +	return t.format() +} + +// get_fmt_time_str returns a date string with specified FormatTime type. +pub fn (t Time) get_fmt_time_str(fmt_time FormatTime) string { +	if fmt_time == .no_time { +		return '' +	} +	tp := if t.hour > 11 { 'p.m.' } else { 'a.m.' } +	hour_ := if t.hour > 12 { +		t.hour - 12 +	} else if t.hour == 0 { +		12 +	} else { +		t.hour +	} +	return match fmt_time { +		.hhmm12 { '$hour_:${t.minute:02d} $tp' } +		.hhmm24 { '${t.hour:02d}:${t.minute:02d}' } +		.hhmmss12 { '$hour_:${t.minute:02d}:${t.second:02d} $tp' } +		.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_micro { '${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${t.microsecond:06d}' } +		else { 'unknown enumeration $fmt_time' } +	} +} + +// get_fmt_time_str returns a date string with specified +// FormatDelimiter and FormatDate type. +pub fn (t Time) get_fmt_date_str(fmt_dlmtr FormatDelimiter, fmt_date FormatDate) string { +	if fmt_date == .no_date { +		return '' +	} +	month := '$t.smonth()' +	year := '${(t.year % 100):02d}' +	mut res := match fmt_date { +		.ddmmyy { '${t.day:02d}|${t.month:02d}|$year' } +		.ddmmyyyy { '${t.day:02d}|${t.month:02d}|${t.year:04d}' } +		.mmddyy { '${t.month:02d}|${t.day:02d}|$year' } +		.mmddyyyy { '${t.month:02d}|${t.day:02d}|${t.year:04d}' } +		.mmmd { '$month|$t.day' } +		.mmmdd { '$month|${t.day:02d}' } +		.mmmddyy { '$month|${t.day:02d}|$year' } +		.mmmddyyyy { '$month|${t.day:02d}|${t.year:04d}' } +		.yyyymmdd { '${t.year:04d}|${t.month:02d}|${t.day:02d}' } +		.yymmdd { '$year|${t.month:02d}|${t.day:02d}' } +		else { 'unknown enumeration $fmt_date' } +	} +	del := match fmt_dlmtr { +		.dot { '.' } +		.hyphen { '-' } +		.slash { '/' } +		.space { ' ' } +		.no_delimiter { '' } +	} +	res = res.replace('|', del) +	return res +} + +// get_fmt_str returns a date string with specified FormatDelimiter, +// FormatTime type, and FormatDate type. +pub fn (t Time) get_fmt_str(fmt_dlmtr FormatDelimiter, fmt_time FormatTime, fmt_date FormatDate) string { +	if fmt_date == .no_date { +		if fmt_time == .no_time { +			// saving one function call although it's checked in +			// t.get_fmt_time_str(fmt_time) in the beginning +			return '' +		} else { +			return t.get_fmt_time_str(fmt_time) +		} +	} else { +		if fmt_time != .no_time { +			return t.get_fmt_date_str(fmt_dlmtr, fmt_date) + ' ' + t.get_fmt_time_str(fmt_time) +		} else { +			return t.get_fmt_date_str(fmt_dlmtr, fmt_date) +		} +	} +} + +// This is just a TEMPORARY function for cookies and their expire dates +pub fn (t Time) utc_string() string { +	day_str := t.weekday_str() +	month_str := t.smonth() +	utc_string := '$day_str, $t.day $month_str $t.year ${t.hour:02d}:${t.minute:02d}:${t.second:02d} UTC' +	return utc_string +} diff --git a/v_windows/v/old/vlib/time/misc/misc.v b/v_windows/v/old/vlib/time/misc/misc.v new file mode 100644 index 0000000..0ae7b94 --- /dev/null +++ b/v_windows/v/old/vlib/time/misc/misc.v @@ -0,0 +1,13 @@ +module misc + +import rand +import time + +const ( +	start_time_unix = time.now().unix // start_time_unix is set when the program is started. +) + +// random returns a random time struct in *the past*. +pub fn random() time.Time { +	return time.unix(int(rand.u64n(misc.start_time_unix))) +} diff --git a/v_windows/v/old/vlib/time/misc/misc_test.v b/v_windows/v/old/vlib/time/misc/misc_test.v new file mode 100644 index 0000000..9bcc8ad --- /dev/null +++ b/v_windows/v/old/vlib/time/misc/misc_test.v @@ -0,0 +1,17 @@ +import time.misc as tmisc +import rand + +fn test_random() { +	// guarantee CI test stability, by seeding the random number generator with a known seed +	rand.seed([u32(0), 0]) +	t1 := tmisc.random() +	t2 := tmisc.random() +	t3 := tmisc.random() +	t4 := tmisc.random() +	assert t1.unix != t2.unix +	assert t1.unix != t3.unix +	assert t1.unix != t4.unix +	assert t2.unix != t3.unix +	assert t2.unix != t4.unix +	assert t3.unix != t4.unix +} diff --git a/v_windows/v/old/vlib/time/operator.v b/v_windows/v/old/vlib/time/operator.v new file mode 100644 index 0000000..7c6e616 --- /dev/null +++ b/v_windows/v/old/vlib/time/operator.v @@ -0,0 +1,21 @@ +module time + +// operator `==` returns true if provided time is equal to time +[inline] +pub fn (t1 Time) == (t2 Time) bool { +	return t1.unix == t2.unix && t1.microsecond == t2.microsecond +} + +// operator `<` returns true if provided time is less than time +[inline] +pub fn (t1 Time) < (t2 Time) bool { +	return t1.unix < t2.unix || (t1.unix == t2.unix && t1.microsecond < t2.microsecond) +} + +// 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 +} diff --git a/v_windows/v/old/vlib/time/operator_test.v b/v_windows/v/old/vlib/time/operator_test.v new file mode 100644 index 0000000..5f3e1b7 --- /dev/null +++ b/v_windows/v/old/vlib/time/operator_test.v @@ -0,0 +1,391 @@ +module time + +fn assert_greater_time(ms int, t1 Time) { +	sleep(ms * millisecond) +	t2 := now() +	assert t2 > t1 +} + +// Tests the now in all platform and the gt operator function with at least ms resolution +fn test_now_always_results_in_greater_time() { +	t1 := now() +	$if macos { +		assert_greater_time(1, t1) +		return +	} +	$if windows { +		// Lower resolution of time for windows +		assert_greater_time(15, t1) +		return +	} +	$if linux { +		assert_greater_time(1, t1) +		return +	} +	$if solaris { +		assert_greater_time(1, t1) +		return +	} +	// other platforms may have more accurate resolution, +	// but we do not know that ... so wait at least 1s: +	assert_greater_time(1001, t1) +} + +fn test_time1_should_be_same_as_time2() { +	t1 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 100 +	}) +	t2 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 100 +	}) +	assert t1 == t2 +} + +fn test_time1_should_not_be_same_as_time2() { +	t1 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 100 +	}) +	// Difference is one microsecond +	t2 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 101 +	}) +	t3 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 0 +	}) +	// Difference is one second +	t4 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 4 +		microsecond: 0 +	}) +	assert t1 != t2 +	assert t3 != t4 +} + +fn test_time1_should_be_greater_than_time2() { +	t1 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 102 +	}) +	// Difference is one microsecond +	t2 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 101 +	}) +	t3 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 5 +		microsecond: 0 +	}) +	// Difference is one second +	t4 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 4 +		microsecond: 0 +	}) +	assert t1 > t2 +	assert t3 > t4 +} + +fn test_time2_should_be_less_than_time1() { +	t1 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 102 +	}) +	// Difference is one microsecond +	t2 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 101 +	}) +	t3 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 0 +	}) +	// Difference is one second +	t4 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 2 +		microsecond: 0 +	}) +	assert t2 < t1 +	assert t4 < t3 +} + +fn test_time1_should_be_greater_or_equal_to_time2_when_gt() { +	t1 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 102 +	}) +	// Difference is one microsecond +	t2 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 101 +	}) +	t3 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 5 +		microsecond: 0 +	}) +	// Difference is one second +	t4 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 4 +		microsecond: 0 +	}) +	assert t1 >= t2 +	assert t3 >= t4 +} + +fn test_time1_should_be_greater_or_equal_to_time2_when_eq() { +	t1 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 100 +	}) +	// Difference is one microsecond +	t2 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 100 +	}) +	t3 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 0 +	}) +	// Difference is one second +	t4 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 0 +	}) +	assert t1 >= t2 +	assert t3 >= t4 +} + +fn test_time1_should_be_less_or_equal_to_time2_when_lt() { +	t1 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 100 +	}) +	// Difference is one microsecond +	t2 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 101 +	}) +	t3 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 0 +	}) +	// Difference is one second +	t4 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 4 +		microsecond: 0 +	}) +	assert t1 <= t2 +	assert t3 <= t4 +} + +fn test_time1_should_be_less_or_equal_to_time2_when_eq() { +	t1 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 100 +	}) +	// Difference is one microsecond +	t2 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 100 +	}) +	t3 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 0 +	}) +	// Difference is one second +	t4 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 0 +	}) +	assert t1 <= t2 +	assert t3 <= t4 +} + +fn test_time2_copied_from_time1_should_be_equal() { +	t1 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 100 +	}) +	t2 := new_time(t1) +	assert t2 == t1 +} + +fn test_subtract() { +	d_seconds := 3 +	d_microseconds := 13 +	duration := d_seconds * second + d_microseconds * microsecond +	t1 := new_time(Time{ +		year: 2000 +		month: 5 +		day: 10 +		hour: 22 +		minute: 11 +		second: 3 +		microsecond: 100 +	}) +	t2 := unix2(i64(t1.unix) + d_seconds, t1.microsecond + d_microseconds) +	d1 := t2 - t1 +	d2 := t1 - t2 +	assert d1 > 0 +	assert d1 == duration +	assert d2 < 0 +	assert d2 == -duration +} diff --git a/v_windows/v/old/vlib/time/parse.v b/v_windows/v/old/vlib/time/parse.v new file mode 100644 index 0000000..95c5352 --- /dev/null +++ b/v_windows/v/old/vlib/time/parse.v @@ -0,0 +1,140 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module time + +// parse returns time from a date string in "YYYY-MM-DD HH:MM:SS" format. +pub fn parse(s string) ?Time { +	pos := s.index(' ') or { return error('Invalid time format: $s') } +	symd := s[..pos] +	ymd := symd.split('-') +	if ymd.len != 3 { +		return error('Invalid time format: $s') +	} +	shms := s[pos..] +	hms := shms.split(':') +	hour_ := hms[0][1..] +	minute_ := hms[1] +	second_ := hms[2] +	res := new_time(Time{ +		year: ymd[0].int() +		month: ymd[1].int() +		day: ymd[2].int() +		hour: hour_.int() +		minute: minute_.int() +		second: second_.int() +	}) +	return res +} + +// parse_rfc2822 returns time from a date string in RFC 2822 datetime format. +pub fn parse_rfc2822(s string) ?Time { +	fields := s.split(' ') +	if fields.len < 5 { +		return error('Invalid time format: $s') +	} +	pos := months_string.index(fields[2]) or { return error('Invalid time format: $s') } +	mm := pos / 3 + 1 +	unsafe { +		tmstr := malloc_noscan(s.len * 2) +		count := C.snprintf(&char(tmstr), (s.len * 2), c'%s-%02d-%s %s', fields[3].str, +			mm, fields[1].str, fields[4].str) +		return parse(tos(tmstr, count)) +	} +} + +// ----- iso8601 ----- +const ( +	err_invalid_8601 = 'Invalid 8601 Format' +) + +fn parse_iso8601_date(s string) ?(int, int, int) { +	year, month, day, dummy := 0, 0, 0, byte(0) +	count := unsafe { C.sscanf(&char(s.str), c'%4d-%2d-%2d%c', &year, &month, &day, &dummy) } +	if count != 3 { +		return error(time.err_invalid_8601) +	} +	return year, month, day +} + +fn parse_iso8601_time(s string) ?(int, int, int, int, i64, bool) { +	hour_ := 0 +	minute_ := 0 +	second_ := 0 +	microsecond_ := 0 +	plus_min_z := `a` +	offset_hour := 0 +	offset_minute := 0 +	mut count := unsafe { +		C.sscanf(&char(s.str), c'%2d:%2d:%2d.%6d%c%2d:%2d', &hour_, &minute_, &second_, +			µsecond_, &char(&plus_min_z), &offset_hour, &offset_minute) +	} +	// Missread microsecond ([Sec Hour Minute].len == 3 < 4) +	if count < 4 { +		count = unsafe { +			C.sscanf(&char(s.str), c'%2d:%2d:%2d%c%2d:%2d', &hour_, &minute_, &second_, +				&char(&plus_min_z), &offset_hour, &offset_minute) +		} +		count++ // Increment count because skipped microsecond +	} +	if count < 4 { +		return error(time.err_invalid_8601) +	} +	is_local_time := plus_min_z == `a` && count == 4 +	is_utc := plus_min_z == `Z` && count == 5 +	if !(count == 7 || is_local_time || is_utc) { +		return error(time.err_invalid_8601) +	} +	if plus_min_z != `+` && plus_min_z != `-` && !is_utc && !is_local_time { +		return error('Invalid 8601 format, expected `Z` or `+` or `-` as time separator') +	} +	mut unix_offset := 0 +	if offset_hour > 0 { +		unix_offset += 3600 * offset_hour +	} +	if offset_minute > 0 { +		unix_offset += 60 * offset_minute +	} +	if plus_min_z == `+` { +		unix_offset *= -1 +	} +	return hour_, minute_, second_, microsecond_, unix_offset, is_local_time +} + +// parse_iso8601 parses rfc8601 time format yyyy-MM-ddTHH:mm:ss.dddddd+dd:dd as local time +// the fraction part is difference in milli seconds and the last part is offset +// from UTC time and can be both +/- HH:mm +// remarks: not all iso8601 is supported +// also checks and support for leapseconds should be added in future PR +pub fn parse_iso8601(s string) ?Time { +	t_i := s.index('T') or { -1 } +	parts := if t_i != -1 { [s[..t_i], s[t_i + 1..]] } else { s.split(' ') } +	if !(parts.len == 1 || parts.len == 2) { +		return error(time.err_invalid_8601) +	} +	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 +	if parts.len == 2 { +		hour_, minute_, second_, microsecond_, unix_offset, is_local_time = parse_iso8601_time(parts[1]) ? +	} +	mut t := new_time(Time{ +		year: year +		month: month +		day: day +		hour: hour_ +		minute: minute_ +		second: second_ +		microsecond: microsecond_ +	}) +	if is_local_time { +		return t // Time already local time +	} +	mut unix_time := t.unix +	if unix_offset < 0 { +		unix_time -= u64(-unix_offset) +	} else if unix_offset > 0 { +		unix_time += u64(unix_offset) +	} +	t = unix2(i64(unix_time), t.microsecond) +	return t +} diff --git a/v_windows/v/old/vlib/time/parse_test.v b/v_windows/v/old/vlib/time/parse_test.v new file mode 100644 index 0000000..de7df37 --- /dev/null +++ b/v_windows/v/old/vlib/time/parse_test.v @@ -0,0 +1,138 @@ +import time + +fn test_parse() { +	s := '2018-01-27 12:48:34' +	t := time.parse(s) or { +		assert false +		return +	} +	assert t.year == 2018 && t.month == 1 && t.day == 27 && t.hour == 12 && t.minute == 48 +		&& t.second == 34 +	assert t.unix == 1517057314 +} + +fn test_parse_invalid() { +	s := 'Invalid time string' +	time.parse(s) or { +		assert true +		return +	} +	assert false +} + +fn test_parse_rfc2822() { +	s1 := 'Thu, 12 Dec 2019 06:07:45 GMT' +	t1 := time.parse_rfc2822(s1) or { +		assert false +		return +	} +	assert t1.year == 2019 && t1.month == 12 && t1.day == 12 && t1.hour == 6 && t1.minute == 7 +		&& t1.second == 45 +	assert t1.unix == 1576130865 +	s2 := 'Thu 12 Dec 2019 06:07:45 +0800' +	t2 := time.parse_rfc2822(s2) or { +		assert false +		return +	} +	assert t2.year == 2019 && t2.month == 12 && t2.day == 12 && t2.hour == 6 && t2.minute == 7 +		&& t2.second == 45 +	assert t2.unix == 1576130865 +} + +fn test_parse_rfc2822_invalid() { +	s3 := 'Thu 12 Foo 2019 06:07:45 +0800' +	time.parse_rfc2822(s3) or { +		assert true +		return +	} +	assert false +} + +fn test_parse_iso8601() { +	formats := [ +		'2020-06-05T15:38:06Z', +		'2020-06-05T15:38:06.015959Z', +		'2020-06-05T15:38:06.015959+00:00', +		'2020-06-05T15:38:06.015959+02:00', +		'2020-06-05T15:38:06.015959-02:00', +		'2020-11-05T15:38:06.015959Z', +	] +	times := [ +		[2020, 6, 5, 15, 38, 6, 0], +		[2020, 6, 5, 15, 38, 6, 15959], +		[2020, 6, 5, 15, 38, 6, 15959], +		[2020, 6, 5, 13, 38, 6, 15959], +		[2020, 6, 5, 17, 38, 6, 15959], +		[2020, 11, 5, 15, 38, 6, 15959], +	] +	for i, format in formats { +		t := time.parse_iso8601(format) or { +			assert false +			continue +		} +		year := times[i][0] +		assert t.year == year +		month := times[i][1] +		assert t.month == month +		day := times[i][2] +		assert t.day == day +		hour := times[i][3] +		assert t.hour == hour +		minute := times[i][4] +		assert t.minute == minute +		second := times[i][5] +		assert t.second == second +		microsecond := times[i][6] +		assert t.microsecond == microsecond +	} +} + +fn test_parse_iso8601_local() { +	format := '2020-06-05T15:38:06.015959' +	t := time.parse_iso8601(format) or { +		assert false +		return +	} +	assert t.year == 2020 +	assert t.month == 6 +	assert t.day == 5 +	assert t.hour == 15 +	assert t.minute == 38 +	assert t.second == 6 +	assert t.microsecond == 15959 +} + +fn test_parse_iso8601_invalid() { +	formats := [ +		'', +		'2020-06-05X15:38:06.015959Z', +		'2020-06-05T15:38:06.015959X', +		'2020-06-05T15:38:06.015959+0000', +		'2020-06-05T', +		'2020-06-05Z', +		'2020-06-05+00:00', +		'15:38:06', +	] +	for format in formats { +		time.parse_iso8601(format) or { +			assert true +			continue +		} +		assert false +	} +} + +fn test_parse_iso8601_date_only() { +	format := '2020-06-05' +	t := time.parse_iso8601(format) or { +		assert false +		return +	} +	assert t.year == 2020 +	assert t.month == 6 +	assert t.day == 5 +	assert t.hour == 0 +	assert t.minute == 0 +	assert t.second == 0 +	assert t.microsecond == 0 +} diff --git a/v_windows/v/old/vlib/time/private_test.v b/v_windows/v/old/vlib/time/private_test.v new file mode 100644 index 0000000..8dde561 --- /dev/null +++ b/v_windows/v/old/vlib/time/private_test.v @@ -0,0 +1,13 @@ +// tests that use and test private functions +module time + +// test the old behavor is same as new, the unix time should always be local time +fn test_new_is_same_as_old_for_all_platforms() { +	t := C.time(0) +	tm := C.localtime(&t) +	old_time := convert_ctime(tm, 0) +	new_time := now() +	diff := new_time.unix - old_time.unix +	// could in very rare cases be that the second changed between calls +	assert (diff >= 0 && diff <= 1) == true +} diff --git a/v_windows/v/old/vlib/time/stopwatch.v b/v_windows/v/old/vlib/time/stopwatch.v new file mode 100644 index 0000000..569e10c --- /dev/null +++ b/v_windows/v/old/vlib/time/stopwatch.v @@ -0,0 +1,72 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module time + +pub struct StopWatchOptions { +	auto_start bool = true +} + +// StopWatch is used to measure elapsed time. +pub struct StopWatch { +mut: +	elapsed u64 +pub mut: +	start u64 +	end   u64 +} + +// new_stopwatch initializes a new StopWatch with the current time as start. +pub fn new_stopwatch(opts StopWatchOptions) StopWatch { +	mut initial := u64(0) +	if opts.auto_start { +		initial = sys_mono_now() +	} +	return StopWatch{ +		elapsed: 0 +		start: initial +		end: 0 +	} +} + +// start starts the stopwatch. If the timer was paused, restarts counting. +pub fn (mut t StopWatch) start() { +	t.start = sys_mono_now() +	t.end = 0 +} + +// restart restarts the stopwatch. If the timer was paused, restarts counting. +pub fn (mut t StopWatch) restart() { +	t.start = sys_mono_now() +	t.end = 0 +	t.elapsed = 0 +} + +// stop stops the timer, by setting the end time to the current time. +pub fn (mut t StopWatch) stop() { +	t.end = sys_mono_now() +} + +// pause resets the `start` time and adds the current elapsed time to `elapsed`. +pub fn (mut t StopWatch) pause() { +	if t.start > 0 { +		if t.end == 0 { +			t.elapsed += sys_mono_now() - t.start +		} else { +			t.elapsed += t.end - t.start +		} +	} +	t.start = 0 +} + +// elapsed returns the Duration since the last start call +pub fn (t StopWatch) elapsed() Duration { +	if t.start > 0 { +		if t.end == 0 { +			return Duration(i64(sys_mono_now() - t.start + t.elapsed)) +		} else { +			return Duration(i64(t.end - t.start + t.elapsed)) +		} +	} +	return Duration(i64(t.elapsed)) +} diff --git a/v_windows/v/old/vlib/time/stopwatch_test.v b/v_windows/v/old/vlib/time/stopwatch_test.v new file mode 100644 index 0000000..49d005a --- /dev/null +++ b/v_windows/v/old/vlib/time/stopwatch_test.v @@ -0,0 +1,36 @@ +import time + +// NB: on CI jobs, especially msvc ones, sleep_ms may sleep for much more +// time than you have specified. To avoid false positives from CI test +// failures, some of the asserts will be run only if you pass `-d stopwatch` +fn test_stopwatch_works_as_intended() { +	mut sw := time.new_stopwatch() +	// sample code that you want to measure: +	println('Hello world') +	time.sleep(1 * time.millisecond) +	// +	println('Greeting the world took: ${sw.elapsed().nanoseconds()}ns') +	assert sw.elapsed().nanoseconds() > 0 +} + +fn test_stopwatch_time_between_pause_and_start_should_be_skipped_in_elapsed() { +	println('Testing pause function') +	mut sw := time.new_stopwatch() +	time.sleep(10 * time.millisecond) // A +	eprintln('Elapsed after 10ms nap: ${sw.elapsed().milliseconds()}ms') +	assert sw.elapsed().milliseconds() >= 8 // sometimes it sleeps for 9ms on windows.. +	sw.pause() +	time.sleep(10 * time.millisecond) +	eprintln('Elapsed after pause and another 10ms nap: ${sw.elapsed().milliseconds()}ms') +	assert sw.elapsed().milliseconds() >= 8 +	$if stopwatch ? { +		assert sw.elapsed().milliseconds() < 20 +	} +	sw.start() +	time.sleep(10 * time.millisecond) // B +	eprintln('Elapsed after resume and another 10ms nap: ${sw.elapsed().milliseconds()}ms') +	assert sw.elapsed().milliseconds() >= 18 +	$if stopwatch ? { +		assert sw.elapsed().milliseconds() < 30 +	} +} diff --git a/v_windows/v/old/vlib/time/time.v b/v_windows/v/old/vlib/time/time.v new file mode 100644 index 0000000..14f0c7a --- /dev/null +++ b/v_windows/v/old/vlib/time/time.v @@ -0,0 +1,431 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module time + +#include <time.h> + +pub const ( +	days_string        = 'MonTueWedThuFriSatSun' +	month_days         = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] +	months_string      = 'JanFebMarAprMayJunJulAugSepOctNovDec' +	// The unsigned zero year for internal calculations. +	// Must be 1 mod 400, and times before it will not compute correctly, +	// but otherwise can be changed at will. +	absolute_zero_year = i64(-292277022399) // as i64 +	seconds_per_minute = 60 +	seconds_per_hour   = 60 * seconds_per_minute +	seconds_per_day    = 24 * seconds_per_hour +	seconds_per_week   = 7 * seconds_per_day +	days_per_400_years = 365 * 400 + 97 +	days_per_100_years = 365 * 100 + 24 +	days_per_4_years   = 365 * 4 + 1 +	days_before        = [ +		0, +		31, +		31 + 28, +		31 + 28 + 31, +		31 + 28 + 31 + 30, +		31 + 28 + 31 + 30 + 31, +		31 + 28 + 31 + 30 + 31 + 30, +		31 + 28 + 31 + 30 + 31 + 30 + 31, +		31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, +		31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, +		31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, +		31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, +		31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31, +	] +	long_days          = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', +		'Sunday', +	] +) + +// Time contains various time units for a point in time. +pub struct Time { +pub: +	year        int +	month       int +	day         int +	hour        int +	minute      int +	second      int +	microsecond int +	unix        u64 +} + +// FormatDelimiter contains different time formats. +pub enum FormatTime { +	hhmm12 +	hhmm24 +	hhmmss12 +	hhmmss24 +	hhmmss24_milli +	hhmmss24_micro +	no_time +} + +// FormatDelimiter contains different date formats. +pub enum FormatDate { +	ddmmyy +	ddmmyyyy +	mmddyy +	mmddyyyy +	mmmd +	mmmdd +	mmmddyy +	mmmddyyyy +	no_date +	yyyymmdd +	yymmdd +} + +// FormatDelimiter contains different time/date delimiters. +pub enum FormatDelimiter { +	dot +	hyphen +	slash +	space +	no_delimiter +} + +// C.timeval represents a C time value. +pub struct C.timeval { +	tv_sec  u64 +	tv_usec u64 +} + +fn C.localtime(t &C.time_t) &C.tm + +fn C.time(t &C.time_t) C.time_t + +// now returns current local time. +pub fn now() Time { +	$if macos { +		return darwin_now() +	} +	$if windows { +		return win_now() +	} +	$if solaris { +		return solaris_now() +	} +	$if linux || android { +		return linux_now() +	} +	// defaults to most common feature, the microsecond precision is not available +	// in this API call +	t := C.time(0) +	now := C.localtime(&t) +	return convert_ctime(*now, 0) +} + +// utc returns the current UTC time. +pub fn utc() Time { +	$if macos { +		return darwin_utc() +	} +	$if windows { +		return win_utc() +	} +	$if solaris { +		return solaris_utc() +	} +	$if linux || android { +		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) +} + +// smonth returns month name. +pub fn (t Time) smonth() string { +	if t.month <= 0 || t.month > 12 { +		return '---' +	} +	i := t.month - 1 +	return time.months_string[i * 3..(i + 1) * 3] +} + +// new_time returns a time struct with calculated Unix time. +pub fn new_time(t Time) Time { +	if t.unix != 0 { +		return t +	} +	tt := C.tm{ +		tm_sec: t.second +		tm_min: t.minute +		tm_hour: t.hour +		tm_mday: t.day +		tm_mon: t.month - 1 +		tm_year: t.year - 1900 +	} +	utime := u64(make_unix_time(tt)) +	return Time{ +		...t +		unix: utime +	} +} + +// unix_time returns Unix time. +[inline] +pub fn (t Time) unix_time() int { +	return int(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) +} + +// 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) +	return unix2(unix, int(micro)) +} + +// add_seconds returns a new time struct with an added number of seconds. +pub fn (t Time) add_seconds(seconds int) Time { +	return t.add(seconds * time.second) +} + +// add_days returns a new time struct with an added number of days. +pub fn (t Time) add_days(days int) Time { +	return t.add(days * 24 * time.hour) +} + +// since returns a number of seconds elapsed since a given time. +fn since(t Time) int { +	// TODO Use time.Duration instead of seconds +	return 0 +} + +// relative returns a string representation of the difference between t +// and the current time. +pub fn (t Time) relative() string { +	znow := now() +	secs := znow.unix - t.unix +	if secs <= 30 { +		// right now or in the future +		// TODO handle time in the future +		return 'now' +	} +	if secs < 60 { +		return '1m' +	} +	if secs < 3600 { +		m := secs / 60 +		if m == 1 { +			return '1 minute ago' +		} +		return '$m minutes ago' +	} +	if secs < 3600 * 24 { +		h := secs / 3600 +		if h == 1 { +			return '1 hour ago' +		} +		return '$h hours ago' +	} +	if secs < 3600 * 24 * 5 { +		d := secs / 3600 / 24 +		if d == 1 { +			return '1 day ago' +		} +		return '$d days ago' +	} +	if secs > 3600 * 24 * 10000 { +		return '' +	} +	return t.md() +} + +// relative_short returns a string saying how long ago a time occured as follows: +// 0-30 seconds: `"now"`; 30-60 seconds: `"1m"`; anything else is rounded to the +// nearest minute, hour or day; anything higher than 10000 days (about 27 years) +// years returns an empty string. +// Some Examples: +// `0s -> 'now'`; +// `20s -> 'now'`; +// `47s -> '1m'`; +// `456s -> '7m'`; +// `1234s -> '20m'`; +// `16834s -> '4h'`; +// `1687440s -> '33d'`; +// `15842354871s -> ''` +pub fn (t Time) relative_short() string { +	znow := now() +	secs := znow.unix - t.unix +	if secs <= 30 { +		// right now or in the future +		// TODO handle time in the future +		return 'now' +	} +	if secs < 60 { +		return '1m' +	} +	if secs < 3600 { +		return '${secs / 60}m' +	} +	if secs < 3600 * 24 { +		return '${secs / 3600}h' +	} +	if secs < 3600 * 24 * 5 { +		return '${secs / 3600 / 24}d' +	} +	if secs > 3600 * 24 * 10000 { +		return '' +	} +	return t.md() +} + +// day_of_week returns the current day of a given year, month, and day, +// as an integer. +pub fn day_of_week(y int, m int, d int) int { +	// Sakomotho's algorithm is explained here: +	// https://stackoverflow.com/a/6385934 +	t := [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4] +	mut sy := y +	if m < 3 { +		sy = sy - 1 +	} +	return (sy + sy / 4 - sy / 100 + sy / 400 + t[m - 1] + d - 1) % 7 + 1 +} + +// day_of_week returns the current day as an integer. +pub fn (t Time) day_of_week() int { +	return day_of_week(t.year, t.month, t.day) +} + +// weekday_str returns the current day as a string. +pub fn (t Time) weekday_str() string { +	i := t.day_of_week() - 1 +	return time.days_string[i * 3..(i + 1) * 3] +} + +// weekday_str returns the current day as a string. +pub fn (t Time) long_weekday_str() string { +	i := t.day_of_week() - 1 +	return time.long_days[i] +} + +// ticks returns a number of milliseconds elapsed since system start. +pub fn ticks() i64 { +	$if windows { +		return C.GetTickCount() +	} $else { +		ts := C.timeval{} +		C.gettimeofday(&ts, 0) +		return i64(ts.tv_sec * u64(1000) + (ts.tv_usec / u64(1000))) +	} +	// t := i64(C.mach_absolute_time()) +	// # Nanoseconds elapsedNano = AbsoluteToNanoseconds( *(AbsoluteTime *) &t ); +	// # return (double)(* (uint64_t *) &elapsedNano) / 1000000; +} + +/* +// sleep makes the calling thread sleep for a given number of seconds. +[deprecated: 'call time.sleep(n * time.second)'] +pub fn sleep(seconds int) { +	wait(seconds * time.second) +} +*/ + +// is_leap_year checks if a given a year is a leap year. +pub fn is_leap_year(year int) bool { +	return (year % 4 == 0) && (year % 100 != 0 || year % 400 == 0) +} + +// days_in_month returns a number of days in a given month. +pub fn days_in_month(month int, year int) ?int { +	if month > 12 || month < 1 { +		return error('Invalid month: $month') +	} +	extra := if month == 2 && is_leap_year(year) { 1 } else { 0 } +	res := time.month_days[month - 1] + extra +	return res +} + +// str returns time in the same format as `parse` expects ("YYYY-MM-DD HH:MM:SS"). +pub fn (t Time) str() string { +	// TODO Define common default format for +	// `str` and `parse` and use it in both ways +	return t.format_ss() +} + +// convert_ctime converts a C time to V time. +fn convert_ctime(t C.tm, microsecond int) Time { +	return Time{ +		year: t.tm_year + 1900 +		month: t.tm_mon + 1 +		day: t.tm_mday +		hour: t.tm_hour +		minute: t.tm_min +		second: t.tm_sec +		microsecond: time.microsecond +		unix: u64(make_unix_time(t)) +	} +} + +// A lot of these are taken from the Go library. +pub type Duration = i64 + +pub const ( +	nanosecond  = Duration(1) +	microsecond = Duration(1000 * nanosecond) +	millisecond = Duration(1000 * microsecond) +	second      = Duration(1000 * millisecond) +	minute      = Duration(60 * second) +	hour        = Duration(60 * minute) +	infinite    = Duration(C.INT64_MAX) +) + +// nanoseconds returns the duration as an integer number of nanoseconds. +pub fn (d Duration) nanoseconds() i64 { +	return i64(d) +} + +// microseconds returns the duration as an integer number of microseconds. +pub fn (d Duration) microseconds() i64 { +	return i64(d) / 1000 +} + +// milliseconds returns the duration as an integer number of milliseconds. +pub fn (d Duration) milliseconds() i64 { +	return i64(d) / 1000000 +} + +// The following functions return floating point numbers because it's common to +// consider all of them in sub-one intervals +// seconds returns the duration as a floating point number of seconds. +pub fn (d Duration) seconds() f64 { +	sec := d / time.second +	nsec := d % time.second +	return f64(sec) + f64(nsec) / 1e9 +} + +// minutes returns the duration as a floating point number of minutes. +pub fn (d Duration) minutes() f64 { +	min := d / time.minute +	nsec := d % time.minute +	return f64(min) + f64(nsec) / (60 * 1e9) +} + +// hours returns the duration as a floating point number of hours. +pub fn (d Duration) hours() f64 { +	hr := d / time.hour +	nsec := d % time.hour +	return f64(hr) + f64(nsec) / (60 * 60 * 1e9) +} + +// offset returns time zone UTC offset in seconds. +pub fn offset() int { +	t := now() +	local := t.local() +	return int(local.unix - t.unix) +} diff --git a/v_windows/v/old/vlib/time/time_darwin.c.v b/v_windows/v/old/vlib/time/time_darwin.c.v new file mode 100644 index 0000000..d16c66b --- /dev/null +++ b/v_windows/v/old/vlib/time/time_darwin.c.v @@ -0,0 +1,84 @@ +module time + +#include <mach/mach_time.h> + +const ( +	// start_time is needed on Darwin and Windows because of potential overflows +	start_time = C.mach_absolute_time() +	time_base  = init_time_base() +) + +[typedef] +struct C.mach_timebase_info_data_t { +	numer u32 +	denom u32 +} + +fn C.mach_absolute_time() u64 + +fn C.mach_timebase_info(&C.mach_timebase_info_data_t) + +fn C.clock_gettime_nsec_np(int) u64 + +struct InternalTimeBase { +	numer 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 { +	tb := C.mach_timebase_info_data_t{} +	C.mach_timebase_info(&tb) +	return C.mach_timebase_info_data_t{ +		numer: tb.numer +		denom: tb.denom +	} +} + +fn sys_mono_now_darwin() u64 { +	tm := C.mach_absolute_time() +	if time.time_base.denom == 0 { +		C.mach_timebase_info(&time.time_base) +	} +	return (tm - time.start_time) * time.time_base.numer / time.time_base.denom +} + +// NB: vpc_now_darwin is used by `v -profile` . +// It should NOT call *any other v function*, just C functions and casts. +[inline] +fn vpc_now_darwin() u64 { +	tm := C.mach_absolute_time() +	if time.time_base.denom == 0 { +		C.mach_timebase_info(&time.time_base) +	} +	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 +// 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 { +	// get the high precision time as UTC clock +	tv := C.timeval{} +	C.gettimeofday(&tv, 0) +	loc_tm := C.tm{} +	asec := voidptr(&tv.tv_sec) +	C.localtime_r(asec, &loc_tm) +	return convert_ctime(loc_tm, int(tv.tv_usec)) +} + +// darwin_utc returns a better precision current time for Darwin based operating system +// 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 { +	// get the high precision time as UTC clock +	tv := C.timeval{} +	C.gettimeofday(&tv, 0) +	return unix2(i64(tv.tv_sec), int(tv.tv_usec)) +} diff --git a/v_windows/v/old/vlib/time/time_format_test.v b/v_windows/v/old/vlib/time/time_format_test.v new file mode 100644 index 0000000..6042cf9 --- /dev/null +++ b/v_windows/v/old/vlib/time/time_format_test.v @@ -0,0 +1,90 @@ +import time + +const ( +	time_to_test = time.Time{ +		year: 1980 +		month: 7 +		day: 11 +		hour: 21 +		minute: 23 +		second: 42 +		unix: 332198622 +	} +) + +fn test_now_format() { +	t := time.now() +	u := t.unix +	assert t.format() == time.unix(int(u)).format() +} + +fn test_format() { +	assert '11.07.1980 21:23' == time_to_test.get_fmt_str(.dot, .hhmm24, .ddmmyyyy) +} + +fn test_hhmm() { +	assert '21:23' == time_to_test.hhmm() +} + +fn test_hhmm12() { +	assert '9:23 p.m.' == time_to_test.hhmm12() +} + +fn test_hhmmss() { +	assert '21:23:42' == time_to_test.hhmmss() +} + +fn test_ymmdd() { +	assert '1980-07-11' == time_to_test.ymmdd() +} + +fn test_ddmmy() { +	assert '11.07.1980' == time_to_test.ddmmy() +} + +fn test_md() { +	assert 'Jul 11' == time_to_test.md() +} + +fn test_get_fmt_time_str() { +	assert '21:23:42' == time_to_test.get_fmt_time_str(.hhmmss24) +	assert '21:23' == time_to_test.get_fmt_time_str(.hhmm24) +	assert '9:23:42 p.m.' == time_to_test.get_fmt_time_str(.hhmmss12) +	assert '9:23 p.m.' == time_to_test.get_fmt_time_str(.hhmm12) +} + +fn test_get_fmt_date_str() { +	assert '11.07.1980' == time_to_test.get_fmt_date_str(.dot, .ddmmyyyy) +	assert '11/07/1980' == time_to_test.get_fmt_date_str(.slash, .ddmmyyyy) +	assert '11-07-1980' == time_to_test.get_fmt_date_str(.hyphen, .ddmmyyyy) +	assert '11 07 1980' == time_to_test.get_fmt_date_str(.space, .ddmmyyyy) +	assert '07.11.1980' == time_to_test.get_fmt_date_str(.dot, .mmddyyyy) +	assert '07/11/1980' == time_to_test.get_fmt_date_str(.slash, .mmddyyyy) +	assert '07-11-1980' == time_to_test.get_fmt_date_str(.hyphen, .mmddyyyy) +	assert '07 11 1980' == time_to_test.get_fmt_date_str(.space, .mmddyyyy) +	assert '11.07.80' == time_to_test.get_fmt_date_str(.dot, .ddmmyy) +	assert '11/07/80' == time_to_test.get_fmt_date_str(.slash, .ddmmyy) +	assert '11-07-80' == time_to_test.get_fmt_date_str(.hyphen, .ddmmyy) +	assert '11 07 80' == time_to_test.get_fmt_date_str(.space, .ddmmyy) +	assert '07.11.80' == time_to_test.get_fmt_date_str(.dot, .mmddyy) +	assert '07/11/80' == time_to_test.get_fmt_date_str(.slash, .mmddyy) +	assert '07-11-80' == time_to_test.get_fmt_date_str(.hyphen, .mmddyy) +	assert '07 11 80' == time_to_test.get_fmt_date_str(.space, .mmddyy) +	assert 'Jul 11' == time_to_test.get_fmt_date_str(.space, .mmmd) +	assert 'Jul 11' == time_to_test.get_fmt_date_str(.space, .mmmdd) +	assert 'Jul 11 80' == time_to_test.get_fmt_date_str(.space, .mmmddyy) +	assert 'Jul 11 1980' == time_to_test.get_fmt_date_str(.space, .mmmddyyyy) +	assert '1980-07-11' == time_to_test.get_fmt_date_str(.hyphen, .yyyymmdd) +	assert '80.07.11' == time_to_test.get_fmt_date_str(.dot, .yymmdd) +} + +fn test_get_fmt_str() { +	// Since get_fmt_time_str and get_fmt_date_str do have comprehensive +	// tests I don't want to exaggerate here with all possible +	// combinations. +	assert '11.07.1980 21:23:42' == time_to_test.get_fmt_str(.dot, .hhmmss24, .ddmmyyyy) +} + +fn test_utc_string() { +	assert 'Fri, 11 Jul 1980 21:23:42 UTC' == time_to_test.utc_string() +} diff --git a/v_windows/v/old/vlib/time/time_linux.c.v b/v_windows/v/old/vlib/time/time_linux.c.v new file mode 100644 index 0000000..b0ab7ad --- /dev/null +++ b/v_windows/v/old/vlib/time/time_linux.c.v @@ -0,0 +1,26 @@ +module time + +// sys_mono_now_darwin - dummy fn to compile on all platforms/compilers +fn sys_mono_now_darwin() u64 { +	return 0 +} + +// darwin_now - dummy fn to compile on all platforms/compilers +pub fn darwin_now() Time { +	return Time{} +} + +// solaris_now - dummy fn to compile on all platforms/compilers +pub fn solaris_now() Time { +	return Time{} +} + +// darwin_utc - dummy fn to compile on all platforms/compilers +pub fn darwin_utc() Time { +	return Time{} +} + +// solaris_utc - dummy fn to compile on all platforms/compilers +pub fn solaris_utc() Time { +	return Time{} +} diff --git a/v_windows/v/old/vlib/time/time_nix.c.v b/v_windows/v/old/vlib/time/time_nix.c.v new file mode 100644 index 0000000..82ff548 --- /dev/null +++ b/v_windows/v/old/vlib/time/time_nix.c.v @@ -0,0 +1,156 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module time + +#include <time.h> +#include <errno.h> + +struct C.tm { +	tm_sec   int +	tm_min   int +	tm_hour  int +	tm_mday  int +	tm_mon   int +	tm_year  int +	tm_wday  int +	tm_yday  int +	tm_isdst int +} + +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)) +} + +// local returns t with the location set to local time. +pub fn (t Time) local() Time { +	loc_tm := C.tm{} +	C.localtime_r(voidptr(&t.unix), &loc_tm) +	return convert_ctime(loc_tm, t.microsecond) +} + +// in most systems, these are __quad_t, which is an i64 +struct C.timespec { +mut: +	tv_sec  i64 +	tv_nsec i64 +} + +// the first arg is defined in include/bits/types.h as `__S32_TYPE`, which is `int` +fn C.clock_gettime(int, &C.timespec) + +fn C.nanosleep(req &C.timespec, rem &C.timespec) int + +// sys_mono_now returns a *monotonically increasing time*, NOT a time adjusted for daylight savings, location etc. +pub fn sys_mono_now() u64 { +	$if macos { +		return sys_mono_now_darwin() +	} $else { +		ts := C.timespec{} +		C.clock_gettime(C.CLOCK_MONOTONIC, &ts) +		return u64(ts.tv_sec) * 1000000000 + u64(ts.tv_nsec) +	} +} + +// NB: vpc_now is used by `v -profile` . +// It should NOT call *any other v function*, just C functions and casts. +[inline] +fn vpc_now() u64 { +	ts := C.timespec{} +	C.clock_gettime(C.CLOCK_MONOTONIC, &ts) +	return u64(ts.tv_sec) * 1000000000 + u64(ts.tv_nsec) +} + +// The linux_* functions are placed here, since they're used on Android as well +// TODO: should `$if linux {}` be parsed on Android as well? (Android runs under the Linux kernel) +// linux_now returns the local time with high precision for most os:es +// this should be implemented properly with support for leap seconds. +// It uses the realtime clock to get and converts it to local time +fn linux_now() Time { +	// get the high precision time as UTC realtime clock +	// and use the nanoseconds part +	mut ts := C.timespec{} +	C.clock_gettime(C.CLOCK_REALTIME, &ts) +	loc_tm := C.tm{} +	C.localtime_r(voidptr(&ts.tv_sec), &loc_tm) +	return convert_ctime(loc_tm, int(ts.tv_nsec / 1000)) +} + +fn linux_utc() Time { +	// get the high precision time as UTC realtime clock +	// and use the nanoseconds part +	mut ts := C.timespec{} +	C.clock_gettime(C.CLOCK_REALTIME, &ts) +	return unix2(i64(ts.tv_sec), int(ts.tv_nsec / 1000)) +} + +// dummy to compile with all compilers +pub fn win_now() Time { +	return Time{} +} + +// dummy to compile with all compilers +pub fn win_utc() 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 +pub fn (d Duration) timespec() C.timespec { +	mut ts := C.timespec{} +	C.clock_gettime(C.CLOCK_REALTIME, &ts) +	d_sec := d / second +	d_nsec := d % second +	ts.tv_sec += d_sec +	ts.tv_nsec += d_nsec +	if ts.tv_nsec > i64(second) { +		ts.tv_nsec -= i64(second) +		ts.tv_sec++ +	} +	return ts +} + +// return timespec of 1970/1/1 +pub fn zero_timespec() C.timespec { +	ts := C.timespec{ +		tv_sec: 0 +		tv_nsec: 0 +	} +	return ts +} + +// sleep makes the calling thread sleep for a given duration (in nanoseconds). +pub fn sleep(duration Duration) { +	mut req := C.timespec{duration / second, duration % second} +	rem := C.timespec{} +	for C.nanosleep(&req, &rem) < 0 { +		if C.errno == C.EINTR { +			// Interrupted by a signal handler +			req = rem +		} else { +			break +		} +	} +} + +// some *nix system functions (e.g. `C.poll()`, C.epoll_wait()) accept an `int` +// value as *timeout in milliseconds* with the special value `-1` meaning "infinite" +pub fn (d Duration) sys_milliseconds() int { +	if d > C.INT32_MAX * millisecond { // treat 2147483647000001 .. C.INT64_MAX as "infinite" +		return -1 +	} else if d <= 0 { +		return 0 // treat negative timeouts as 0 - consistent with Unix behaviour +	} else { +		return int(d / millisecond) +	} +} diff --git a/v_windows/v/old/vlib/time/time_solaris.c.v b/v_windows/v/old/vlib/time/time_solaris.c.v new file mode 100644 index 0000000..b87f1c8 --- /dev/null +++ b/v_windows/v/old/vlib/time/time_solaris.c.v @@ -0,0 +1,32 @@ +module time + +// solaris_now returns the local time with high precision for most os:es +// this should be implemented properly with support for leap seconds. +// It uses the realtime clock to get and converts it to local time +fn solaris_now() Time { +	// get the high precision time as UTC realtime clock +	// and use the nanoseconds part +	mut ts := C.timespec{} +	C.clock_gettime(C.CLOCK_REALTIME, &ts) +	loc_tm := C.tm{} +	C.localtime_r(voidptr(&ts.tv_sec), &loc_tm) +	return convert_ctime(loc_tm, int(ts.tv_nsec / 1000)) +} + +fn solaris_utc() Time { +	// get the high precision time as UTC realtime clock +	// and use the nanoseconds part +	mut ts := C.timespec{} +	C.clock_gettime(C.CLOCK_REALTIME, &ts) +	return unix2(i64(ts.tv_sec), int(ts.tv_nsec / 1000)) +} + +// dummy to compile with all compilers +pub fn darwin_now() Time { +	return Time{} +} + +// dummy to compile with all compilers +pub fn darwin_utc() Time { +	return Time{} +} diff --git a/v_windows/v/old/vlib/time/time_test.v b/v_windows/v/old/vlib/time/time_test.v new file mode 100644 index 0000000..0511916 --- /dev/null +++ b/v_windows/v/old/vlib/time/time_test.v @@ -0,0 +1,247 @@ +import time +import math + +const ( +	time_to_test = time.Time{ +		year: 1980 +		month: 7 +		day: 11 +		hour: 21 +		minute: 23 +		second: 42 +		microsecond: 123456 +		unix: 332198622 +	} +) + +fn test_is_leap_year() { +	// 1996 % 4 = 0 and 1996 % 100 > 0 +	assert time.is_leap_year(1996) == true +	// 2000 % 4 = 0 and 2000 % 400 = 0 +	assert time.is_leap_year(2000) == true +	// 1996 % 4 > 0 +	assert time.is_leap_year(1997) == false +	// 2000 % 4 = 0 and 2000 % 100 = 0 +	assert time.is_leap_year(2100) == false +} + +fn check_days_in_month(month int, year int, expected int) bool { +	res := time.days_in_month(month, year) or { return false } +	return res == expected +} + +fn test_days_in_month() { +	days_in_month := [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] +	for i, days in days_in_month { +		month := i + 1 +		assert check_days_in_month(month, 2001, days) +	} +} + +fn test_unix() { +	t := time.unix(1564366499) +	assert t.year == 2019 +	assert t.month == 7 +	assert t.day == 29 +	assert t.hour == 2 +	assert t.minute == 14 +	assert t.second == 59 +	t2 := time.unix(1078058096) +	assert t2.year == 2004 +	assert t2.month == 2 +	assert t2.day == 29 +	assert t2.hour == 12 +	assert t2.minute == 34 +	assert t2.second == 56 +	t3 := time.unix(1070236799) +	assert t3.year == 2003 +	assert t3.month == 11 +	assert t3.day == 30 +	assert t3.hour == 23 +	assert t3.minute == 59 +	assert t3.second == 59 +	t4 := time.unix(1577783439) +	assert t4.year == 2019 +	assert t4.month == 12 +	assert t4.day == 31 +	assert t4.hour == 9 +	assert t4.minute == 10 +	assert t4.second == 39 +	t5 := time.unix(-1824922433) +	assert t5.year == 1912 +	assert t5.month == 3 +	assert t5.day == 4 +	assert t5.hour == 5 +	assert t5.minute == 6 +	assert t5.second == 7 +	t6 := time.unix(1577858969) +	assert t6.year == 2020 +	assert t6.month == 1 +	assert t6.day == 1 +	assert t6.hour == 6 +	assert t6.minute == 9 +	assert t6.second == 29 +} + +fn test_format_ss() { +	assert '11.07.1980 21:23:42' == time_to_test.get_fmt_str(.dot, .hhmmss24, .ddmmyyyy) +} + +fn test_format_ss_milli() { +	assert '11.07.1980 21:23:42.123' == time_to_test.get_fmt_str(.dot, .hhmmss24_milli, +		.ddmmyyyy) +	assert '1980-07-11 21:23:42.123' == time_to_test.format_ss_milli() +} + +fn test_format_ss_micro() { +	assert '11.07.1980 21:23:42.123456' == time_to_test.get_fmt_str(.dot, .hhmmss24_micro, +		.ddmmyyyy) +	assert '1980-07-11 21:23:42.123456' == time_to_test.format_ss_micro() +} + +fn test_smonth() { +	month_names := ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', +		'Dec', +	] +	for i, name in month_names { +		month_num := i + 1 +		t := time.Time{ +			year: 1980 +			month: month_num +			day: 1 +			hour: 0 +			minute: 0 +			second: 0 +			unix: 0 +		} +		assert t.smonth() == name +	} +} + +fn test_day_of_week() { +	for i in 0 .. 7 { +		day_of_week := i + 1 +		// 2 Dec 2019 is Monday +		t := time.Time{ +			year: 2019 +			month: 12 +			day: 2 + i +			hour: 0 +			minute: 0 +			second: 0 +			unix: 0 +		} +		assert day_of_week == t.day_of_week() +	} +} + +fn test_weekday_str() { +	day_names := ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] +	for i, name in day_names { +		// 2 Dec 2019 is Monday +		t := time.Time{ +			year: 2019 +			month: 12 +			day: 2 + i +			hour: 0 +			minute: 0 +			second: 0 +			unix: 0 +		} +		assert t.weekday_str() == name +	} +} + +fn test_add() { +	d_seconds := 3 +	d_microseconds := 13 +	duration := time.Duration(d_seconds * time.second + d_microseconds * time.microsecond) +	t1 := time_to_test +	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) +	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) +} + +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) +} + +fn test_str() { +	assert '1980-07-11 21:23:42' == time_to_test.str() +} + +// not optimal test but will find obvious bugs +fn test_now() { +	now := time.now() +	// The year the test was built +	assert now.year >= 2020 +	assert now.month > 0 +	assert now.month <= 12 +	assert now.minute >= 0 +	assert now.minute < 60 +	assert now.second >= 0 +	assert now.second <= 60 // <= 60 cause of leap seconds +	assert now.microsecond >= 0 +	assert now.microsecond < 1000000 +} + +fn test_utc() { +	now := time.utc() +	// The year the test was built +	assert now.year >= 2020 +	assert now.month > 0 +	assert now.month <= 12 +	assert now.minute >= 0 +	assert now.minute < 60 +	assert now.second >= 0 +	assert now.second <= 60 // <= 60 cause of leap seconds +	assert now.microsecond >= 0 +	assert now.microsecond < 1000000 +} + +fn test_unix_time() { +	t1 := time.utc() +	time.sleep(50 * time.millisecond) +	t2 := time.utc() +	ut1 := t1.unix_time() +	ut2 := t2.unix_time() +	assert ut2 - ut1 < 2 +	// +	utm1 := t1.unix_time_milli() +	utm2 := t2.unix_time_milli() +	assert (utm1 - u64(ut1) * 1000) < 1000 +	assert (utm2 - u64(ut2) * 1000) < 1000 +	// +	// println('utm1: $utm1 | utm2: $utm2') +	assert utm2 - utm1 > 2 +	assert utm2 - utm1 < 999 +} + +fn test_offset() { +	u := time.utc() +	n := time.now() +	// +	mut diff_seconds := 0 +	if u.day != n.day { +		if u.day > n.day { +			diff_seconds = int(math.abs(((u.hour * 60 + u.minute) - (n.hour * 60 + n.minute)) * 60)) - 86400 +		} else { +			diff_seconds = 86400 - int(math.abs(((u.hour * 60 + u.minute) - (n.hour * 60 + n.minute)) * 60)) +		} +		if math.abs(u.day - n.day) > 1 { // different month +			diff_seconds = diff_seconds * -1 +		} +	} else { // same day +		diff_seconds = ((n.hour * 60 + n.minute) - (u.hour * 60 + u.minute)) * 60 +	} + +	assert diff_seconds == time.offset() +} diff --git a/v_windows/v/old/vlib/time/time_windows.c.v b/v_windows/v/old/vlib/time/time_windows.c.v new file mode 100644 index 0000000..d44e6c9 --- /dev/null +++ b/v_windows/v/old/vlib/time/time_windows.c.v @@ -0,0 +1,233 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module time + +#include <time.h> +// #include <sysinfoapi.h> + +struct C.tm { +	tm_year int +	tm_mon  int +	tm_mday int +	tm_hour int +	tm_min  int +	tm_sec  int +} + +struct C._FILETIME { +	dwLowDateTime  u32 +	dwHighDateTime u32 +} + +struct SystemTime { +	year        u16 +	month       u16 +	day_of_week u16 +	day         u16 +	hour        u16 +	minute      u16 +	second      u16 +	millisecond u16 +} + +fn C.GetSystemTimeAsFileTime(lpSystemTimeAsFileTime &C._FILETIME) + +fn C.FileTimeToSystemTime(lpFileTime &C._FILETIME, lpSystemTime &SystemTime) + +fn C.SystemTimeToTzSpecificLocalTime(lpTimeZoneInformation &C.TIME_ZONE_INFORMATION, lpUniversalTime &SystemTime, lpLocalTime &SystemTime) + +fn C.localtime_s(t &C.time_t, tm &C.tm) + +const ( +	// start_time is needed on Darwin and Windows because of potential overflows +	start_time       = init_win_time_start() +	freq_time        = init_win_time_freq() +	start_local_time = local_as_unix_time() +) + +// in most systems, these are __quad_t, which is an i64 +struct C.timespec { +	tv_sec  i64 +	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 init_win_time_freq() u64 { +	f := u64(0) +	C.QueryPerformanceFrequency(&f) +	return f +} + +fn init_win_time_start() u64 { +	s := u64(0) +	C.QueryPerformanceCounter(&s) +	return s +} + +// sys_mono_now returns a *monotonically increasing time*, NOT a time adjusted for daylight savings, location etc. +pub fn sys_mono_now() u64 { +	tm := u64(0) +	C.QueryPerformanceCounter(&tm) // XP or later never fail +	return (tm - time.start_time) * 1000000000 / time.freq_time +} + +// NB: vpc_now is used by `v -profile` . +// It should NOT call *any other v function*, just C functions and casts. +[inline] +fn vpc_now() u64 { +	tm := u64(0) +	C.QueryPerformanceCounter(&tm) +	return tm +} + +// local_as_unix_time returns the current local time as unix time +fn local_as_unix_time() int { +	t := C.time(0) +	tm := C.localtime(&t) +	return make_unix_time(tm) +} + +// local - return the time `t`, converted to the currently active local timezone +pub fn (t Time) local() Time { +	st_utc := SystemTime{ +		year: u16(t.year) +		month: u16(t.month) +		day: u16(t.day) +		hour: u16(t.hour) +		minute: u16(t.minute) +		second: u16(t.second) +	} +	st_local := SystemTime{} +	C.SystemTimeToTzSpecificLocalTime(voidptr(0), &st_utc, &st_local) +	t_local := Time{ +		year: st_local.year +		month: st_local.month +		day: st_local.day +		hour: st_local.hour +		minute: st_local.minute +		second: st_local.second // These are the same +		microsecond: st_local.millisecond * 1000 +		unix: u64(st_local.unix_time()) +	} +	return t_local +} + +// win_now calculates current time using winapi to get higher resolution on windows +// GetSystemTimeAsFileTime is used and converted to local time. It can resolve time +// down to millisecond. Other more precice methods can be implemented in the future +fn win_now() Time { +	ft_utc := C._FILETIME{} +	C.GetSystemTimeAsFileTime(&ft_utc) +	st_utc := SystemTime{} +	C.FileTimeToSystemTime(&ft_utc, &st_utc) +	st_local := SystemTime{} +	C.SystemTimeToTzSpecificLocalTime(voidptr(0), &st_utc, &st_local) +	t := Time{ +		year: st_local.year +		month: st_local.month +		day: st_local.day +		hour: st_local.hour +		minute: st_local.minute +		second: st_local.second +		microsecond: st_local.millisecond * 1000 +		unix: u64(st_local.unix_time()) +	} +	return t +} + +// win_utc calculates current time using winapi to get higher resolution on windows +// GetSystemTimeAsFileTime is used. It can resolve time down to millisecond +// other more precice methods can be implemented in the future +fn win_utc() Time { +	ft_utc := C._FILETIME{} +	C.GetSystemTimeAsFileTime(&ft_utc) +	st_utc := SystemTime{} +	C.FileTimeToSystemTime(&ft_utc, &st_utc) +	t := Time{ +		year: st_utc.year +		month: st_utc.month +		day: st_utc.day +		hour: st_utc.hour +		minute: st_utc.minute +		second: st_utc.second +		microsecond: st_utc.millisecond * 1000 +		unix: u64(st_utc.unix_time()) +	} +	return t +} + +// unix_time returns Unix time. +pub fn (st SystemTime) unix_time() int { +	tt := C.tm{ +		tm_sec: st.second +		tm_min: st.minute +		tm_hour: st.hour +		tm_mday: st.day +		tm_mon: st.month - 1 +		tm_year: st.year - 1900 +	} +	return make_unix_time(tt) +} + +// dummy to compile with all compilers +pub fn darwin_now() Time { +	return Time{} +} + +// dummy to compile with all compilers +pub fn linux_now() Time { +	return Time{} +} + +// dummy to compile with all compilers +pub fn solaris_now() Time { +	return Time{} +} + +// dummy to compile with all compilers +pub fn darwin_utc() Time { +	return Time{} +} + +// dummy to compile with all compilers +pub fn linux_utc() Time { +	return Time{} +} + +// dummy to compile with all compilers +pub fn solaris_utc() 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). +pub fn sleep(duration Duration) { +	C.Sleep(int(duration / millisecond)) +} + +// some Windows system functions (e.g. `C.WaitForSingleObject()`) accept an `u32` +// value as *timeout in milliseconds* with the special value `u32(-1)` meaning "infinite" +pub fn (d Duration) sys_milliseconds() u32 { +	if d >= u32(-1) * millisecond { // treat 4294967295000000 .. C.INT64_MAX as "infinite" +		return u32(-1) +	} else if d <= 0 { +		return 0 // treat negative timeouts as 0 - consistent with Unix behaviour +	} else { +		return u32(d / millisecond) +	} +} diff --git a/v_windows/v/old/vlib/time/unix.v b/v_windows/v/old/vlib/time/unix.v new file mode 100644 index 0000000..ac9d010 --- /dev/null +++ b/v_windows/v/old/vlib/time/unix.v @@ -0,0 +1,124 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module time + +// unix returns a time struct from Unix time. +pub fn unix(abs int) Time { +	// Split into day and time +	mut day_offset := abs / seconds_per_day +	if abs % seconds_per_day < 0 { +		// Compensate for round towards zero on integers as we want floored instead +		day_offset-- +	} +	year, month, day := calculate_date_from_offset(day_offset) +	hr, min, sec := calculate_time_from_offset(abs % seconds_per_day) +	return Time{ +		year: year +		month: month +		day: day +		hour: hr +		minute: min +		second: sec +		unix: u64(abs) +	} +} + +// unix2 returns a time struct from Unix time and microsecond value +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 { +		// Compensate for round towards zero on integers as we want floored instead +		day_offset-- +	} +	year, month, day := calculate_date_from_offset(day_offset) +	hr, min, sec := calculate_time_from_offset(abs % seconds_per_day) +	return Time{ +		year: year +		month: month +		day: day +		hour: hr +		minute: min +		second: sec +		microsecond: microsecond +		unix: u64(abs) +	} +} + +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 +	// 1970-2000 (inclusive) has 31 years (8 of which are leap years) +	mut year := 2001 +	day_offset -= 31 * 365 + 8 +	// Account for 400 year cycle +	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 += int(day_offset / days_per_100_years) * 100 +		day_offset %= days_per_100_years +	} +	// Account for 4 year cycle +	if day_offset == days_per_4_years * 25 { +		year += 96 +		day_offset -= days_per_4_years * 24 +	} else { +		year += int(day_offset / days_per_4_years) * 4 +		day_offset %= days_per_4_years +	} +	// Account for every year +	if day_offset == 365 * 4 { +		year += 3 +		day_offset -= 365 * 3 +	} else { +		year += int(day_offset / 365) +		day_offset %= 365 +	} +	if day_offset < 0 { +		year-- +		if is_leap_year(year) { +			day_offset += 366 +		} else { +			day_offset += 365 +		} +	} +	if is_leap_year(year) { +		if day_offset > 31 + 29 - 1 { +			// After leap day; pretend it wasn't there. +			day_offset-- +		} else if day_offset == 31 + 29 - 1 { +			// Leap day. +			return year, 2, 29 +		} +	} +	mut estimated_month := day_offset / 31 +	for day_offset >= days_before[estimated_month + 1] { +		estimated_month++ +	} +	for day_offset < days_before[estimated_month] { +		if estimated_month == 0 { +			break +		} +		estimated_month-- +	} +	day_offset -= days_before[estimated_month] +	return year, int(estimated_month + 1), int(day_offset + 1) +} + +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 +	} +	hour_ := second_offset / seconds_per_hour +	second_offset %= seconds_per_hour +	min := second_offset / seconds_per_minute +	second_offset %= seconds_per_minute +	return int(hour_), int(min), int(second_offset) +}  | 
