2022-01-04 12:21:08 +03:00
|
|
|
// Copyright (c) 2019-2022 Alexander Medvednikov. All rights reserved.
|
2019-12-31 19:11:47 +03:00
|
|
|
// Use of this source code is governed by an MIT license
|
|
|
|
// that can be found in the LICENSE file.
|
|
|
|
module time
|
|
|
|
|
2020-02-06 16:19:44 +03:00
|
|
|
// unix returns a time struct from Unix time.
|
2021-08-16 06:28:54 +03:00
|
|
|
pub fn unix(abs i64) Time {
|
2019-12-31 19:11:47 +03:00
|
|
|
// 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
|
2020-01-23 23:09:47 +03:00
|
|
|
day_offset--
|
2019-12-31 19:11:47 +03:00
|
|
|
}
|
2020-12-06 17:19:39 +03:00
|
|
|
year, month, day := calculate_date_from_offset(day_offset)
|
|
|
|
hr, min, sec := calculate_time_from_offset(abs % seconds_per_day)
|
2019-12-31 19:11:47 +03:00
|
|
|
return Time{
|
|
|
|
year: year
|
|
|
|
month: month
|
|
|
|
day: day
|
|
|
|
hour: hr
|
|
|
|
minute: min
|
|
|
|
second: sec
|
2021-08-04 13:12:02 +03:00
|
|
|
unix: abs
|
2019-12-31 19:11:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-07 16:19:09 +03:00
|
|
|
// unix2 returns a time struct from Unix time and microsecond value
|
2021-07-06 18:51:47 +03:00
|
|
|
pub fn unix2(abs i64, microsecond int) Time {
|
2020-06-07 16:19:09 +03:00
|
|
|
// 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--
|
|
|
|
}
|
2020-12-06 17:19:39 +03:00
|
|
|
year, month, day := calculate_date_from_offset(day_offset)
|
|
|
|
hr, min, sec := calculate_time_from_offset(abs % seconds_per_day)
|
2020-06-07 16:19:09 +03:00
|
|
|
return Time{
|
|
|
|
year: year
|
|
|
|
month: month
|
|
|
|
day: day
|
|
|
|
hour: hr
|
|
|
|
minute: min
|
|
|
|
second: sec
|
|
|
|
microsecond: microsecond
|
2021-08-04 13:12:02 +03:00
|
|
|
unix: abs
|
2020-06-07 16:19:09 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-06 18:51:47 +03:00
|
|
|
fn calculate_date_from_offset(day_offset_ i64) (int, int, int) {
|
2019-12-31 19:11:47 +03:00
|
|
|
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
|
2020-01-23 23:09:47 +03:00
|
|
|
day_offset -= 31 * 365 + 8
|
2019-12-31 19:11:47 +03:00
|
|
|
// Account for 400 year cycle
|
2021-07-06 18:51:47 +03:00
|
|
|
year += int(day_offset / days_per_400_years) * 400
|
2019-12-31 19:11:47 +03:00
|
|
|
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
|
2020-12-06 17:19:39 +03:00
|
|
|
} else {
|
2021-07-06 18:51:47 +03:00
|
|
|
year += int(day_offset / days_per_100_years) * 100
|
2019-12-31 19:11:47 +03:00
|
|
|
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
|
2020-12-06 17:19:39 +03:00
|
|
|
} else {
|
2021-07-06 18:51:47 +03:00
|
|
|
year += int(day_offset / days_per_4_years) * 4
|
2019-12-31 19:11:47 +03:00
|
|
|
day_offset %= days_per_4_years
|
|
|
|
}
|
|
|
|
// Account for every year
|
|
|
|
if day_offset == 365 * 4 {
|
|
|
|
year += 3
|
|
|
|
day_offset -= 365 * 3
|
2020-12-06 17:19:39 +03:00
|
|
|
} else {
|
2021-07-06 18:51:47 +03:00
|
|
|
year += int(day_offset / 365)
|
2019-12-31 19:11:47 +03:00
|
|
|
day_offset %= 365
|
|
|
|
}
|
|
|
|
if day_offset < 0 {
|
2020-01-23 23:09:47 +03:00
|
|
|
year--
|
2019-12-31 19:11:47 +03:00
|
|
|
if is_leap_year(year) {
|
|
|
|
day_offset += 366
|
2020-12-06 17:19:39 +03:00
|
|
|
} else {
|
2019-12-31 19:11:47 +03:00
|
|
|
day_offset += 365
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if is_leap_year(year) {
|
|
|
|
if day_offset > 31 + 29 - 1 {
|
|
|
|
// After leap day; pretend it wasn't there.
|
|
|
|
day_offset--
|
2020-12-06 17:19:39 +03:00
|
|
|
} else if day_offset == 31 + 29 - 1 {
|
2019-12-31 19:11:47 +03:00
|
|
|
// Leap day.
|
2020-12-06 17:19:39 +03:00
|
|
|
return year, 2, 29
|
2019-12-31 19:11:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
mut estimated_month := day_offset / 31
|
2020-01-23 23:09:47 +03:00
|
|
|
for day_offset >= days_before[estimated_month + 1] {
|
2019-12-31 19:11:47 +03:00
|
|
|
estimated_month++
|
|
|
|
}
|
2020-01-14 20:12:28 +03:00
|
|
|
for day_offset < days_before[estimated_month] {
|
2020-01-01 09:27:48 +03:00
|
|
|
if estimated_month == 0 {
|
|
|
|
break
|
|
|
|
}
|
2019-12-31 19:11:47 +03:00
|
|
|
estimated_month--
|
|
|
|
}
|
|
|
|
day_offset -= days_before[estimated_month]
|
2021-07-06 18:51:47 +03:00
|
|
|
return year, int(estimated_month + 1), int(day_offset + 1)
|
2019-12-31 19:11:47 +03:00
|
|
|
}
|
|
|
|
|
2021-07-06 18:51:47 +03:00
|
|
|
fn calculate_time_from_offset(second_offset_ i64) (int, int, int) {
|
2019-12-31 19:11:47 +03:00
|
|
|
mut second_offset := second_offset_
|
|
|
|
if second_offset < 0 {
|
|
|
|
second_offset += seconds_per_day
|
|
|
|
}
|
2021-01-10 23:41:29 +03:00
|
|
|
hour_ := second_offset / seconds_per_hour
|
2019-12-31 19:11:47 +03:00
|
|
|
second_offset %= seconds_per_hour
|
|
|
|
min := second_offset / seconds_per_minute
|
|
|
|
second_offset %= seconds_per_minute
|
2021-07-06 18:51:47 +03:00
|
|
|
return int(hour_), int(min), int(second_offset)
|
2019-12-31 19:11:47 +03:00
|
|
|
}
|