Skip to content

Instantly share code, notes, and snippets.

@invidian
Created October 2, 2019 10:19
Show Gist options
  • Save invidian/346b0ea57f20677ce5ae74b410e5cbe1 to your computer and use it in GitHub Desktop.
Save invidian/346b0ea57f20677ce5ae74b410e5cbe1 to your computer and use it in GitHub Desktop.
Golang calculating max time
package main
import (
"fmt"
"time"
)
// hoursSince returns how many hours passed from given date.
// for Time 0 (time.Time{}), it returns 0.
func hoursSince(d time.Time) int {
// Get current year
y, _, _ := d.Date()
// Golang time starts from 1
y = y - 1
// Hours in non-leap years
normalHours := y * 365 * 24
// Hours in leap years
leapHours := (y / 4) * 24
// Calculate remaining hours since beginning of the year and remove hours in Time 0.
remainingHours := int(d.Sub(time.Date(y, 0, 0, 0, 0, 0, 0, time.UTC)).Round(time.Hour).Hours()) - int(time.Time{}.Sub(time.Date(0, 0, 0, 0, 0, 0, 0, time.UTC)).Round(time.Hour).Hours())
return normalHours + leapHours + remainingHours
}
func main() {
// Snapshot current time
t := time.Now()
// Max golang date before it overflows
// Calculate max date golang can handle. AddDate is easier to use than time.Date() since we don't have to calculate number of months
tMax := time.Time{}.AddDate(292277026853, 0, 312).Add((time.Duration(7) * time.Hour) + (time.Duration(15) * time.Second) + (time.Duration(999) * time.Millisecond) + (time.Duration(999) * time.Microsecond) + (time.Duration(999) * time.Nanosecond))
// h represents max number of hours we can add to a current time before it overflows
h := hoursSince(tMax) - hoursSince(t) - 3 // +1
// If hours now + added hours are bigged than max time, panic
if hoursSince(t)+h > hoursSince(tMax)-3 {
panic(fmt.Sprintf("Added time overflows the universe, max value possible to add is %d", hoursSince(tMax)-2))
}
fmt.Printf("Now is %s\n", t)
fmt.Println()
fmt.Printf("Attempting to add %d hours\n", h)
fmt.Println()
// First, calculate how many days we have to add
days := h / 24
fmt.Printf("%d days to add\n", days)
// Calculate how many years we have in calculated days, this considers leap years as well
years := (days / ((365 * 4) + 1)) * 4
// Since we have years now, get remaining days we have left
days = days % ((365 * 4) + 1)
fmt.Printf("Adding %d years, %d days\n", years, days)
// Add calculated years and days to current date
t = t.AddDate(years, 0, days)
fmt.Printf("Now is %s\n", t)
fmt.Println()
// There are some hours left to add after /24 division, get them with module and add as well
h = h % 24
fmt.Printf("%d hours remaining to add\n", h)
fmt.Println()
fmt.Printf("Adding %d hours\n", h)
// We can't simply put entire h into time.Duration() as time.Duration overflows only after 290 years
t = t.Add(time.Duration(h) * time.Hour)
fmt.Printf("Now is %s\n", t)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment