From 25df4fa143dc08179b53c836c9038c40a8830eae Mon Sep 17 00:00:00 2001 From: David 'Epper' Marshall Date: Fri, 29 Apr 2022 08:57:08 -0400 Subject: [PATCH] time: add custom formatter (#14202) --- vlib/math/math_bench_test.v | 249 +++++++++++++++---------------- vlib/time/custom_format_test.v | 11 ++ vlib/time/format.v | 261 +++++++++++++++++++++++++++++++++ vlib/time/time.v | 12 +- 4 files changed, 395 insertions(+), 138 deletions(-) create mode 100644 vlib/time/custom_format_test.v diff --git a/vlib/math/math_bench_test.v b/vlib/math/math_bench_test.v index 596af933f8..43c76c4983 100644 --- a/vlib/math/math_bench_test.v +++ b/vlib/math/math_bench_test.v @@ -1,5 +1,6 @@ -module math +module main +import math import benchmark const max_iter = 1000 @@ -7,8 +8,8 @@ const max_iter = 1000 fn test_benchmark_acos() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = acos(0.5) + for i in 0 .. max_iter { + x = math.acos(0.5) } bmark.measure(@FN) } @@ -16,8 +17,8 @@ fn test_benchmark_acos() { fn test_benchmark_acosh() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = acosh(1.5) + for i in 0 .. max_iter { + x = math.acosh(1.5) } bmark.measure(@FN) } @@ -25,8 +26,8 @@ fn test_benchmark_acosh() { fn test_benchmark_asin() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = asin(0.5) + for i in 0 .. max_iter { + x = math.asin(0.5) } bmark.measure(@FN) } @@ -34,8 +35,8 @@ fn test_benchmark_asin() { fn test_benchmark_asinh() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = asinh(0.5) + for i in 0 .. max_iter { + x = math.asinh(0.5) } bmark.measure(@FN) } @@ -43,8 +44,8 @@ fn test_benchmark_asinh() { fn test_benchmark_atan() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = atan(0.5) + for i in 0 .. max_iter { + x = math.atan(0.5) } bmark.measure(@FN) } @@ -52,8 +53,8 @@ fn test_benchmark_atan() { fn test_benchmark_atanh() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = atanh(0.5) + for i in 0 .. max_iter { + x = math.atanh(0.5) } bmark.measure(@FN) } @@ -61,8 +62,8 @@ fn test_benchmark_atanh() { fn test_benchmark_atan2() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = atan2(0.5, 1) + for i in 0 .. max_iter { + x = math.atan2(0.5, 1) } bmark.measure(@FN) } @@ -70,8 +71,8 @@ fn test_benchmark_atan2() { fn test_benchmark_cbrt() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = cbrt(10) + for i in 0 .. max_iter { + x = math.cbrt(10) } bmark.measure(@FN) } @@ -79,19 +80,17 @@ fn test_benchmark_cbrt() { fn test_benchmark_ceil() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = ceil(0.5) + for i in 0 .. max_iter { + x = math.ceil(0.5) } bmark.measure(@FN) } -const copysign_neg = -1.0 - fn test_benchmark_copysign() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = copysign(0.5, math.copysign_neg) + for i in 0 .. max_iter { + x = math.copysign(0.5, -1.0) } bmark.measure(@FN) } @@ -99,8 +98,8 @@ fn test_benchmark_copysign() { fn test_benchmark_cos() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = cos(0.5) + for i in 0 .. max_iter { + x = math.cos(0.5) } bmark.measure(@FN) } @@ -108,8 +107,8 @@ fn test_benchmark_cos() { fn test_benchmark_cosh() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = cosh(2.5) + for i in 0 .. max_iter { + x = math.cosh(2.5) } bmark.measure(@FN) } @@ -117,8 +116,8 @@ fn test_benchmark_cosh() { fn test_benchmark_erf() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = erf(0.5) + for i in 0 .. max_iter { + x = math.erf(0.5) } bmark.measure(@FN) } @@ -126,8 +125,8 @@ fn test_benchmark_erf() { fn test_benchmark_erfc() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = erfc(0.5) + for i in 0 .. max_iter { + x = math.erfc(0.5) } bmark.measure(@FN) } @@ -135,8 +134,8 @@ fn test_benchmark_erfc() { fn test_benchmark_exp() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = exp(0.5) + for i in 0 .. max_iter { + x = math.exp(0.5) } bmark.measure(@FN) } @@ -144,8 +143,8 @@ fn test_benchmark_exp() { fn test_benchmark_expm1() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = expm1(0.5) + for i in 0 .. max_iter { + x = math.expm1(0.5) } bmark.measure(@FN) } @@ -153,19 +152,17 @@ fn test_benchmark_expm1() { fn test_benchmark_exp2() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = exp2(0.5) + for i in 0 .. max_iter { + x = math.exp2(0.5) } bmark.measure(@FN) } -const abs_pos = 0.5 - fn test_benchmark_abs() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = abs(math.abs_pos) + for i in 0 .. max_iter { + x = math.abs(0.5) } bmark.measure(@FN) } @@ -173,8 +170,8 @@ fn test_benchmark_abs() { fn test_benchmark_floor() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = floor(0.5) + for i in 0 .. max_iter { + x = math.floor(0.5) } bmark.measure(@FN) } @@ -182,8 +179,8 @@ fn test_benchmark_floor() { fn test_benchmark_max() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = max(10, 3) + for i in 0 .. max_iter { + x = math.max(10, 3) } bmark.measure(@FN) } @@ -191,8 +188,8 @@ fn test_benchmark_max() { fn test_benchmark_min() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = min(10, 3) + for i in 0 .. max_iter { + x = math.min(10, 3) } bmark.measure(@FN) } @@ -200,8 +197,8 @@ fn test_benchmark_min() { fn test_benchmark_mod() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = mod(10, 3) + for i in 0 .. max_iter { + x = math.mod(10, 3) } bmark.measure(@FN) } @@ -210,8 +207,8 @@ fn test_benchmark_frexp() { mut x := 0.0 mut y := 0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x, y = frexp(8) + for i in 0 .. max_iter { + x, y = math.frexp(8) } bmark.measure(@FN) } @@ -219,8 +216,8 @@ fn test_benchmark_frexp() { fn test_benchmark_gamma() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = gamma(2.5) + for i in 0 .. max_iter { + x = math.gamma(2.5) } bmark.measure(@FN) } @@ -228,8 +225,8 @@ fn test_benchmark_gamma() { fn test_benchmark_hypot() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = hypot(3, 4) + for i in 0 .. max_iter { + x = math.hypot(3, 4) } bmark.measure(@FN) } @@ -237,8 +234,8 @@ fn test_benchmark_hypot() { fn test_benchmark_ldexp() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = ldexp(0.5, 2) + for i in 0 .. max_iter { + x = math.ldexp(0.5, 2) } bmark.measure(@FN) } @@ -246,8 +243,8 @@ fn test_benchmark_ldexp() { fn test_benchmark_log_gamma() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = log_gamma(2.5) + for i in 0 .. max_iter { + x = math.log_gamma(2.5) } bmark.measure(@FN) } @@ -255,8 +252,8 @@ fn test_benchmark_log_gamma() { fn test_benchmark_log() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = log(0.5) + for i in 0 .. max_iter { + x = math.log(0.5) } bmark.measure(@FN) } @@ -264,8 +261,8 @@ fn test_benchmark_log() { fn test_benchmark_log_b() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = log_b(0.5) + for i in 0 .. max_iter { + x = math.log_b(0.5) } bmark.measure(@FN) } @@ -273,8 +270,8 @@ fn test_benchmark_log_b() { fn test_benchmark_log1p() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = log1p(0.5) + for i in 0 .. max_iter { + x = math.log1p(0.5) } bmark.measure(@FN) } @@ -282,8 +279,8 @@ fn test_benchmark_log1p() { fn test_benchmark_log10() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = log10(0.5) + for i in 0 .. max_iter { + x = math.log10(0.5) } bmark.measure(@FN) } @@ -291,8 +288,8 @@ fn test_benchmark_log10() { fn test_benchmark_log2() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = log2(0.5) + for i in 0 .. max_iter { + x = math.log2(0.5) } bmark.measure(@FN) } @@ -301,8 +298,8 @@ fn test_benchmark_modf() { mut x := 0.0 mut y := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x, y = modf(1.5) + for i in 0 .. max_iter { + x, y = math.modf(1.5) } bmark.measure(@FN) } @@ -310,8 +307,8 @@ fn test_benchmark_modf() { fn test_benchmark_nextafter32() { mut x := f32(0.0) mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = nextafter32(0.5, 1) + for i in 0 .. max_iter { + x = math.nextafter32(0.5, 1) } bmark.measure(@FN) } @@ -319,8 +316,8 @@ fn test_benchmark_nextafter32() { fn test_benchmark_nextafter64() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = nextafter(0.5, 1) + for i in 0 .. max_iter { + x = math.nextafter(0.5, 1) } bmark.measure(@FN) } @@ -328,8 +325,8 @@ fn test_benchmark_nextafter64() { fn test_benchmark_pow_int() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = pow(2, 2) + for i in 0 .. max_iter { + x = math.pow(2, 2) } bmark.measure(@FN) } @@ -337,41 +334,35 @@ fn test_benchmark_pow_int() { fn test_benchmark_pow_frac() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = pow(2.5, 1.5) + for i in 0 .. max_iter { + x = math.pow(2.5, 1.5) } bmark.measure(@FN) } -const pow10pos = int(300) - fn test_benchmark_pow10_pos() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = pow10(math.pow10pos) + for i in 0 .. max_iter { + x = math.pow10(300) } bmark.measure(@FN) } -const pow10neg = int(-300) - fn test_benchmark_pow10_neg() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = pow10(math.pow10neg) + for i in 0 .. max_iter { + x = math.pow10(-300) } bmark.measure(@FN) } -const round_neg = f64(-2.5) - fn test_benchmark_round() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = round(math.round_neg) + for i in 0 .. max_iter { + x = math.round(-2.5) } bmark.measure(@FN) } @@ -379,19 +370,17 @@ fn test_benchmark_round() { fn test_benchmark_round_to_even() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = round_to_even(math.round_neg) + for i in 0 .. max_iter { + x = math.round_to_even(-2.5) } bmark.measure(@FN) } -const signbit_pos = 2.5 - fn test_benchmark_signbit() { mut x := false mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = signbit(math.signbit_pos) + for i in 0 .. max_iter { + x = math.signbit(2.5) } bmark.measure(@FN) } @@ -399,8 +388,8 @@ fn test_benchmark_signbit() { fn test_benchmark_sin() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = sin(0.5) + for i in 0 .. max_iter { + x = math.sin(0.5) } bmark.measure(@FN) } @@ -409,8 +398,8 @@ fn test_benchmark_sincos() { mut x := 0.0 mut y := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x, y = sincos(0.5) + for i in 0 .. max_iter { + x, y = math.sincos(0.5) } bmark.measure(@FN) } @@ -418,17 +407,17 @@ fn test_benchmark_sincos() { fn test_benchmark_sinh() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = sinh(2.5) + for i in 0 .. max_iter { + x = math.sinh(2.5) } bmark.measure(@FN) } fn test_benchmark_sqrt_indirect() { mut x, y := 0.0, 10.0 - f := sqrt + f := math.sqrt mut bmark := benchmark.start() - for i in 0 .. math.max_iter { + for i in 0 .. max_iter { x += f(y) } bmark.measure(@FN) @@ -437,17 +426,17 @@ fn test_benchmark_sqrt_indirect() { fn test_benchmark_sqrt_latency() { mut x := 10.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = sqrt(x) + for i in 0 .. max_iter { + x = math.sqrt(x) } bmark.measure(@FN) } fn test_benchmark_sqrt_indirect_latency() { mut x := 10.0 - f := sqrt + f := math.sqrt mut bmark := benchmark.start() - for i in 0 .. math.max_iter { + for i in 0 .. max_iter { x = f(x) } bmark.measure(@FN) @@ -459,7 +448,7 @@ fn is_prime(i int) bool { // the benefit of using a direct sqrt instruction on systems // that have one, whereas the obvious loop seems not to // demonstrate such a benefit. - for j := 2; f64(j) <= sqrt(f64(i)); j++ { + for j := 2; f64(j) <= math.sqrt(f64(i)); j++ { if i % j == 0 { return false } @@ -470,7 +459,7 @@ fn is_prime(i int) bool { fn test_benchmark_sqrt_prime() { mut x := false mut bmark := benchmark.start() - for i in 0 .. math.max_iter { + for i in 0 .. max_iter { x = is_prime(100003) } bmark.measure(@FN) @@ -479,8 +468,8 @@ fn test_benchmark_sqrt_prime() { fn test_benchmark_tan() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = tan(0.5) + for i in 0 .. max_iter { + x = math.tan(0.5) } bmark.measure(@FN) } @@ -488,8 +477,8 @@ fn test_benchmark_tan() { fn test_benchmark_tanh() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = tanh(2.5) + for i in 0 .. max_iter { + x = math.tanh(2.5) } bmark.measure(@FN) } @@ -497,50 +486,44 @@ fn test_benchmark_tanh() { fn test_benchmark_trunc() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = trunc(0.5) + for i in 0 .. max_iter { + x = math.trunc(0.5) } bmark.measure(@FN) } fn test_benchmark_f64_bits() { - mut y := u64(0) + mut x := u64(0) mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - y = f64_bits(math.round_neg) + for i in 0 .. max_iter { + x = math.f64_bits(-2.5) } bmark.measure(@FN) } -const round_u64 = u64(5) - fn test_benchmark_f64_from_bits() { mut x := 0.0 mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = f64_from_bits(math.round_u64) + for i in 0 .. max_iter { + x = math.f64_from_bits(5) } bmark.measure(@FN) } -const round_f32 = f32(-2.5) - fn test_benchmark_f32_bits() { - mut y := u32(0) + mut x := u32(0) mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - y = f32_bits(math.round_f32) + for i in 0 .. max_iter { + x = math.f32_bits(-2.5) } bmark.measure(@FN) } -const round_u32 = u32(5) - fn test_benchmark_f32_from_bits() { mut x := f32(0.0) mut bmark := benchmark.start() - for i in 0 .. math.max_iter { - x = f32_from_bits(math.round_u32) + for i in 0 .. max_iter { + x = math.f32_from_bits(5) } bmark.measure(@FN) } diff --git a/vlib/time/custom_format_test.v b/vlib/time/custom_format_test.v new file mode 100644 index 0000000000..aa8a4fd27b --- /dev/null +++ b/vlib/time/custom_format_test.v @@ -0,0 +1,11 @@ +import time + +fn test_custom_format() { + date := time.now() + assert date.custom_format('YYYY-MM-DD HH:mm') == date.format() + assert date.custom_format('MMM') == date.smonth() + + test_str := 'M MM MMM MMMM\nD DD DDD DDDD\nd dd ddd dddd\nYY YYYY a A\nH HH h hh k kk e\nm mm s ss Z ZZ ZZZ\nDo DDDo Q Qo QQ\nN NN w wo ww\nM/D/YYYY N-HH:mm:ss Qo?a' + + println(date.custom_format(test_str)) +} diff --git a/vlib/time/format.v b/vlib/time/format.v index 02a9c1dd5d..17c4d5116e 100644 --- a/vlib/time/format.v +++ b/vlib/time/format.v @@ -3,6 +3,9 @@ // that can be found in the LICENSE file. module time +import strings +import math + // 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) @@ -53,6 +56,264 @@ pub fn (t Time) md() string { return t.get_fmt_date_str(.space, .mmmd) } +// appends ordinal suffix to a number +fn ordinal_suffix(n int) string { + if n > 3 && n < 21 { + return '${n}th' + } + match n % 10 { + 1 { + return '${n}st' + } + 2 { + return '${n}nd' + } + 3 { + return '${n}rd' + } + else { + return '${n}th' + } + } +} + +const tokens_2 = ['MM', 'DD', 'Do', 'YY', 'ss', 'kk', 'NN', 'mm', 'hh', 'HH', 'ZZ', 'dd', 'Qo', + 'QQ', 'wo', 'ww'] + +const tokens_3 = ['MMM', 'DDD', 'ZZZ', 'ddd'] + +const tokens_4 = ['MMMM', 'DDDD', 'DDDo', 'dddd', 'YYYY'] + +// custom_format returns a date with custom format +// | | Token | Output | +// | :----------- | -------: | :--------- | +// | Month | M | 1 2 ... 11 12 | +// | | Mo | 1st 2nd ... 11th 12th | +// | | MM | 01 02 ... 11 12 | +// | | MMM | Jan Feb ... Nov Dec | +// | | MMMM | January February ... November December | +// | Quarter | Q | 1 2 3 4 | +// | | QQ | 01 02 03 04 | +// | | Qo | 1st 2nd 3rd 4th | +// | Day of Month | D | 1 2 ... 30 31 | +// | | Do | 1st 2nd ... 30th 31st | +// | | DD | 01 02 ... 30 31 | +// | Day of Year | DDD | 1 2 ... 364 365 | +// | | DDDo | 1st 2nd ... 364th 365th | +// | | DDDD | 001 002 ... 364 365 | +// | Day of Week | d | 0 1 ... 5 6 (Sun-Sat) | +// | | c | 1 2 ... 6 7 (Mon-Sun) | +// | | dd | Su Mo ... Fr Sa | +// | | ddd | Sun Mon ... Fri Sat | +// | | dddd | Sunday Monday ... Friday Saturday | +// | Week of Year | w | 1 2 ... 52 53 | +// | | wo | 1st 2nd ... 52nd 53rd | +// | | ww | 01 02 ... 52 53 | +// | Year | YY | 70 71 ... 29 30 | +// | | YYYY | 1970 1971 ... 2029 2030 | +// | Era | N | BC AD | +// | | NN | Before Christ, Anno Domini | +// | AM/PM | A | AM PM | +// | | a | am pm | +// | Hour | H | 0 1 ... 22 23 | +// | | HH | 00 01 ... 22 23 | +// | | h | 1 2 ... 11 12 | +// | | hh | 01 02 ... 11 12 | +// | | k | 1 2 ... 23 24 | +// | | kk | 01 02 ... 23 24 | +// | Minute | m | 0 1 ... 58 59 | +// | | mm | 00 01 ... 58 59 | +// | Second | s | 0 1 ... 58 59 | +// | | ss | 00 01 ... 58 59 | +// | Offset | Z | -7 -6 ... +5 +6 | +// | | ZZ | -0700 -0600 ... +0500 +0600 | +// | | ZZZ | -07:00 -06:00 ... +05:00 +06:00 | +pub fn (t Time) custom_format(s string) string { + mut tokens := []string{} + for i := 0; i < s.len; { + for j := 4; j > 0; j-- { + if i > s.len - j { + continue + } + if j == 1 || (j == 2 && s[i..i + j] in time.tokens_2) + || (j == 3 && s[i..i + j] in time.tokens_3) + || (j == 4 && s[i..i + j] in time.tokens_4) { + tokens << s[i..i + j] + i += (j - 1) + break + } + } + i++ + } + mut sb := strings.new_builder(128) + + for token in tokens { + match token { + 'M' { + sb.write_string(t.month.str()) + } + 'MM' { + sb.write_string('${t.month:02}') + } + 'Mo' { + sb.write_string(ordinal_suffix(t.month)) + } + 'MMM' { + sb.write_string(long_months[t.month - 1][0..3]) + } + 'MMMM' { + sb.write_string(long_months[t.month - 1]) + } + 'D' { + sb.write_string(t.day.str()) + } + 'DD' { + sb.write_string('${t.day:02}') + } + 'Do' { + sb.write_string(ordinal_suffix(t.day)) + } + 'DDD' { + sb.write_string((t.day + days_before[t.month - 1] + int(is_leap_year(t.year))).str()) + } + 'DDDD' { + sb.write_string('${t.day + days_before[t.month - 1] + int(is_leap_year(t.year)):03}') + } + 'DDDo' { + sb.write_string(ordinal_suffix(t.day + days_before[t.month - 1] + + int(is_leap_year(t.year)))) + } + 'd' { + sb.write_string(t.day_of_week().str()) + } + 'dd' { + sb.write_string(long_days[t.day_of_week() - 1][0..2]) + } + 'ddd' { + sb.write_string(long_days[t.day_of_week() - 1][0..3]) + } + 'dddd' { + sb.write_string(long_days[t.day_of_week() - 1]) + } + 'YY' { + sb.write_string(t.year.str()[2..4]) + } + 'YYYY' { + sb.write_string(t.year.str()) + } + 'H' { + sb.write_string(t.hour.str()) + } + 'HH' { + sb.write_string('${t.hour:02}') + } + 'h' { + sb.write_string((t.hour % 12).str()) + } + 'hh' { + sb.write_string('${(t.hour % 12):02}') + } + 'm' { + sb.write_string(t.minute.str()) + } + 'mm' { + sb.write_string('${t.minute:02}') + } + 's' { + sb.write_string(t.second.str()) + } + 'ss' { + sb.write_string('${t.second:02}') + } + 'k' { + sb.write_string((t.hour + 1).str()) + } + 'kk' { + sb.write_string('${(t.hour + 1):02}') + } + 'w' { + sb.write_string('${math.ceil((t.day + days_before[t.month - 1] + + int(is_leap_year(t.year))) / 7):.0}') + } + 'ww' { + sb.write_string('${math.ceil((t.day + days_before[t.month - 1] + + int(is_leap_year(t.year))) / 7):02.0}') + } + 'wo' { + sb.write_string(ordinal_suffix(int(math.ceil((t.day + days_before[t.month - 1] + + int(is_leap_year(t.year))) / 7)))) + } + 'Q' { + sb.write_string('${(t.month % 4) + 1}') + } + 'QQ' { + sb.write_string('${(t.month % 4) + 1:02}') + } + 'Qo' { + sb.write_string(ordinal_suffix((t.month % 4) + 1)) + } + 'c' { + sb.write_string('${t.day_of_week() + 1}') + } + 'N' { + // TODO integrate BC + sb.write_string('AD') + } + 'NN' { + // TODO integrate Before Christ + sb.write_string('Anno Domini') + } + 'Z' { + mut hours := offset() / seconds_per_hour + if hours >= 0 { + sb.write_string('+$hours') + } else { + hours = -hours + sb.write_string('-$hours') + } + } + 'ZZ' { + // TODO update if minute differs? + mut hours := offset() / seconds_per_hour + if hours >= 0 { + sb.write_string('+${hours:02}00') + } else { + hours = -hours + sb.write_string('-${hours:02}00') + } + } + 'ZZZ' { + // TODO update if minute differs? + mut hours := offset() / seconds_per_hour + if hours >= 0 { + sb.write_string('+${hours:02}:00') + } else { + hours = -hours + sb.write_string('-${hours:02}:00') + } + } + 'a' { + if t.hour > 12 { + sb.write_string('pm') + } else { + sb.write_string('am') + } + } + 'A' { + if t.hour > 12 { + sb.write_string('PM') + } else { + sb.write_string('AM') + } + } + else { + sb.write_string(token) + } + } + } + return sb.str() +} + // 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 diff --git a/vlib/time/time.v b/vlib/time/time.v index 986d729cfe..072c866b35 100644 --- a/vlib/time/time.v +++ b/vlib/time/time.v @@ -2,8 +2,12 @@ module time pub const ( days_string = 'MonTueWedThuFriSatSun' + long_days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', + 'Sunday'] month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] months_string = 'JanFebMarAprMayJunJulAugSepOctNovDec' + long_months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', + 'September', 'October', 'November', 'December'] // 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. @@ -30,8 +34,6 @@ pub const ( 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. @@ -83,7 +85,7 @@ pub enum FormatDelimiter { no_delimiter } -// smonth returns month name. +// smonth returns month name abbreviation. pub fn (t Time) smonth() string { if t.month <= 0 || t.month > 12 { return '---' @@ -224,10 +226,10 @@ 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. +// weekday_str returns the current day as a string abbreviation. pub fn (t Time) weekday_str() string { i := t.day_of_week() - 1 - return time.days_string[i * 3..(i + 1) * 3] + return time.long_days[i][0..3] } // weekday_str returns the current day as a string.