time: fix calculate_date_from_offset (#14399)
							parent
							
								
									b50f7fdc71
								
							
						
					
					
						commit
						c28051020a
					
				| 
						 | 
				
			
			@ -184,3 +184,17 @@ fn test_parse_rfc3339() {
 | 
			
		|||
		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_day    = 24 * seconds_per_hour
 | 
			
		||||
	seconds_per_week   = 7 * seconds_per_day
 | 
			
		||||
	days_per_400_years = 365 * 400 + 97
 | 
			
		||||
	days_per_100_years = 365 * 100 + 24
 | 
			
		||||
	days_per_4_years   = 365 * 4 + 1
 | 
			
		||||
	days_per_400_years = days_in_year * 400 + 97
 | 
			
		||||
	days_per_100_years = days_in_year * 100 + 24
 | 
			
		||||
	days_per_4_years   = days_in_year * 4 + 1
 | 
			
		||||
	days_in_year       = 365
 | 
			
		||||
	days_before        = [
 | 
			
		||||
		0,
 | 
			
		||||
		31,
 | 
			
		||||
| 
						 | 
				
			
			@ -179,13 +180,13 @@ pub fn (t Time) relative() string {
 | 
			
		|||
		}
 | 
			
		||||
		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 ' {
 | 
			
		||||
			return 'on $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 {
 | 
			
		||||
		return '${prefix}1 year$suffix'
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -234,14 +235,14 @@ pub fn (t Time) relative_short() string {
 | 
			
		|||
		}
 | 
			
		||||
		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
 | 
			
		||||
		if d == 1 {
 | 
			
		||||
			return '${prefix}1d$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 {
 | 
			
		||||
		return '${prefix}1y$suffix'
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,13 +5,13 @@ fn test_add_to_day_in_the_previous_century() ? {
 | 
			
		|||
	aa := a.add_days(180)
 | 
			
		||||
	dump(a.debug())
 | 
			
		||||
	dump(aa.debug())
 | 
			
		||||
	assert aa.ymmdd() == '1900-06-29'
 | 
			
		||||
	assert aa.ymmdd() == '1900-06-30'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn test_add_to_day_in_the_past() ? {
 | 
			
		||||
	a := time.parse_iso8601('1990-03-01')?
 | 
			
		||||
	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() ? {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -267,3 +267,9 @@ fn test_recursive_local_call() {
 | 
			
		|||
fn test_strftime() {
 | 
			
		||||
	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) {
 | 
			
		||||
	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 += int(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
 | 
			
		||||
 | 
			
		||||
	// 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)
 | 
			
		||||
	} else {
 | 
			
		||||
		year += int(day_offset / days_per_100_years) * 100
 | 
			
		||||
		day_offset %= days_per_100_years
 | 
			
		||||
		era = int((day_offset - days_per_400_years - 1) / days_per_400_years)
 | 
			
		||||
	}
 | 
			
		||||
	// Account for 4 year cycle
 | 
			
		||||
	if day_offset == days_per_4_years * 25 {
 | 
			
		||||
		year += 96
 | 
			
		||||
		day_offset -= days_per_4_years * 24
 | 
			
		||||
	// 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
 | 
			
		||||
	} else {
 | 
			
		||||
		year += int(day_offset / days_per_4_years) * 4
 | 
			
		||||
		day_offset %= days_per_4_years
 | 
			
		||||
		m -= 9
 | 
			
		||||
	}
 | 
			
		||||
	// Account for every year
 | 
			
		||||
	if day_offset == 365 * 4 {
 | 
			
		||||
		year += 3
 | 
			
		||||
		day_offset -= 365 * 3
 | 
			
		||||
	} else {
 | 
			
		||||
		year += int(day_offset / 365)
 | 
			
		||||
		day_offset %= 365
 | 
			
		||||
	if m <= 2 {
 | 
			
		||||
		y += 1
 | 
			
		||||
	}
 | 
			
		||||
	if day_offset < 0 {
 | 
			
		||||
		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)
 | 
			
		||||
	return y, m, d
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn calculate_time_from_offset(second_offset_ i64) (int, int, int) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue