package models import ( "bytes" "encoding/json" "fmt" "strconv" "strings" "time" ) var TimeOfDayTimeZone = time.UTC type TimeOfDay int func (t *TimeOfDay) UnmarshalJSON(v []byte) error { if bytes.Equal(v, []byte("null")) { *t = -1 } var str string err := json.Unmarshal(v, &str) if err != nil { var n int err = json.Unmarshal(v, &n) if err != nil { return err } if n < -1 && n >= 86400 { return fmt.Errorf("value outside range 0..86400: %d", n) } } t2, err := ParseTimeOfDay(str) if err != nil { return err } *t = t2 return nil } func (t TimeOfDay) MarshalJSON() ([]byte, error) { if t.IsNever() { return []byte("null"), nil } return json.Marshal(t.String()) } const Never = TimeOfDay(-1) func (t *TimeOfDay) String() string { if *t < 0 { return "n/a" } return fmt.Sprintf("%02d:%02d:%02d", *t/3600, (*t/60)%60, *t%60) } func (t *TimeOfDay) StringPtr() *string { if *t < 0 { return nil } s := t.String() return &s } func (t TimeOfDay) IsNever() bool { return t == Never } func (t TimeOfDay) IsBetween(from TimeOfDay, to TimeOfDay) bool { if from == to { return t == from } else if from > to { return t >= from || t <= to } else { return t >= from && t <= to } } func CurrentTimeOfDay() TimeOfDay { return TimeOfDayFromDate(time.Now().In(TimeOfDayTimeZone)) } func TimeOfDayFromDate(date time.Time) TimeOfDay { localDate := date.In(TimeOfDayTimeZone) return NewTimeOfDay(localDate.Hour(), localDate.Minute(), localDate.Second()) } func NewTimeOfDay(hours, minutes, seconds int) TimeOfDay { return TimeOfDay(((hours % 24) * 3600) + ((minutes % 60) * 60) + seconds) } func ParseTimeOfDayPtr(str *string) (TimeOfDay, error) { if str == nil { return Never, nil } return ParseTimeOfDay(*str) } func ParseTimeOfDay(str string) (TimeOfDay, error) { if str == "" || str == "n/a" || str == "N/A" { return -1, nil } split := strings.SplitN(str, ":", 4) res := 0 n, err := strconv.Atoi(split[0]) if err != nil { return Never, err } res += n * 3600 if len(split) >= 2 { n, err := strconv.Atoi(split[1]) if err != nil { return Never, err } res += n * 60 } if len(split) >= 3 { n, err := strconv.Atoi(split[2]) if err != nil { return Never, err } res += n } if res >= 86400 || res < 0 { return Never, fmt.Errorf("invalid time of day string %s (=%d)", str, res) } return TimeOfDay(res), nil }