diff --git a/time.go b/time.go index 213abd4..5dda79c 100644 --- a/time.go +++ b/time.go @@ -25,20 +25,20 @@ func main() { fmt.Println("Loc", now.In(loc)) /* boundary checks */ - CheckInput([]int{2019, 11, 10, - 01, 02, 56, 0}) - CheckInput([]int{2019, 11, 10, - 01, 02, 60, 0}) - CheckInput([]int{2019, 11, 10, - 01, 60, 59, 0}) - CheckInput([]int{2019, 11, 10, - 24, 59, 59, 0}) - CheckInput([]int{2019, 11, 10, - 25, 59, 59, 0}) - CheckInput([]int{2019, 11, 10, - 23, 59, 59, 0}) - CheckInput([]int{2019, 11, 31, - 23, 0, 0, 0}) + for _, st := range [][]int{ + []int{2019, 11, 10, 01, 02, 56, 0}, + []int{2019, 11, 10, 01, 02, 60, 0}, + []int{2019, 11, 10, 01, 60, 59, 0}, + []int{2019, 11, 10, 24, 59, 59, 0}, + []int{2019, 11, 10, 25, 59, 59, 0}, + []int{2019, 11, 10, 23, 59, 59, 0}, + []int{2019, 11, 31, 23, 0, 0, 0}, + } { + err := Exists(st, "America/Denver") + if nil != err { + fmt.Println(err) + } + } /* funky times */ tz := "America/Denver" @@ -75,41 +75,94 @@ func main() { 05, 01, 00, 0}, tz) } -func CheckInput2(st []int, tzstr string) { - m := time.Month(st[1]) +type ErrNoExist struct { + e string + t []int + z string +} + +func (err ErrNoExist) Error() string { + return fmt.Sprintf("E_INVALID_TIME: '%#v' is not a valid timestamp at '%s': %s", err.t, err.z, err.e) +} + +// Check if the time is a real time in the given timezone. +// +// For example: 2:30am doesn't happen on 2019 Nov 3rd according +// to America/Denver local time, due to the end of Daylight Savings Time, +// but it did happen in America/Phoenix. +// +// Also rejects times that are parsable and return a valid date object, +// but are not canonical, such as 24:60:75 November 31st, 2020. +// (which would be represented as `2020-12-02 02:01:15 +0000 UTC`) +// +// Example of parsable, but non-canonical time: +// +// fmt.Println(time.Date(2020, time.November, 31, 25, 60, 0, 0, time.UTC)) +// "2020-12-02 02:01:15 +0000 UTC" +// +// Example of a canonical, but non-parsable time (the 2016 leap second): +// +// fmt.Println(time.Date(2016, time.December, 31, 23, 59, 60, 0, time.UTC)) +// "2020-12-02 02:00:00 +0000 UTC" // should be "2016-12-31 23:59:60 +0000 UTC" +func Exists(st []int, tzstr string) error { tz, err := time.LoadLocation(tzstr) if nil != err { - fmt.Println("screwed the pooch") - return + return err } - // Does the time exist + m := time.Month(st[1]) t1 := time.Date(st[0], m, st[2], st[3], st[4], st[5], st[6], tz) if st[5] != t1.Second() { - fmt.Println("Bad Second", st, t1) - return + return ErrNoExist{ + t: st, + z: tzstr, + e: "invalid second, probably just bad math on your part", + } } if st[4] != t1.Minute() { - fmt.Println("Bad Minute", st, t1.Minute()) - return + return ErrNoExist{ + t: st, + z: tzstr, + e: "invalid minute, probably just bad math on your part, but perhaps a half-hour daylight savings or summer time", + } } if st[3] != t1.Hour() { - fmt.Println("Bad Hour", st, t1) - return + return ErrNoExist{ + t: st, + z: tzstr, + e: "invalid hour, possibly a Daylight Savings or Summer Time error, or perhaps bad math on your part", + } } if st[2] != t1.Day() { - fmt.Println("Bad Day of Month", st, t1) - return + return ErrNoExist{ + t: st, + z: tzstr, + e: "invalid day of month, most likely bad math on your part. Remember: 31 28ΒΌ 31 30 31 30 31 31 30 31 30 31", + } } if st[1] != int(t1.Month()) { - fmt.Println("Bad Month", st, t1) - return + return ErrNoExist{ + t: st, + z: tzstr, + e: "invalid month, most likely bad math on your part. Remember: Decemberween isn't until next year", + } } if st[0] != t1.Year() { - fmt.Println("Bad Year", st, t1) - return + return ErrNoExist{ + t: st, + z: tzstr, + e: "invalid year, must have reached the end of time...", + } } + return nil +} + +func IsAmbigious(st []int, tzstr string) error { + return fmt.Errorf("Not Implemented") +} + +func CheckInput2(st []int, tzstr string) error { // Does the time exist twice? // (if I change the time in UTC, do I still get the same time) // Note: Some timezones change by half or quarter hour @@ -122,6 +175,12 @@ func CheckInput2(st []int, tzstr string) { // https://en.wikipedia.org/wiki/Summer_time_in_Europe // https://en.wikipedia.org/wiki/Daylight_saving_time_in_the_Americas // If I change the time iadd or subtract time in UTC, do I see the same difference in TZ? + tz, err := time.LoadLocation(tzstr) + if nil != err { + return err + } + m := time.Month(st[1]) + t1 := time.Date(st[0], m, st[2], st[3], st[4], st[5], st[6], tz) u1 := t1.UTC() // A better way to do this would probably be to parse the timezone database, but... yeah... for _, n := range []int{ /*-120, -60,*/ 30, 60, 120} { @@ -131,39 +190,11 @@ func CheckInput2(st []int, tzstr string) { fmt.Println("Ambiguous Time") fmt.Printf("%s, %s, %+d\n", t1, u1, n) fmt.Printf("%s, %s, %+d\n", t2, u2, n) - return + return nil } } //ta := -} - -func CheckInput(st []int) { - m := time.Month(st[1]) - t1 := time.Date(st[0], m, st[2], st[3], st[4], st[5], st[6], time.UTC) - if st[5] != t1.Second() { - fmt.Println("Bad Second", st) - return - } - if st[4] != t1.Minute() { - fmt.Println("Bad Minute", st, t1.Minute()) - return - } - if st[3] != t1.Hour() { - fmt.Println("Bad Hour", st) - return - } - if st[2] != t1.Day() { - fmt.Println("Bad Day of Month", st) - return - } - if st[1] != int(t1.Month()) { - fmt.Println("Bad Month", st) - return - } - if st[0] != t1.Year() { - fmt.Println("Bad Year", st) - return - } + return nil } /*