time: rewrite unix() function

pull/3285/head
lutherwenxu 2020-01-01 00:11:47 +08:00 committed by Alexander Medvednikov
parent 67912c692b
commit 286a0a1371
8 changed files with 186 additions and 109 deletions

View File

@ -2,7 +2,7 @@ import rand
import time import time
fn main() { fn main() {
rand.seed(time.now().uni) rand.seed(time.now().unix)
for _ in 0..10 { for _ in 0..10 {
println('${rand.next(255)}.${rand.next(255)}.${rand.next(255)}.${rand.next(255)}') println('${rand.next(255)}.${rand.next(255)}.${rand.next(255)}.${rand.next(255)}')

View File

@ -173,7 +173,7 @@ fn main() {
fn (g mut Game) init_game() { fn (g mut Game) init_game() {
g.parse_tetros() g.parse_tetros()
rand.seed(time.now().uni) rand.seed(time.now().unix)
g.generate_tetro() g.generate_tetro()
g.field = [] // TODO: g.field = [][]int g.field = [] // TODO: g.field = [][]int
// Generate the field, fill it with 0's, add -1's on each edge // Generate the field, fill it with 0's, add -1's on each edge

View File

@ -89,7 +89,7 @@ fn get_bet(money int) int {
fn run_wheel(bet_nbr int, _bet int) int { fn run_wheel(bet_nbr int, _bet int) int {
mut bet := _bet mut bet := _bet
rand.seed(time.now().uni) rand.seed(time.now().unix)
winning_nbr := rand.next(50) winning_nbr := rand.next(50)
print('Roulette Wheel spinning... and stops on the number $winning_nbr which is a ') print('Roulette Wheel spinning... and stops on the number $winning_nbr which is a ')
if winning_nbr % 2 == 1 { if winning_nbr % 2 == 1 {

View File

@ -19,7 +19,7 @@ fn test_bf_set_clear_toggle_get() {
} }
fn test_bf_and_not_or_xor() { fn test_bf_and_not_or_xor() {
rand.seed(time.now().uni) rand.seed(time.now().unix)
len := 80 len := 80
mut input1 := bitfield.new(len) mut input1 := bitfield.new(len)
mut input2 := bitfield.new(len) mut input2 := bitfield.new(len)
@ -46,7 +46,7 @@ fn test_bf_and_not_or_xor() {
} }
fn test_clone_cmp() { fn test_clone_cmp() {
rand.seed(time.now().uni) rand.seed(time.now().unix)
len := 80 len := 80
mut input := bitfield.new(len) mut input := bitfield.new(len)
for i := 0; i < len; i++ { for i := 0; i < len; i++ {
@ -60,7 +60,7 @@ fn test_clone_cmp() {
} }
fn test_slice_join() { fn test_slice_join() {
rand.seed(time.now().uni) rand.seed(time.now().unix)
len := 80 len := 80
mut input := bitfield.new(len) mut input := bitfield.new(len)
for i := 0; i < len; i++ { for i := 0; i < len; i++ {
@ -83,7 +83,7 @@ fn test_slice_join() {
} }
fn test_popcount() { fn test_popcount() {
rand.seed(time.now().uni) rand.seed(time.now().unix)
len := 80 len := 80
mut count0 := 0 mut count0 := 0
mut input := bitfield.new(len) mut input := bitfield.new(len)
@ -98,7 +98,7 @@ fn test_popcount() {
} }
fn test_hamming() { fn test_hamming() {
rand.seed(time.now().uni) rand.seed(time.now().unix)
len := 80 len := 80
mut count := 0 mut count := 0
mut input1 := bitfield.new(len) mut input1 := bitfield.new(len)
@ -138,7 +138,7 @@ fn test_bf_from_bytes() {
} }
fn test_bf_from_string() { fn test_bf_from_string() {
rand.seed(time.now().uni) rand.seed(time.now().unix)
len := 80 len := 80
mut input := '' mut input := ''
for i := 0; i < len; i++ { for i := 0; i < len; i++ {
@ -160,7 +160,7 @@ fn test_bf_from_string() {
} }
fn test_bf_bf2str() { fn test_bf_bf2str() {
rand.seed(time.now().uni) rand.seed(time.now().unix)
len := 80 len := 80
mut input := bitfield.new(len) mut input := bitfield.new(len)
for i := 0; i < len; i++ { for i := 0; i < len; i++ {
@ -188,7 +188,7 @@ fn test_bf_bf2str() {
} }
fn test_bf_setall() { fn test_bf_setall() {
rand.seed(time.now().uni) rand.seed(time.now().unix)
len := 80 len := 80
mut input := bitfield.new(len) mut input := bitfield.new(len)
input.setall() input.setall()
@ -202,7 +202,7 @@ fn test_bf_setall() {
} }
fn test_bf_clearall() { fn test_bf_clearall() {
rand.seed(time.now().uni) rand.seed(time.now().unix)
len := 80 len := 80
mut input := bitfield.new(len) mut input := bitfield.new(len)
for i := 0; i < len; i++ { for i := 0; i < len; i++ {
@ -221,7 +221,7 @@ fn test_bf_clearall() {
} }
fn test_bf_reverse() { fn test_bf_reverse() {
rand.seed(time.now().uni) rand.seed(time.now().unix)
len := 80 len := 80
mut input := bitfield.new(len) mut input := bitfield.new(len)
for i := 0; i < len; i++ { for i := 0; i < len; i++ {
@ -241,7 +241,7 @@ fn test_bf_reverse() {
} }
fn test_bf_resize() { fn test_bf_resize() {
rand.seed(time.now().uni) rand.seed(time.now().unix)
len := 80 len := 80
mut input := bitfield.new(rand.next(len) + 1) mut input := bitfield.new(rand.next(len) + 1)
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
@ -259,7 +259,7 @@ fn test_bf_pos() {
* all haystacks here contain exactly one instanse of needle, * all haystacks here contain exactly one instanse of needle,
* so search should return non-negative-values * so search should return non-negative-values
**/ **/
rand.seed(time.now().uni) rand.seed(time.now().unix)
len := 80 len := 80
mut result := 1 mut result := 1
for i := 1; i < len; i++ { // needle size for i := 1; i < len; i++ { // needle size

View File

@ -292,7 +292,7 @@ fn main() {
game.sdl.jids[1] = -1 game.sdl.jids[1] = -1
game.sdl.set_sdl_context(WinWidth, WinHeight, Title) game.sdl.set_sdl_context(WinWidth, WinHeight, Title)
game.font = C.TTF_OpenFont(FontName.str, TextSize) game.font = C.TTF_OpenFont(FontName.str, TextSize)
seed := time.now().uni seed := time.now().unix
mut game2 := &Game{ font: 0 } mut game2 := &Game{ font: 0 }
game2.sdl = game.sdl game2.sdl = game.sdl
game2.font = game.font game2.font = game.font

View File

@ -32,7 +32,7 @@ pub:
hour int hour int
minute int minute int
second int second int
uni int // TODO it's safe to use "unix" now unix int
} }
pub enum FormatTime { pub enum FormatTime {
@ -92,92 +92,11 @@ pub fn now() Time {
} }
pub fn random() Time { pub fn random() Time {
now_unix := now().uni now_unix := now().unix
rand_unix := rand.next(now_unix) rand_unix := rand.next(now_unix)
return time.unix(rand_unix) return time.unix(rand_unix)
} }
// Based on Go's time package.
// Copyright 2009 The Go Authors.
pub fn unix(abs int) Time {
// Split into time and day.
mut d := abs / seconds_per_day
// Account for 400 year cycles.
mut n := d / days_per_400_years
mut y := 400 * n
d -= days_per_400_years * n
// Cut off 100-year cycles.
// The last cycle has one extra leap year, so on the last day
// of that year, day / days_per_100_years will be 4 instead of 3.
// Cut it back down to 3 by subtracting n>>2.
n = d / days_per_100_years
n -= n>>2
y += 100 * n
d -= days_per_100_years * n
// Cut off 4-year cycles.
// The last cycle has a missing leap year, which does not
// affect the computation.
n = d / days_per_4_years
y += 4 * n
d -= days_per_4_years * n
// Cut off years within a 4-year cycle.
// The last year is a leap year, so on the last day of that year,
// day / 365 will be 4 instead of 3. Cut it back down to 3
// by subtracting n>>2.
n = d / 365
n -= n>>2
y += n
d -= 365 * n
yday := d
mut day := yday
year := abs / int(3.154e+7) + 1970 // int(i64(y) + absolute_zero_year)
hour := (abs % seconds_per_day) / seconds_per_hour
minute := (abs % seconds_per_hour) / seconds_per_minute
second := (abs % seconds_per_minute)
if is_leap_year(year) {
// Leap year
if day > 31 + 29 - 1 {
// After leap day; pretend it wasn't there.
day--
}
else if day == 31 + 29 - 1 {
// Leap day.
day = 29
return Time{
year: year
month: 2
day: day
hour: hour
minute: minute
second: second
}
}
}
// Estimate month on assumption that every month has 31 days.
// The estimate may be too low by at most one month, so adjust.
mut month := day / 31
mut begin := 0
end := (days_before[month + 1])
if day >= end {
month++
begin = end
}
else {
begin = (days_before[month])
}
month++ // because January is 1
day = day - begin + 1
return Time{
year: year
month: month
day: day
hour: hour
minute: minute
second: second
uni: abs
}
}
pub fn convert_ctime(t tm) Time { pub fn convert_ctime(t tm) Time {
return Time{ return Time{
year: t.tm_year + 1900 year: t.tm_year + 1900
@ -186,7 +105,7 @@ pub fn convert_ctime(t tm) Time {
hour: t.tm_hour hour: t.tm_hour
minute: t.tm_min minute: t.tm_min
second: t.tm_sec second: t.tm_sec
uni: C.mktime(&t) unix: C.mktime(&t)
} }
} }
@ -337,15 +256,28 @@ pub fn parse_iso(s string) Time {
} }
pub fn new_time(t Time) Time { pub fn new_time(t Time) Time {
return Time{
year: t.year,
month: t.month,
day: t.day,
hour: t.hour,
minute: t.minute,
second: t.second,
unix: t.calc_unix()
}
//TODO: Use the syntax below when it works with reserved keywords like `unix`
/*
return { return {
t | t |
uni:t.calc_unix() unix:t.calc_unix()
} }
*/
} }
pub fn (t &Time) calc_unix() int { pub fn (t &Time) calc_unix() int {
if t.uni != 0 { if t.unix != 0 {
return t.uni return t.unix
} }
tt := C.tm{ tt := C.tm{
tm_sec: t.second tm_sec: t.second
@ -360,11 +292,11 @@ pub fn (t &Time) calc_unix() int {
// TODO add(d time.Duration) // TODO add(d time.Duration)
pub fn (t Time) add_seconds(seconds int) Time { pub fn (t Time) add_seconds(seconds int) Time {
return unix(t.uni + seconds) return unix(t.unix + seconds)
} }
pub fn (t Time) add_days(days int) Time { pub fn (t Time) add_days(days int) Time {
return unix(t.uni + days * 3600 * 24) return unix(t.unix + days * 3600 * 24)
} }
// TODO use time.Duration instead of seconds // TODO use time.Duration instead of seconds
@ -374,7 +306,7 @@ fn since(t Time) int {
pub fn (t Time) relative() string { pub fn (t Time) relative() string {
now := time.now() now := time.now()
secs := now.uni - t.uni secs := now.unix - t.unix
if secs <= 30 { if secs <= 30 {
// right now or in the future // right now or in the future
// TODO handle time in the future // TODO handle time in the future

View File

@ -46,6 +46,38 @@ fn test_unix() {
assert t.hour == 2 assert t.hour == 2
assert t.minute == 14 assert t.minute == 14
assert t.second == 59 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
} }
fn test_format_ss() { fn test_format_ss() {
@ -63,7 +95,7 @@ fn test_smonth() {
t := time.Time { t := time.Time {
year: 1980, month: month_num, day: 1, year: 1980, month: month_num, day: 1,
hour: 0, minute: 0, second: 0, uni: 0 hour: 0, minute: 0, second: 0, unix: 0
} }
assert t.smonth() == name assert t.smonth() == name
@ -105,7 +137,7 @@ fn test_day_of_week() {
// 2 Dec 2019 is Monday // 2 Dec 2019 is Monday
t := time.Time { t := time.Time {
year: 2019, month: 12, day: 2 + i, year: 2019, month: 12, day: 2 + i,
hour: 0, minute: 0, second: 0, uni: 0 hour: 0, minute: 0, second: 0, unix: 0
} }
assert day_of_week == t.day_of_week() assert day_of_week == t.day_of_week()
@ -119,7 +151,7 @@ fn test_weekday_str() {
// 2 Dec 2019 is Monday // 2 Dec 2019 is Monday
t := time.Time { t := time.Time {
year: 2019, month: 12, day: 2 + i, year: 2019, month: 12, day: 2 + i,
hour: 0, minute: 0, second: 0, uni: 0 hour: 0, minute: 0, second: 0, unix: 0
} }
assert t.weekday_str() == name assert t.weekday_str() == name

View File

@ -0,0 +1,113 @@
// Copyright (c) 2019 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 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 -= 1
}
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: abs
}
}
[inline]
fn calculate_date_from_offset(day_offset_ int) (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 += (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 += (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 += (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 += (day_offset / 365)
day_offset %= 365
}
if day_offset < 0 {
year -= 1
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] {
estimated_month--
}
day_offset -= days_before[estimated_month]
return year, estimated_month+1, day_offset+1
}
[inline]
fn calculate_time_from_offset(second_offset_ int) (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 hour, min, second_offset
}