time: fix calculate_date_from_offset (#14399)
							parent
							
								
									771ec47a04
								
							
						
					
					
						commit
						fd17b62ea6
					
				| 
						 | 
					@ -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