diff --git a/vlib/time/format.v b/vlib/time/format.v new file mode 100644 index 0000000000..7d44568538 --- /dev/null +++ b/vlib/time/format.v @@ -0,0 +1,177 @@ +// Copyright (c) 2019-2020 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) +} + +// 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 { + now := time.now() + // Today + if t.month == now.month && t.year == now.year && t.day == now.day { + return t.get_fmt_time_str(.hhmm24) + } + // This year + if t.year == now.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 { + now := time.now() + // Today + if t.month == now.month && t.year == now.year && t.day == now.day { + return t.get_fmt_time_str(.hhmm12) + } + // This year + if t.year == now.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}' + } + 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.str()[2..] + return match fmt_date { + .ddmmyy{ + '${t.day:02d}|${t.month:02d}|$year' + } + .ddmmyyyy{ + '${t.day:02d}|${t.month:02d}|${t.year}' + } + .mmddyy{ + '${t.month:02d}|${t.day:02d}|$year' + } + .mmddyyyy{ + '${t.month:02d}|${t.day:02d}|${t.year}' + } + .mmmd{ + '$month|${t.day}' + } + .mmmdd{ + '$month|${t.day:02d}' + } + .mmmddyyyy{ + '$month|${t.day:02d}|${t.year}' + } + .yyyymmdd{ + '${t.year}|${t.month:02d}|${t.day:02d}' + } + else { + 'unknown enumeration $fmt_date'}}.replace('|', match fmt_dlmtr { + .dot{ + '.' + } + .hyphen{ + '-' + } + .slash{ + '/' + } + .space{ + ' ' + } + else { + 'unknown enumeration $fmt_dlmtr'}}) +} + +// 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) + } + } +} diff --git a/vlib/time/format_test.v b/vlib/time/format_test.v new file mode 100644 index 0000000000..b3924b04e7 --- /dev/null +++ b/vlib/time/format_test.v @@ -0,0 +1,84 @@ +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(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 1980' == time_to_test.get_fmt_date_str(.space, .mmmddyyyy) + assert '1980-07-11' == time_to_test.get_fmt_date_str(.hyphen, .yyyymmdd) +} + +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) +} diff --git a/vlib/time/misc/misc.v b/vlib/time/misc/misc.v index f619976d61..aa4b7efb56 100644 --- a/vlib/time/misc/misc.v +++ b/vlib/time/misc/misc.v @@ -6,7 +6,7 @@ import time const ( start_time_unix = time.now().unix ) -// random will return a random time.Time in *the past* +// random returns a random time struct in *the past*. pub fn random() time.Time { return time.unix(rand.next(start_time_unix)) } diff --git a/vlib/time/parse.v b/vlib/time/parse.v new file mode 100644 index 0000000000..e883fe92e1 --- /dev/null +++ b/vlib/time/parse.v @@ -0,0 +1,53 @@ +// Copyright (c) 2019-2020 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] + + return new_time(Time{ + year: ymd[0].int() + month: ymd[1].int() + day: ymd[2].int() + hour: hour.int() + minute: minute.int() + second: second.int() + }) +} + +// 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 + mut tmstr := byteptr(0) + unsafe { tmstr = malloc(s.len * 2) } + count := C.sprintf(charptr(tmstr), '%s-%02d-%s %s'.str, fields[3].str, mm, + fields[1].str, fields[4].str) + + t := parse(tos(tmstr, count)) or { + // FIXME Remove this when optional forwarding is fixed. + return error('Invalid time format: $s') + } + + return t +} diff --git a/vlib/time/parse_test.v b/vlib/time/parse_test.v new file mode 100644 index 0000000000..892436c5dd --- /dev/null +++ b/vlib/time/parse_test.v @@ -0,0 +1,46 @@ +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' + t := 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' + t3 := time.parse_rfc2822(s3) or { + assert true + return + } + assert false +} diff --git a/vlib/time/time.v b/vlib/time/time.v index 8cbf7e96c9..6ef8e5b28a 100644 --- a/vlib/time/time.v +++ b/vlib/time/time.v @@ -3,6 +3,8 @@ // that can be found in the LICENSE file. module time +#include + const ( days_string = 'MonTueWedThuFriSatSun' month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] @@ -21,7 +23,6 @@ const ( 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, ] ) -#include pub struct Time { pub: year int @@ -60,14 +61,18 @@ pub enum FormatDelimiter { space } -fn C.localtime(int) &C.tm - - pub struct C.time_t {} +pub struct C.timeval { + tv_sec u64 + tv_usec u64 +} + +fn C.localtime(int) &C.tm + fn C.time(int) C.time_t - +// now returns current local time. pub fn now() Time { t := C.time(0) mut now := &C.tm(0) @@ -75,155 +80,13 @@ pub fn now() Time { return convert_ctime(now) } -// format_ss returns a string for t in a given format YYYY-MM-DD HH:MM:SS in -// 24h notation -// @param -// @return string -// @example 1980-07-11 21:23:42 -pub fn (t Time) format_ss() string { - return t.get_fmt_str(.hyphen, .hhmmss24, .yyyymmdd) -} - -// format_ss returns a string for t in a given format YYYY-MM-DD HH:MM in 24h -// notation -// @param -// @return string -// @example 1980-07-11 21:23 -pub fn (t Time) format() string { - return t.get_fmt_str(.hyphen, .hhmm24, .yyyymmdd) -} - +// smonth returns month name. pub fn (t Time) smonth() string { i := t.month - 1 return months_string[i * 3..(i + 1) * 3] } -// hhmm returns a string for t in the given format HH:MM in 24h notation -// @example 21:04 -pub fn (t Time) hhmm() string { - return t.get_fmt_time_str(.hhmm24) -} - -/* -fn (t Time) hhmm_tmp() string { - return '${t.hour:02d}:${t.minute:02d}' -} -*/ - -// hhmm12 returns a string for t in the given format HH:MM in 12h notation -pub fn (t Time) hhmm12() string { - return t.get_fmt_time_str(.hhmm12) -} - -// hhmmss returns a string for t in the given format HH:MM:SS in 24h notation -pub fn (t Time) hhmmss() string { - return t.get_fmt_time_str(.hhmmss24) -} - -// ymmdd returns a string for t in the given format YYYY-MM-DD -pub fn (t Time) ymmdd() string { - return t.get_fmt_date_str(.hyphen, .yyyymmdd) -} - -// ddmmy returns a string for t in the given format DD.MM.YYYY -pub fn (t Time) ddmmy() string { - return t.get_fmt_date_str(.dot, .ddmmyyyy) -} - -// md returns a string for t in the given format MMM D -pub fn (t Time) md() string { - return t.get_fmt_date_str(.space, .mmmd) -} - -pub fn (t Time) clean() string { - nowe := time.now() - // if amtime { - // hm = t.Format("3:04 pm") - // } - // Today - if t.month == nowe.month && t.year == nowe.year && t.day == nowe.day { - return t.get_fmt_time_str(.hhmm24) - } - // This week - // if time.Since(t) < 24*7*time.Hour { - // return t.Weekday().String()[:3] + " " + hm - // } - // This year - if t.year == nowe.year { - return t.get_fmt_str(.space, .hhmm24, .mmmd) - } - return t.format() - // return fmt.Sprintf("%4d/%02d/%02d", t.Year(), t.Month(), t.Day()) + " " + hm -} - -pub fn (t Time) clean12() string { - nowe := time.now() - // if amtime { - // hm = t.Format("3:04 pm") - // } - // Today - if t.month == nowe.month && t.year == nowe.year && t.day == nowe.day { - return t.get_fmt_time_str(.hhmm12) - } - // This week - // if time.Since(t) < 24*7*time.Hour { - // return t.Weekday().String()[:3] + " " + hm - // } - // This year - if t.year == nowe.year { - return t.get_fmt_str(.space, .hhmm12, .mmmd) - } - return t.format() - // return fmt.Sprintf("%4d/%02d/%02d", t.Year(), t.Month(), t.Day()) + " " + hm -} -// `parse` parses time in the following format: "2018-01-27 12:48:34" -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] - - return new_time(Time{ - year: ymd[0].int() - month: ymd[1].int() - day: ymd[2].int() - hour: hour.int() - minute: minute.int() - second: second.int() - }) -} - -// `parse_iso` parses time in the following format: "Thu, 12 Dec 2019 06:07:45 GMT" -pub fn parse_iso(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 - tmstr := malloc(s.len * 2) - count := C.sprintf(charptr(tmstr), '%s-%02d-%s %s'.str, fields[3].str, mm, - fields[1].str, fields[4].str) - - t := parse(tos(tmstr, count)) or { - // FIXME Remove this when optional forwarding is fixed. - return error('Invalid time format: $s') - } - - return t -} - +// new_time returns a time struct with calculated Unix time. pub fn new_time(t Time) Time { return Time{ year: t.year @@ -234,16 +97,14 @@ pub fn new_time(t Time) Time { second: t.second unix: t.calc_unix() } - // TODO: Use the syntax below when it works with reserved keywords like `unix` - /* - return { - t | - unix:t.calc_unix() - } - */ - + // TODO Use the syntax below when it works with reserved keywords like `unix` + // return { + // t | + // unix:t.calc_unix() + // } } +// calc_unix returns Unix time. pub fn (t &Time) calc_unix() int { if t.unix != 0 { return t.unix @@ -259,20 +120,25 @@ pub fn (t &Time) calc_unix() int { return make_unix_time(tt) } -// TODO add(d time.Duration) +// add_days returns a new time struct with an added number of seconds. pub fn (t Time) add_seconds(seconds int) Time { + // TODO Add(d time.Duration) return unix(t.unix + seconds) } +// add_days returns a new time struct with an added number of days. pub fn (t Time) add_days(days int) Time { return unix(t.unix + days * 3600 * 24) } -// TODO use time.Duration instead of seconds +// 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 difference between time +// and current time. pub fn (t Time) relative() string { now := time.now() secs := now.unix - t.unix @@ -299,6 +165,8 @@ pub fn (t Time) relative() string { 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, m, d int) int { // Sakomotho's algorithm is explained here: // https://stackoverflow.com/a/6385934 @@ -310,22 +178,18 @@ pub fn day_of_week(y, m, d int) int { 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 in string (upto 3 characters) +// weekday_str returns the current day as a string. pub fn (t Time) weekday_str() string { i := t.day_of_week() - 1 return days_string[i * 3..(i + 1) * 3] } -pub struct C.timeval { - tv_sec u64 - tv_usec u64 -} - -// in ms +// ticks returns a number of milliseconds elapsed since system start. pub fn ticks() i64 { $if windows { return C.GetTickCount() @@ -334,14 +198,12 @@ pub fn ticks() i64 { 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; -*/ - + // 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. pub fn sleep(seconds int) { $if windows { C.Sleep(seconds * 1000) @@ -350,6 +212,7 @@ pub fn sleep(seconds int) { } } +// sleep_ms makes the calling thread sleep for a given number of milliseconds. pub fn sleep_ms(milliseconds int) { $if windows { C.Sleep(milliseconds) @@ -358,6 +221,7 @@ pub fn sleep_ms(milliseconds int) { } } +// usleep makes the calling thread sleep for a given number of microseconds. pub fn usleep(microseconds int) { $if windows { milliseconds := microseconds / 1000 @@ -367,12 +231,12 @@ pub fn usleep(microseconds int) { } } -// Determine whether a year is a leap year. +// 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) } -// Returns number of days in month +// days_in_month returns a number of days in a given month. pub fn days_in_month(month, year int) ?int { if month > 12 || month < 1 { return error('Invalid month: $month') @@ -382,115 +246,10 @@ pub fn days_in_month(month, year int) ?int { return res } -// get_fmt_time_str returns a string for time t in a given format -// @param FormatTime -// @return string -// @example 21:23:42 -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}' - } - else { - 'unknown enumeration $fmt_time'} - } -} - -// get_fmt_date_str returns a string for t in a given date format -// @param FormatDelimiter, FormatDate -// @return string -// @example 11.07.1980 -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.str()[2..] - return match fmt_date { - .ddmmyy{ - '${t.day:02d}|${t.month:02d}|$year' - } - .ddmmyyyy{ - '${t.day:02d}|${t.month:02d}|${t.year}' - } - .mmddyy{ - '${t.month:02d}|${t.day:02d}|$year' - } - .mmddyyyy{ - '${t.month:02d}|${t.day:02d}|${t.year}' - } - .mmmd{ - '$month|${t.day}' - } - .mmmdd{ - '$month|${t.day:02d}' - } - .mmmddyyyy{ - '$month|${t.day:02d}|${t.year}' - } - .yyyymmdd{ - '${t.year}|${t.month:02d}|${t.day:02d}' - } - else { - 'unknown enumeration $fmt_date'}}.replace('|', match fmt_dlmtr { - .dot{ - '.' - } - .hyphen{ - '-' - } - .slash{ - '/' - } - .space{ - ' ' - } - else { - 'unknown enumeration $fmt_dlmtr'}}) -} - -// get_fmt_str returns a string for t in a given format for time and date -// @param FormatDelimiter, FormatTime, FormatDate -// @return string -// @example 11.07.1980 21:23:42 -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) - } - } -} - -// `str` returns time in the same format as `parse` expects: "2018-01-27 12:48:34" -// TODO define common default format for `str` and `parse` and use it in both ways +// 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() } diff --git a/vlib/time/time_test.v b/vlib/time/time_test.v index d78a65d488..39c4edae24 100644 --- a/vlib/time/time_test.v +++ b/vlib/time/time_test.v @@ -1,14 +1,15 @@ import time const ( - time_to_test = time.new_time(time.Time{ + time_to_test = time.Time{ year: 1980 month: 7 day: 11 hour: 21 minute: 23 second: 42 - }) + unix: 332198622 + } ) fn test_is_leap_year() { @@ -22,15 +23,6 @@ fn test_is_leap_year() { assert time.is_leap_year(2100) == false } -fn test_now_format() { - t := time.now() - u := t.unix - println(u) - println(t.format()) - println(time.unix(u).format()) - assert t.format() == time.unix(u).format() -} - fn check_days_in_month(month, year, expected int) bool { res := time.days_in_month(month, year) or { return false @@ -113,34 +105,6 @@ fn test_smonth() { } } -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_day_of_week() { for i := 0; i < 7; i++ { day_of_week := i + 1 @@ -182,88 +146,6 @@ fn test_add_days() { assert t.unix == time_to_test.unix + 86400 * num_of_days } -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 1980' == time_to_test.get_fmt_date_str(.space, .mmmddyyyy) - assert '1980-07-11' == time_to_test.get_fmt_date_str(.hyphen, .yyyymmdd) -} - -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_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' - t := time.parse(s) or { - assert true - return - } - assert false -} - -fn test_parse_iso() { - s1 := 'Thu, 12 Dec 2019 06:07:45 GMT' - t1 := time.parse_iso(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_iso(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_iso_invalid() { - s3 := 'Thu 12 Foo 2019 06:07:45 +0800' - t3 := time.parse_iso(s3) or { - assert true - return - } - assert false -} - fn test_str() { assert '1980-07-11 21:23:42' == time_to_test.str() } diff --git a/vlib/time/time_unix.v b/vlib/time/unix.v similarity index 98% rename from vlib/time/time_unix.v rename to vlib/time/unix.v index 6e1f1a473f..74d60f95ab 100644 --- a/vlib/time/time_unix.v +++ b/vlib/time/unix.v @@ -3,6 +3,7 @@ // 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