Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
2.5 kB · 90 lines
Go
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091package aqtime
import ( "fmt" "regexp" "strings" "time")
// RE matches the canonical internal format: 2006-01-02T15:04:05.000Z// It also accepts the file-safe variant with dashes/dots swapped, for backward compat.var RE *regexp.Regexpvar Pattern string = `(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d)(?:[:-])(\d\d)(?:[:-])(\d\d)(?:[.-])(\d\d\d)Z`
func init() { RE = regexp.MustCompile(fmt.Sprintf(`^%s$`, Pattern))}
var fstr = "2006-01-02T15:04:05.000Z"
type AQTime string
// return a consistently formatted timestampfunc FromMillis(ms int64) AQTime { return AQTime(time.UnixMilli(ms).UTC().Format(fstr))}
// return a consistently formatted timestampfunc FromSec(sec int64) AQTime { return AQTime(time.Unix(sec, 0).UTC().Format(fstr))}
func FromString(str string) (AQTime, error) { // Reject -00:00 (valid RFC 3339 but disallowed by ATProto) if strings.HasSuffix(str, "-00:00") { return "", fmt.Errorf("bad time format, -00:00 timezone offset is not allowed, got=%s", str) }
t, err := time.Parse(time.RFC3339Nano, str) if err != nil { // Fall back to file-safe variant (e.g. 2024-09-13T18-10-17-090Z) if bits := RE.FindStringSubmatch(str); bits != nil { if bits[2] < "01" || bits[2] > "12" || bits[3] < "01" || bits[3] > "31" || bits[4] > "23" || bits[5] > "59" || bits[6] > "60" { return "", fmt.Errorf("bad time format, invalid date/time values in %s", str) } return AQTime(str), nil } return "", fmt.Errorf("bad time format: %w", err) }
// Reject if UTC normalization results in a negative year utc := t.UTC() if utc.Year() < 0 { return "", fmt.Errorf("bad time format, datetime normalizes to negative year: %s", str) }
// Normalize to canonical UTC millisecond format return AQTime(utc.Format(fstr)), nil}
func FromTime(t time.Time) AQTime { return AQTime(t.UTC().Format(fstr))}
// year, month, day, hour, min, sec, millisecondfunc (aqt AQTime) Parts() (string, string, string, string, string, string, string) { bits := RE.FindStringSubmatch(aqt.String()) return bits[1], bits[2], bits[3], bits[4], bits[5], bits[6], bits[7]}
func (aqt AQTime) String() string { return string(aqt)}
// version of AQTime suitable for saving as a file (esp on windows)func (aqt AQTime) FileSafeString() string { str := string(aqt) str = strings.ReplaceAll(str, ":", "-") str = strings.ReplaceAll(str, ".", "-") return str}
func (aqt AQTime) Time() time.Time { t, err := time.Parse(fstr, aqt.String()) if err != nil { panic(err) } return t}