about summary refs log tree commit diff
path: root/vendor/github.com/ncruces/go-strftime/strftime.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/ncruces/go-strftime/strftime.go')
-rw-r--r--vendor/github.com/ncruces/go-strftime/strftime.go324
1 files changed, 324 insertions, 0 deletions
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"