From 1a57267a17c2fc17fb6e104846fabc3e363c326c Mon Sep 17 00:00:00 2001 From: Emile Date: Fri, 16 Aug 2024 19:50:26 +0200 Subject: initial commit --- vendor/github.com/ncruces/go-strftime/strftime.go | 324 ++++++++++++++++++++++ 1 file changed, 324 insertions(+) create mode 100644 vendor/github.com/ncruces/go-strftime/strftime.go (limited to 'vendor/github.com/ncruces/go-strftime/strftime.go') diff --git a/vendor/github.com/ncruces/go-strftime/strftime.go b/vendor/github.com/ncruces/go-strftime/strftime.go new file mode 100644 index 0000000..5308ef7 --- /dev/null +++ b/vendor/github.com/ncruces/go-strftime/strftime.go @@ -0,0 +1,324 @@ +package strftime + +import ( + "bytes" + "strconv" + "time" +) + +// Format returns a textual representation of the time value +// formatted according to the strftime format specification. +func Format(fmt string, t time.Time) string { + buf := buffer(fmt) + return string(AppendFormat(buf, fmt, t)) +} + +// AppendFormat is like Format, but appends the textual representation +// to dst and returns the extended buffer. +func AppendFormat(dst []byte, fmt string, t time.Time) []byte { + var parser parser + + parser.literal = func(b byte) error { + dst = append(dst, b) + return nil + } + + parser.format = func(spec, flag byte) error { + switch spec { + case 'A': + dst = append(dst, t.Weekday().String()...) + return nil + case 'a': + dst = append(dst, t.Weekday().String()[:3]...) + return nil + case 'B': + dst = append(dst, t.Month().String()...) + return nil + case 'b', 'h': + dst = append(dst, t.Month().String()[:3]...) + return nil + case 'm': + dst = appendInt2(dst, int(t.Month()), flag) + return nil + case 'd': + dst = appendInt2(dst, int(t.Day()), flag) + return nil + case 'e': + dst = appendInt2(dst, int(t.Day()), ' ') + return nil + case 'I': + dst = append12Hour(dst, t, flag) + return nil + case 'l': + dst = append12Hour(dst, t, ' ') + return nil + case 'H': + dst = appendInt2(dst, t.Hour(), flag) + return nil + case 'k': + dst = appendInt2(dst, t.Hour(), ' ') + return nil + case 'M': + dst = appendInt2(dst, t.Minute(), flag) + return nil + case 'S': + dst = appendInt2(dst, t.Second(), flag) + return nil + case 'L': + dst = append(dst, t.Format(".000")[1:]...) + return nil + case 'f': + dst = append(dst, t.Format(".000000")[1:]...) + return nil + case 'N': + dst = append(dst, t.Format(".000000000")[1:]...) + return nil + case 'y': + dst = t.AppendFormat(dst, "06") + return nil + case 'Y': + dst = t.AppendFormat(dst, "2006") + return nil + case 'C': + dst = t.AppendFormat(dst, "2006") + dst = dst[:len(dst)-2] + return nil + case 'U': + dst = appendWeekNumber(dst, t, flag, true) + return nil + case 'W': + dst = appendWeekNumber(dst, t, flag, false) + return nil + case 'V': + _, w := t.ISOWeek() + dst = appendInt2(dst, w, flag) + return nil + case 'g': + y, _ := t.ISOWeek() + dst = year(y).AppendFormat(dst, "06") + return nil + case 'G': + y, _ := t.ISOWeek() + dst = year(y).AppendFormat(dst, "2006") + return nil + case 's': + dst = strconv.AppendInt(dst, t.Unix(), 10) + return nil + case 'Q': + dst = strconv.AppendInt(dst, t.UnixMilli(), 10) + return nil + case 'w': + w := t.Weekday() + dst = appendInt1(dst, int(w)) + return nil + case 'u': + if w := t.Weekday(); w == 0 { + dst = append(dst, '7') + } else { + dst = appendInt1(dst, int(w)) + } + return nil + case 'j': + if flag == '-' { + dst = strconv.AppendInt(dst, int64(t.YearDay()), 10) + } else { + dst = t.AppendFormat(dst, "002") + } + return nil + } + + if layout := goLayout(spec, flag, false); layout != "" { + dst = t.AppendFormat(dst, layout) + return nil + } + + dst = append(dst, '%') + if flag != 0 { + dst = append(dst, flag) + } + dst = append(dst, spec) + return nil + } + + parser.parse(fmt) + return dst +} + +// Parse converts a textual representation of time to the time value it represents +// according to the strptime format specification. +func Parse(fmt, value string) (time.Time, error) { + pattern, err := layout(fmt, true) + if err != nil { + return time.Time{}, err + } + return time.Parse(pattern, value) +} + +// Layout converts a strftime format specification +// to a Go time pattern specification. +func Layout(fmt string) (string, error) { + return layout(fmt, false) +} + +func layout(fmt string, parsing bool) (string, error) { + dst := buffer(fmt) + var parser parser + + parser.literal = func(b byte) error { + if '0' <= b && b <= '9' { + return literalErr(b) + } + dst = append(dst, b) + if b == 'M' || b == 'T' || b == 'm' || b == 'n' { + switch { + case bytes.HasSuffix(dst, []byte("Jan")): + return literalErr("Jan") + case bytes.HasSuffix(dst, []byte("Mon")): + return literalErr("Mon") + case bytes.HasSuffix(dst, []byte("MST")): + return literalErr("MST") + case bytes.HasSuffix(dst, []byte("PM")): + return literalErr("PM") + case bytes.HasSuffix(dst, []byte("pm")): + return literalErr("pm") + } + } + return nil + } + + parser.format = func(spec, flag byte) error { + if layout := goLayout(spec, flag, parsing); layout != "" { + dst = append(dst, layout...) + return nil + } + + switch spec { + default: + return formatError{} + + case 'L', 'f', 'N': + if bytes.HasSuffix(dst, []byte(".")) || bytes.HasSuffix(dst, []byte(",")) { + switch spec { + default: + dst = append(dst, "000"...) + case 'f': + dst = append(dst, "000000"...) + case 'N': + dst = append(dst, "000000000"...) + } + return nil + } + return formatError{message: "must follow '.' or ','"} + } + } + + if err := parser.parse(fmt); err != nil { + return "", err + } + return string(dst), nil +} + +// UTS35 converts a strftime format specification +// to a Unicode Technical Standard #35 Date Format Pattern. +func UTS35(fmt string) (string, error) { + const quote = '\'' + var quoted bool + dst := buffer(fmt) + + var parser parser + + parser.literal = func(b byte) error { + if b == quote { + dst = append(dst, quote, quote) + return nil + } + if !quoted && ('a' <= b && b <= 'z' || 'A' <= b && b <= 'Z') { + dst = append(dst, quote) + quoted = true + } + dst = append(dst, b) + return nil + } + + parser.format = func(spec, flag byte) error { + if quoted { + dst = append(dst, quote) + quoted = false + } + if pattern := uts35Pattern(spec, flag); pattern != "" { + dst = append(dst, pattern...) + return nil + } + return formatError{} + } + + if err := parser.parse(fmt); err != nil { + return "", err + } + if quoted { + dst = append(dst, quote) + } + return string(dst), nil +} + +func buffer(format string) (buf []byte) { + const bufSize = 64 + max := len(format) + 10 + if max < bufSize { + var b [bufSize]byte + buf = b[:0] + } else { + buf = make([]byte, 0, max) + } + return +} + +func year(y int) time.Time { + return time.Date(y, time.January, 1, 0, 0, 0, 0, time.UTC) +} + +func appendWeekNumber(dst []byte, t time.Time, flag byte, sunday bool) []byte { + offset := int(t.Weekday()) + if sunday { + offset = 6 - offset + } else if offset != 0 { + offset = 7 - offset + } + return appendInt2(dst, (t.YearDay()+offset)/7, flag) +} + +func append12Hour(dst []byte, t time.Time, flag byte) []byte { + h := t.Hour() + if h == 0 { + h = 12 + } else if h > 12 { + h -= 12 + } + return appendInt2(dst, h, flag) +} + +func appendInt1(dst []byte, i int) []byte { + return append(dst, byte('0'+i)) +} + +func appendInt2(dst []byte, i int, flag byte) []byte { + if flag == 0 || i >= 10 { + return append(dst, smallsString[i*2:i*2+2]...) + } + if flag == ' ' { + dst = append(dst, flag) + } + return appendInt1(dst, i) +} + +const smallsString = "" + + "00010203040506070809" + + "10111213141516171819" + + "20212223242526272829" + + "30313233343536373839" + + "40414243444546474849" + + "50515253545556575859" + + "60616263646566676869" + + "70717273747576777879" + + "80818283848586878889" + + "90919293949596979899" -- cgit 1.4.1