v / vlib / time / time_test.v
532 lines · 470 sloc · 13.66 KB · 07c796b670d9e498ccb25605af189617f61ec295
Raw
1import time
2import math
3import os
4
5const local_time_to_test = time.new(
6 year: 1980
7 month: 7
8 day: 11
9 hour: 21
10 minute: 23
11 second: 42
12 nanosecond: 123456789
13 is_local: true
14)
15
16const utc_time_to_test = time.new(
17 year: 1980
18 month: 7
19 day: 11
20 hour: 21
21 minute: 23
22 second: 42
23 nanosecond: 123456789
24 is_local: false
25)
26
27fn assert_new_panics(expr string, expected string) {
28 source_path := os.join_path(os.temp_dir(), 'time_new_invalid_prog.v')
29 source := 'import time
30
31fn main() {
32 println(${expr})
33}
34'
35 os.write_file(source_path, source) or { panic(err) }
36 defer {
37 os.rm(source_path) or {}
38 }
39 res := os.execute('${os.quoted_path(@VEXE)} run ${os.quoted_path(source_path)}')
40 assert res.exit_code != 0, 'expected `${expr}` to fail'
41 assert res.output.contains(expected), 'expected `${expected}` in `${res.output}`'
42}
43
44fn test_is_leap_year() {
45 // 1996 % 4 = 0 and 1996 % 100 > 0
46 assert time.is_leap_year(1996) == true
47 // 2000 % 4 = 0 and 2000 % 400 = 0
48 assert time.is_leap_year(2000) == true
49 // 1996 % 4 > 0
50 assert time.is_leap_year(1997) == false
51 // 2000 % 4 = 0 and 2000 % 100 = 0
52 assert time.is_leap_year(2100) == false
53}
54
55fn check_days_in_month(month int, year int, expected int) bool {
56 res := time.days_in_month(month, year) or { return false }
57 return res == expected
58}
59
60fn test_days_in_month() {
61 days_in_month := [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
62 for i, days in days_in_month {
63 month := i + 1
64 assert check_days_in_month(month, 2001, days)
65 }
66}
67
68fn test_new_defaults_missing_month_and_day() {
69 t := time.new(year: 2024)
70 assert t.year == 2024
71 assert t.month == 1
72 assert t.day == 1
73 assert t.hour == 0
74 assert t.minute == 0
75 assert t.second == 0
76 assert t.nanosecond == 0
77 assert t.str() == '2024-01-01 00:00:00'
78}
79
80fn test_new_rejects_invalid_values() {
81 assert_new_panics('time.new(year: 10000)', 'invalid time: year must be between -9999 and 9999')
82 assert_new_panics('time.new(year: 2024, month: 13)',
83 'invalid time: month must be between 1 and 12')
84 assert_new_panics('time.new(year: 2024, month: 2, day: 30)',
85 'invalid time: day must be between 1 and 29 for year 2024, month 2')
86 assert_new_panics('time.new(year: 2024, hour: 24)',
87 'invalid time: hour must be between 0 and 23')
88}
89
90fn test_unix() {
91 t := time.unix(1564366499)
92 assert t.year == 2019
93 assert t.month == 7
94 assert t.day == 29
95 assert t.hour == 2
96 assert t.minute == 14
97 assert t.second == 59
98 t2 := time.unix(1078058096)
99 assert t2.year == 2004
100 assert t2.month == 2
101 assert t2.day == 29
102 assert t2.hour == 12
103 assert t2.minute == 34
104 assert t2.second == 56
105 t3 := time.unix(1070236799)
106 assert t3.year == 2003
107 assert t3.month == 11
108 assert t3.day == 30
109 assert t3.hour == 23
110 assert t3.minute == 59
111 assert t3.second == 59
112 t4 := time.unix(1577783439)
113 assert t4.year == 2019
114 assert t4.month == 12
115 assert t4.day == 31
116 assert t4.hour == 9
117 assert t4.minute == 10
118 assert t4.second == 39
119 t5 := time.unix(-1824922433)
120 assert t5.year == 1912
121 assert t5.month == 3
122 assert t5.day == 4
123 assert t5.hour == 5
124 assert t5.minute == 6
125 assert t5.second == 7
126 t6 := time.unix(1577858969)
127 assert t6.year == 2020
128 assert t6.month == 1
129 assert t6.day == 1
130 assert t6.hour == 6
131 assert t6.minute == 9
132 assert t6.second == 29
133 assert utc_time_to_test.unix() == 332198622
134}
135
136fn test_format_rfc3339() {
137 // assert '1980-07-11T19:23:42.123Z'
138 utc_res := utc_time_to_test.format_rfc3339()
139 assert utc_res.ends_with('23:42.123Z')
140 assert utc_res.starts_with('1980-07-1')
141 assert utc_res.contains('T')
142}
143
144fn test_format_rfc3339_micro() {
145 utc_res := utc_time_to_test.format_rfc3339_micro()
146 assert utc_res.ends_with('23:42.123456Z')
147 assert utc_res.starts_with('1980-07-1')
148 assert utc_res.contains('T')
149}
150
151fn test_format_rfc3339_nano() {
152 utc_res := utc_time_to_test.format_rfc3339_nano()
153 assert utc_res.ends_with('23:42.123456789Z')
154 assert utc_res.starts_with('1980-07-1')
155 assert utc_res.contains('T')
156}
157
158fn test_format_ss() {
159 assert '11.07.1980 21:23:42' == local_time_to_test.get_fmt_str(.dot, .hhmmss24, .ddmmyyyy)
160
161 assert '11.07.1980 21:23:42' == utc_time_to_test.get_fmt_str(.dot, .hhmmss24, .ddmmyyyy)
162}
163
164fn test_format_ss_milli() {
165 assert '11.07.1980 21:23:42.123' == local_time_to_test.get_fmt_str(.dot, .hhmmss24_milli,
166 .ddmmyyyy)
167 assert '1980-07-11 21:23:42.123' == local_time_to_test.format_ss_milli()
168
169 assert '11.07.1980 21:23:42.123' == utc_time_to_test.get_fmt_str(.dot, .hhmmss24_milli,
170 .ddmmyyyy)
171 assert '1980-07-11 21:23:42.123' == utc_time_to_test.format_ss_milli()
172}
173
174fn test_format_ss_micro() {
175 assert '11.07.1980 21:23:42.123456' == local_time_to_test.get_fmt_str(.dot, .hhmmss24_micro,
176 .ddmmyyyy)
177 assert '1980-07-11 21:23:42.123456' == local_time_to_test.format_ss_micro()
178
179 assert '11.07.1980 21:23:42.123456' == utc_time_to_test.get_fmt_str(.dot, .hhmmss24_micro,
180 .ddmmyyyy)
181 assert '1980-07-11 21:23:42.123456' == utc_time_to_test.format_ss_micro()
182}
183
184fn test_format_ss_nano() {
185 assert '11.07.1980 21:23:42.123456789' == local_time_to_test.get_fmt_str(.dot, .hhmmss24_nano,
186 .ddmmyyyy)
187 assert '1980-07-11 21:23:42.123456789' == local_time_to_test.format_ss_nano()
188
189 assert '11.07.1980 21:23:42.123456789' == utc_time_to_test.get_fmt_str(.dot, .hhmmss24_nano,
190 .ddmmyyyy)
191 assert '1980-07-11 21:23:42.123456789' == utc_time_to_test.format_ss_nano()
192}
193
194fn test_smonth() {
195 month_names := ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov',
196 'Dec']
197 for i, name in month_names {
198 month_num := i + 1
199 t := time.Time{
200 year: 1980
201 month: month_num
202 day: 1
203 hour: 0
204 minute: 0
205 second: 0
206 }
207 assert t.smonth() == name
208 }
209}
210
211fn test_day_of_week() {
212 for i in 0 .. 7 {
213 day_of_week := i + 1
214 // 2 Dec 2019 is Monday
215 t := time.Time{
216 year: 2019
217 month: 12
218 day: 2 + i
219 hour: 0
220 minute: 0
221 second: 0
222 }
223 assert day_of_week == t.day_of_week()
224 }
225}
226
227fn test_week_of_year() {
228 // As windows use msvcrt.dll, which `strftime` does not support %V, so skip test
229 // TODO: newer version windows use ucrtbase.dll, which support %V
230 $if !windows {
231 for year in 2000 .. 2100 {
232 mut t := time.new(time.Time{
233 year: year
234 month: 12
235 day: 20
236 })
237
238 // check from year.12.20 to next_year.1.8
239 for _ in 0 .. 20 {
240 assert t.strftime('%V') == '${t.week_of_year():02}', '${t}'
241 t = t.add_days(1)
242 }
243 }
244 }
245
246 t1 := time.Time{
247 year: 2025
248 month: 3
249 day: 3
250 }
251 assert t1.week_of_year() == 10
252 assert t1.add_days(1).week_of_year() == 10
253}
254
255fn test_year_day() {
256 // testing if December 31st in a leap year is numbered as 366
257 assert time.parse('2024-12-31 20:00:00')!.year_day() == 366
258
259 // testing December 31st's number in a non leap year
260 assert time.parse('2025-12-31 20:00:00')!.year_day() == 365
261
262 assert time.parse('2024-02-28 20:00:00')!.year_day() == 59
263 assert time.parse('2024-02-29 20:00:00')!.year_day() == 60
264 assert time.parse('2024-03-01 20:00:00')!.year_day() == 61
265 assert time.parse('2024-03-02 20:00:00')!.year_day() == 62
266
267 assert time.parse('2025-02-28 20:00:00')!.year_day() == 59
268 assert time.parse('2025-03-01 20:00:00')!.year_day() == 60
269
270 assert time.parse('2024-01-01 20:00:00')!.year_day() == 1
271 assert time.parse('2025-01-01 20:00:00')!.year_day() == 1
272}
273
274fn test_weekday_str() {
275 day_names := ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
276 for i, name in day_names {
277 // 2 Dec 2019 is Monday
278 t := time.Time{
279 year: 2019
280 month: 12
281 day: 2 + i
282 hour: 0
283 minute: 0
284 second: 0
285 }
286 assert t.weekday_str() == name
287 }
288}
289
290fn test_add() {
291 d_seconds := 3
292 d_nanoseconds := 13
293 duration := time.Duration(i64(d_seconds) * time.second + d_nanoseconds * time.nanosecond)
294 // dump(duration.debug())
295 t1 := local_time_to_test
296 // dump(t1.debug())
297 t2 := local_time_to_test.add(duration)
298 // dump(t2.debug())
299 assert t2.second == t1.second + d_seconds
300 assert t2.nanosecond == t1.nanosecond + d_nanoseconds
301 assert t2.unix() == t1.unix() + d_seconds
302 assert t2.is_local == t1.is_local
303
304 t3 := local_time_to_test.add(-duration)
305 // dump(t3.debug())
306 assert t3.second == t1.second - d_seconds
307 assert t3.nanosecond == t1.nanosecond - d_nanoseconds
308 assert t3.unix() == t1.unix() - d_seconds
309 assert t3.is_local == t1.is_local
310
311 t4 := local_time_to_test.as_local()
312 // dump(t4.debug())
313 t5 := t4.add(duration)
314 // dump(t5.debug())
315 assert t5.is_local == t4.is_local
316
317 t := time.Time{
318 year: 2024
319 month: 4
320 day: 3
321 }
322 t_5am := t.add(time.hour * 5)
323 assert t_5am.hour == 5
324 next_day := t_5am.add_days(1)
325 assert next_day.day == 4 && next_day.day == t_5am.day + 1
326 assert next_day.year == t_5am.year && next_day.month == t.month
327 assert next_day.month == t_5am.month && next_day.month == t.month
328 assert next_day.hour == t_5am.hour && next_day.month == t.month
329}
330
331fn test_add_days() {
332 num_of_days := 3
333 t := local_time_to_test.add_days(num_of_days)
334 assert t.day == local_time_to_test.day + num_of_days
335 assert t.unix() == local_time_to_test.unix() + 86400 * num_of_days
336}
337
338fn test_str() {
339 assert '1980-07-11 21:23:42' == local_time_to_test.str()
340
341 assert '1980-07-11 21:23:42' == utc_time_to_test.str()
342}
343
344// not optimal test but will find obvious bugs
345fn test_now() {
346 now := time.now()
347 // The year the test was built
348 assert now.year >= 2020
349 assert now.month > 0
350 assert now.month <= 12
351 assert now.minute >= 0
352 assert now.minute < 60
353 assert now.second >= 0
354 assert now.second <= 60 // <= 60 cause of leap seconds
355 assert now.nanosecond >= 0
356 assert now.nanosecond < time.second
357}
358
359fn test_utc() {
360 now := time.utc()
361 // The year the test was built
362 // dump(now.debug())
363 assert now.year >= 2020
364 assert now.month > 0
365 assert now.month <= 12
366 assert now.minute >= 0
367 assert now.minute < 60
368 assert now.second >= 0
369 assert now.second <= 60 // <= 60 cause of leap seconds
370 assert now.nanosecond >= 0
371 assert now.nanosecond < time.second
372}
373
374fn test_unix_time() {
375 t1 := time.utc()
376 time.sleep(50 * time.millisecond)
377 t2 := time.utc()
378 eprintln(' t1: ${t1}')
379 eprintln(' t2: ${t2}')
380 ut1 := t1.unix()
381 ut2 := t2.unix()
382 eprintln(' ut1: ${ut1}')
383 eprintln(' ut2: ${ut2}')
384 assert ut2 - ut1 < 2
385
386 utm1 := t1.unix_milli()
387 utm2 := t2.unix_milli()
388 eprintln('utm1: ${utm1}')
389 eprintln('utm2: ${utm2}')
390 assert (utm1 - ut1 * 1000) < 1000
391 assert (utm2 - ut2 * 1000) < 1000
392
393 assert utm2 - utm1 > 2
394 assert utm2 - utm1 < 999
395}
396
397fn test_offset() {
398 u := time.utc()
399 n := time.now()
400
401 mut diff_seconds := 0
402 if u.day != n.day {
403 if u.day > n.day {
404 diff_seconds = int(math.abs(((u.hour * 60 + u.minute) - (n.hour * 60 + n.minute)) * 60)) - 86400
405 } else {
406 diff_seconds = 86400 - int(math.abs(((u.hour * 60 + u.minute) - (n.hour * 60 + n.minute)) * 60))
407 }
408 if math.abs(u.day - n.day) > 1 { // different month
409 diff_seconds = diff_seconds * -1
410 }
411 } else { // same day
412 diff_seconds = ((n.hour * 60 + n.minute) - (u.hour * 60 + u.minute)) * 60
413 }
414
415 assert diff_seconds == time.offset()
416}
417
418fn test_since() {
419 t1 := time.now()
420 time.sleep(20 * time.millisecond)
421 d1 := time.since(t1)
422 assert d1 >= 20_000_000
423 time.sleep(20 * time.millisecond)
424 d2 := time.since(t1)
425 assert d2 >= 40_000_000
426}
427
428// issue relate https://github.com/vlang/v/issues/13828
429// problem: the local method add 2h on the time in a Linux machine
430// the other machine are not tested in a local env
431fn test_recursive_local_call() {
432 now_tm := time.now()
433 assert now_tm.str() == now_tm.local().str()
434 assert now_tm.local().str() == now_tm.local().local().str()
435}
436
437fn test_strftime() {
438 assert '1980 July 11' == local_time_to_test.strftime('%Y %B %d')
439
440 assert '1980 July 11' == utc_time_to_test.strftime('%Y %B %d')
441}
442
443fn test_add_seconds_to_time() {
444 now_tm := time.now()
445 future_tm := now_tm.add_seconds(60)
446 assert now_tm.unix() < future_tm.unix()
447}
448
449fn test_plus_equals_duration() {
450 mut d := time.second
451 d += time.second
452 assert d == 2 * time.second
453}
454
455fn test_parse_three_letters_month() {
456 tm := time.now()
457 format := 'MMM DD HH:mm:ss YYYY'
458 tm_s := tm.custom_format(format)
459 tm_tm := time.parse_format(tm_s, format)!
460 assert tm_tm.month == tm.month
461}
462
463fn test_parse_ordinal_weekday_d() {
464 format := 'd MMM DD HH:mm:ss YYYY'
465 dt := '0 Jan 01 00:00:00 1970'
466 tm := time.parse_format(dt, format)!
467 tm_s := tm.custom_format(format)
468 assert tm_s == '4 Jan 01 00:00:00 1970'
469}
470
471fn test_parse_ordinal_weekday_c() {
472 format := 'c MMM DD HH:mm:ss YYYY'
473 dt := '7 Jan 01 00:00:00 1970'
474 tm := time.parse_format(dt, format)!
475 tm_s := tm.custom_format(format)
476 assert tm_s == '4 Jan 01 00:00:00 1970'
477}
478
479fn test_parse_two_letters_weekday() {
480 format := 'dd MMM DD HH:mm:ss YYYY'
481 dt := 'Su Jan 01 00:00:00 1970'
482 tm := time.parse_format(dt, format)!
483 tm_s := tm.custom_format(format)
484 assert tm_s == 'Th Jan 01 00:00:00 1970'
485}
486
487fn test_parse_three_letters_weekday() {
488 format := 'ddd MMM DD HH:mm:ss YYYY'
489 dt := 'Sun Jan 01 00:00:00 1970'
490 tm := time.parse_format(dt, format)!
491 tm_s := tm.custom_format(format)
492 assert tm_s == 'Thu Jan 01 00:00:00 1970'
493}
494
495fn test_parse_weekday() {
496 format := 'dddd MMM DD HH:mm:ss YYYY'
497 dt := 'Sunday Jan 01 00:00:00 1970'
498 tm := time.parse_format(dt, format)!
499 tm_s := tm.custom_format(format)
500 assert tm_s == 'Thursday Jan 01 00:00:00 1970'
501}
502
503fn test_empty_time() {
504 t := time.Time{}
505 assert t.unix() == -62167132800
506 assert t.format_rfc3339() == '0000-01-01T00:00:00.000Z'
507 assert t == time.parse_rfc3339(t.format_rfc3339())!
508 assert t.custom_format('MMMM YYYY') == 'January 0'
509}
510
511fn test_pre_epoch_unix_calculation() {
512 assert time.new(time.Time{}).unix() == -62167132800
513 assert time.new(
514 year: 1
515 month: 1
516 day: 1
517 ).unix() == -62135596800
518 assert time.parse_rfc3339('0001-01-01T00:00:00Z')!.unix() == -62135596800
519 t := time.Time{}
520 assert t.is_zero()
521 // assert t.unix() == -62169984000
522 assert t.custom_format('MMMM YYYY') == 'January 0'
523}
524
525fn test_is_zero() {
526 assert time.Time{}.is_zero()
527 assert !time.unix(0).is_zero()
528 assert !time.new(year: 2024).is_zero()
529 assert !time.Time{
530 is_local: true
531 }.is_zero()
532}
533