2023-03-28 23:55:57 +03:00
|
|
|
// Copyright (c) 2019-2023 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
|
|
|
|
|
2023-08-05 23:41:23 +03:00
|
|
|
// unix returns a time struct from an Unix timestamp (number of seconds since 1970-01-01)
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-05 23:41:23 +03:00
|
|
|
// unix2 returns a Time struct, given an Unix timestamp in seconds, and a microsecond value
|
|
|
|
[deprecated: 'use unix_microsecond(unix_ts, us) instead']
|
|
|
|
[deprecated_after: '2023-09-05']
|
2021-07-06 18:51:47 +03:00
|
|
|
pub fn unix2(abs i64, microsecond int) Time {
|
2023-08-05 23:41:23 +03:00
|
|
|
return unix_nanosecond(abs, microsecond * 1000)
|
|
|
|
}
|
|
|
|
|
|
|
|
// unix_microsecond returns a Time struct, given an Unix timestamp in seconds, and a microsecond value
|
|
|
|
pub fn unix_microsecond(abs i64, microsecond int) Time {
|
|
|
|
return unix_nanosecond(abs, microsecond * 1000)
|
|
|
|
}
|
|
|
|
|
|
|
|
// unix_nanosecond returns a Time struct, given an Unix timestamp in seconds, and a nanosecond value
|
|
|
|
pub fn unix_nanosecond(abs i64, nanosecond 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
|
2023-08-05 23:41:23 +03:00
|
|
|
nanosecond: nanosecond
|
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_
|
2022-05-15 10:55:24 +03:00
|
|
|
|
|
|
|
// source: http://howardhinnant.github.io/date_algorithms.html#civil_from_days
|
|
|
|
|
|
|
|
// shift from 1970-01-01 to 0000-03-01
|
|
|
|
day_offset += 719468 // int(days_per_400_years * 1970 / 400 - (28+31))
|
|
|
|
|
|
|
|
mut era := 0
|
|
|
|
if day_offset >= 0 {
|
|
|
|
era = int(day_offset / days_per_400_years)
|
2020-12-06 17:19:39 +03:00
|
|
|
} else {
|
2022-05-15 10:55:24 +03:00
|
|
|
era = int((day_offset - days_per_400_years - 1) / days_per_400_years)
|
2019-12-31 19:11:47 +03:00
|
|
|
}
|
2022-05-15 10:55:24 +03:00
|
|
|
// doe(day of era) [0, 146096]
|
|
|
|
doe := day_offset - era * days_per_400_years
|
|
|
|
// yoe(year of era) [0, 399]
|
|
|
|
yoe := (doe - doe / (days_per_4_years - 1) + doe / days_per_100_years - doe / (days_per_400_years - 1)) / days_in_year
|
|
|
|
// year number
|
|
|
|
mut y := int(yoe + era * 400)
|
|
|
|
// doy (day of year), with year beginning Mar 1 [0, 365]
|
|
|
|
doy := doe - (days_in_year * yoe + yoe / 4 - yoe / 100)
|
|
|
|
|
|
|
|
mp := (5 * doy + 2) / 153
|
|
|
|
d := int(doy - (153 * mp + 2) / 5 + 1)
|
|
|
|
mut m := int(mp)
|
|
|
|
if mp < 10 {
|
|
|
|
m += 3
|
2020-12-06 17:19:39 +03:00
|
|
|
} else {
|
2022-05-15 10:55:24 +03:00
|
|
|
m -= 9
|
2019-12-31 19:11:47 +03:00
|
|
|
}
|
2022-05-15 10:55:24 +03:00
|
|
|
if m <= 2 {
|
|
|
|
y += 1
|
2019-12-31 19:11:47 +03:00
|
|
|
}
|
2022-05-15 10:55:24 +03:00
|
|
|
return y, m, d
|
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
|
|
|
}
|