time: fix calculate_date_from_offset (#14399)
parent
b50f7fdc71
commit
c28051020a
|
@ -184,3 +184,17 @@ fn test_parse_rfc3339() {
|
||||||
assert expected == output
|
assert expected == output
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_ad_second_to_parse_result_in_2001() ? {
|
||||||
|
now_tm := time.parse('2001-01-01 04:00:00')?
|
||||||
|
future_tm := now_tm.add_seconds(60)
|
||||||
|
assert future_tm.str() == '2001-01-01 04:01:00'
|
||||||
|
assert now_tm.unix < future_tm.unix
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_ad_second_to_parse_result_pre_2001() ? {
|
||||||
|
now_tm := time.parse('2000-01-01 04:00:00')?
|
||||||
|
future_tm := now_tm.add_seconds(60)
|
||||||
|
assert future_tm.str() == '2000-01-01 04:01:00'
|
||||||
|
assert now_tm.unix < future_tm.unix
|
||||||
|
}
|
||||||
|
|
|
@ -16,9 +16,10 @@ pub const (
|
||||||
seconds_per_hour = 60 * seconds_per_minute
|
seconds_per_hour = 60 * seconds_per_minute
|
||||||
seconds_per_day = 24 * seconds_per_hour
|
seconds_per_day = 24 * seconds_per_hour
|
||||||
seconds_per_week = 7 * seconds_per_day
|
seconds_per_week = 7 * seconds_per_day
|
||||||
days_per_400_years = 365 * 400 + 97
|
days_per_400_years = days_in_year * 400 + 97
|
||||||
days_per_100_years = 365 * 100 + 24
|
days_per_100_years = days_in_year * 100 + 24
|
||||||
days_per_4_years = 365 * 4 + 1
|
days_per_4_years = days_in_year * 4 + 1
|
||||||
|
days_in_year = 365
|
||||||
days_before = [
|
days_before = [
|
||||||
0,
|
0,
|
||||||
31,
|
31,
|
||||||
|
@ -179,13 +180,13 @@ pub fn (t Time) relative() string {
|
||||||
}
|
}
|
||||||
return '$prefix$d days$suffix'
|
return '$prefix$d days$suffix'
|
||||||
}
|
}
|
||||||
if secs < time.seconds_per_hour * 24 * 365 {
|
if secs < time.seconds_per_hour * 24 * time.days_in_year {
|
||||||
if prefix == 'in ' {
|
if prefix == 'in ' {
|
||||||
return 'on $t.md()'
|
return 'on $t.md()'
|
||||||
}
|
}
|
||||||
return 'last $t.md()'
|
return 'last $t.md()'
|
||||||
}
|
}
|
||||||
y := secs / time.seconds_per_hour / 24 / 365
|
y := secs / time.seconds_per_hour / 24 / time.days_in_year
|
||||||
if y == 1 {
|
if y == 1 {
|
||||||
return '${prefix}1 year$suffix'
|
return '${prefix}1 year$suffix'
|
||||||
}
|
}
|
||||||
|
@ -234,14 +235,14 @@ pub fn (t Time) relative_short() string {
|
||||||
}
|
}
|
||||||
return '$prefix${h}h$suffix'
|
return '$prefix${h}h$suffix'
|
||||||
}
|
}
|
||||||
if secs < time.seconds_per_hour * 24 * 365 {
|
if secs < time.seconds_per_hour * 24 * time.days_in_year {
|
||||||
d := secs / time.seconds_per_hour / 24
|
d := secs / time.seconds_per_hour / 24
|
||||||
if d == 1 {
|
if d == 1 {
|
||||||
return '${prefix}1d$suffix'
|
return '${prefix}1d$suffix'
|
||||||
}
|
}
|
||||||
return '$prefix${d}d$suffix'
|
return '$prefix${d}d$suffix'
|
||||||
}
|
}
|
||||||
y := secs / time.seconds_per_hour / 24 / 365
|
y := secs / time.seconds_per_hour / 24 / time.days_in_year
|
||||||
if y == 1 {
|
if y == 1 {
|
||||||
return '${prefix}1y$suffix'
|
return '${prefix}1y$suffix'
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,13 @@ fn test_add_to_day_in_the_previous_century() ? {
|
||||||
aa := a.add_days(180)
|
aa := a.add_days(180)
|
||||||
dump(a.debug())
|
dump(a.debug())
|
||||||
dump(aa.debug())
|
dump(aa.debug())
|
||||||
assert aa.ymmdd() == '1900-06-29'
|
assert aa.ymmdd() == '1900-06-30'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_add_to_day_in_the_past() ? {
|
fn test_add_to_day_in_the_past() ? {
|
||||||
a := time.parse_iso8601('1990-03-01')?
|
a := time.parse_iso8601('1990-03-01')?
|
||||||
aa := a.add_days(180)
|
aa := a.add_days(180)
|
||||||
assert aa.ymmdd() == '1990-08-27'
|
assert aa.ymmdd() == '1990-08-28'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_add_to_day_in_the_recent_past() ? {
|
fn test_add_to_day_in_the_recent_past() ? {
|
||||||
|
|
|
@ -267,3 +267,9 @@ fn test_recursive_local_call() {
|
||||||
fn test_strftime() {
|
fn test_strftime() {
|
||||||
assert '1980 July 11' == time_to_test.strftime('%Y %B %d')
|
assert '1980 July 11' == time_to_test.strftime('%Y %B %d')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_add_seconds_to_time() {
|
||||||
|
now_tm := time.now()
|
||||||
|
future_tm := now_tm.add_seconds(60)
|
||||||
|
assert now_tm.unix < future_tm.unix
|
||||||
|
}
|
||||||
|
|
|
@ -48,67 +48,39 @@ pub fn unix2(abs i64, microsecond int) Time {
|
||||||
|
|
||||||
fn calculate_date_from_offset(day_offset_ i64) (int, int, int) {
|
fn calculate_date_from_offset(day_offset_ i64) (int, int, int) {
|
||||||
mut day_offset := day_offset_
|
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
|
// source: http://howardhinnant.github.io/date_algorithms.html#civil_from_days
|
||||||
// 1970-2000 (inclusive) has 31 years (8 of which are leap years)
|
|
||||||
mut year := 2001
|
// shift from 1970-01-01 to 0000-03-01
|
||||||
day_offset -= 31 * 365 + 8
|
day_offset += 719468 // int(days_per_400_years * 1970 / 400 - (28+31))
|
||||||
// Account for 400 year cycle
|
|
||||||
year += int(day_offset / days_per_400_years) * 400
|
mut era := 0
|
||||||
day_offset %= days_per_400_years
|
if day_offset >= 0 {
|
||||||
// Account for 100 year cycle
|
era = int(day_offset / days_per_400_years)
|
||||||
if day_offset == days_per_100_years * 4 {
|
|
||||||
year += 300
|
|
||||||
day_offset -= days_per_100_years * 3
|
|
||||||
} else {
|
} else {
|
||||||
year += int(day_offset / days_per_100_years) * 100
|
era = int((day_offset - days_per_400_years - 1) / days_per_400_years)
|
||||||
day_offset %= days_per_100_years
|
|
||||||
}
|
}
|
||||||
// Account for 4 year cycle
|
// doe(day of era) [0, 146096]
|
||||||
if day_offset == days_per_4_years * 25 {
|
doe := day_offset - era * days_per_400_years
|
||||||
year += 96
|
// yoe(year of era) [0, 399]
|
||||||
day_offset -= days_per_4_years * 24
|
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
|
||||||
} else {
|
} else {
|
||||||
year += int(day_offset / days_per_4_years) * 4
|
m -= 9
|
||||||
day_offset %= days_per_4_years
|
|
||||||
}
|
}
|
||||||
// Account for every year
|
if m <= 2 {
|
||||||
if day_offset == 365 * 4 {
|
y += 1
|
||||||
year += 3
|
|
||||||
day_offset -= 365 * 3
|
|
||||||
} else {
|
|
||||||
year += int(day_offset / 365)
|
|
||||||
day_offset %= 365
|
|
||||||
}
|
}
|
||||||
if day_offset < 0 {
|
return y, m, d
|
||||||
year--
|
|
||||||
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] {
|
|
||||||
if estimated_month == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
estimated_month--
|
|
||||||
}
|
|
||||||
day_offset -= days_before[estimated_month]
|
|
||||||
return year, int(estimated_month + 1), int(day_offset + 1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_time_from_offset(second_offset_ i64) (int, int, int) {
|
fn calculate_time_from_offset(second_offset_ i64) (int, int, int) {
|
||||||
|
|
Loading…
Reference in New Issue