about summary refs log tree commit diff
path: root/vendor/github.com/ncruces/go-strftime
diff options
context:
space:
mode:
authorEmile <git@emile.space>2024-08-16 19:50:26 +0200
committerEmile <git@emile.space>2024-08-16 19:50:26 +0200
commit1a57267a17c2fc17fb6e104846fabc3e363c326c (patch)
tree1e574e3a80622086dc3c81ff9cba65ef7049b1a9 /vendor/github.com/ncruces/go-strftime
initial commit
Diffstat (limited to 'vendor/github.com/ncruces/go-strftime')
-rw-r--r--vendor/github.com/ncruces/go-strftime/.gitignore15
-rw-r--r--vendor/github.com/ncruces/go-strftime/LICENSE21
-rw-r--r--vendor/github.com/ncruces/go-strftime/README.md5
-rw-r--r--vendor/github.com/ncruces/go-strftime/parser.go107
-rw-r--r--vendor/github.com/ncruces/go-strftime/pkg.go96
-rw-r--r--vendor/github.com/ncruces/go-strftime/specifiers.go241
-rw-r--r--vendor/github.com/ncruces/go-strftime/strftime.go324
7 files changed, 809 insertions, 0 deletions
diff --git a/vendor/github.com/ncruces/go-strftime/.gitignore b/vendor/github.com/ncruces/go-strftime/.gitignore
new file mode 100644
index 0000000..66fd13c
--- /dev/null
+++ b/vendor/github.com/ncruces/go-strftime/.gitignore
@@ -0,0 +1,15 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Dependency directories (remove the comment below to include it)
+# vendor/
diff --git a/vendor/github.com/ncruces/go-strftime/LICENSE b/vendor/github.com/ncruces/go-strftime/LICENSE
new file mode 100644
index 0000000..7f0f553
--- /dev/null
+++ b/vendor/github.com/ncruces/go-strftime/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 Nuno Cruces
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/ncruces/go-strftime/README.md b/vendor/github.com/ncruces/go-strftime/README.md
new file mode 100644
index 0000000..5b0573c
--- /dev/null
+++ b/vendor/github.com/ncruces/go-strftime/README.md
@@ -0,0 +1,5 @@
+# `strftime`/`strptime` compatible time formatting and parsing for Go
+
+[![Go Reference](https://pkg.go.dev/badge/image)](https://pkg.go.dev/github.com/ncruces/go-strftime)
+[![Go Report](https://goreportcard.com/badge/github.com/ncruces/go-strftime)](https://goreportcard.com/report/github.com/ncruces/go-strftime)
+[![Go Coverage](https://github.com/ncruces/go-strftime/wiki/coverage.svg)](https://raw.githack.com/wiki/ncruces/go-strftime/coverage.html)
\ No newline at end of file
diff --git a/vendor/github.com/ncruces/go-strftime/parser.go b/vendor/github.com/ncruces/go-strftime/parser.go
new file mode 100644
index 0000000..b006de3
--- /dev/null
+++ b/vendor/github.com/ncruces/go-strftime/parser.go
@@ -0,0 +1,107 @@
+package strftime
+
+import "unicode/utf8"
+
+type parser struct {
+	format  func(spec, flag byte) error
+	literal func(byte) error
+}
+
+func (p *parser) parse(fmt string) error {
+	const (
+		initial = iota
+		percent
+		flagged
+		modified
+	)
+
+	var flag, modifier byte
+	var err error
+	state := initial
+	start := 0
+	for i, b := range []byte(fmt) {
+		switch state {
+		default:
+			if b == '%' {
+				state = percent
+				start = i
+				continue
+			}
+			err = p.literal(b)
+
+		case percent:
+			if b == '-' || b == ':' {
+				state = flagged
+				flag = b
+				continue
+			}
+			if b == 'E' || b == 'O' {
+				state = modified
+				modifier = b
+				flag = 0
+				continue
+			}
+			err = p.format(b, 0)
+			state = initial
+
+		case flagged:
+			if b == 'E' || b == 'O' {
+				state = modified
+				modifier = b
+				continue
+			}
+			err = p.format(b, flag)
+			state = initial
+
+		case modified:
+			if okModifier(modifier, b) {
+				err = p.format(b, flag)
+			} else {
+				err = p.literals(fmt[start : i+1])
+			}
+			state = initial
+		}
+
+		if err != nil {
+			if err, ok := err.(formatError); ok {
+				err.setDirective(fmt, start, i)
+				return err
+			}
+			return err
+		}
+	}
+
+	if state != initial {
+		return p.literals(fmt[start:])
+	}
+	return nil
+}
+
+func (p *parser) literals(literal string) error {
+	for _, b := range []byte(literal) {
+		if err := p.literal(b); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+type literalErr string
+
+func (e literalErr) Error() string {
+	return "strftime: unsupported literal: " + string(e)
+}
+
+type formatError struct {
+	message   string
+	directive string
+}
+
+func (e formatError) Error() string {
+	return "strftime: unsupported directive: " + e.directive + " " + e.message
+}
+
+func (e *formatError) setDirective(str string, i, j int) {
+	_, n := utf8.DecodeRuneInString(str[j:])
+	e.directive = str[i : j+n]
+}
diff --git a/vendor/github.com/ncruces/go-strftime/pkg.go b/vendor/github.com/ncruces/go-strftime/pkg.go
new file mode 100644
index 0000000..9a3bbd3
--- /dev/null
+++ b/vendor/github.com/ncruces/go-strftime/pkg.go
@@ -0,0 +1,96 @@
+/*
+Package strftime provides strftime/strptime compatible time formatting and parsing.
+
+The following specifiers are available:
+
+  Date (Year, Month, Day):
+    %Y - Year with century (can be negative, 4 digits at least)
+            -0001, 0000, 1995, 2009, 14292, etc.
+    %C - year / 100 (round down, 20 in 2009)
+    %y - year % 100 (00..99)
+
+    %m - Month of the year, zero-padded (01..12)
+            %-m  no-padded (1..12)
+    %B - Full month name (January)
+    %b - Abbreviated month name (Jan)
+    %h - Equivalent to %b
+
+    %d - Day of the month, zero-padded  (01..31)
+            %-d  no-padded (1..31)
+    %e - Day of the month, blank-padded ( 1..31)
+
+    %j - Day of the year (001..366)
+            %-j  no-padded (1..366)
+
+  Time (Hour, Minute, Second, Subsecond):
+    %H - Hour of the day, 24-hour clock, zero-padded  (00..23)
+            %-H  no-padded (0..23)
+    %k - Hour of the day, 24-hour clock, blank-padded ( 0..23)
+    %I - Hour of the day, 12-hour clock, zero-padded  (01..12)
+            %-I  no-padded (1..12)
+    %l - Hour of the day, 12-hour clock, blank-padded ( 1..12)
+    %P - Meridian indicator, lowercase (am or pm)
+    %p - Meridian indicator, uppercase (AM or PM)
+
+    %M - Minute of the hour (00..59)
+            %-M  no-padded (0..59)
+
+    %S - Second of the minute (00..60)
+            %-S  no-padded (0..60)
+
+    %L - Millisecond of the second (000..999)
+    %f - Microsecond of the second (000000..999999)
+    %N - Nanosecond  of the second (000000000..999999999)
+
+  Time zone:
+    %z - Time zone as hour and minute offset from UTC (e.g. +0900)
+            %:z - hour and minute offset from UTC with a colon (e.g. +09:00)
+    %Z - Time zone abbreviation (e.g. MST)
+
+  Weekday:
+    %A - Full weekday name (Sunday)
+    %a - Abbreviated weekday name (Sun)
+    %u - Day of the week (Monday is 1, 1..7)
+    %w - Day of the week (Sunday is 0, 0..6)
+
+  ISO 8601 week-based year and week number:
+  Week 1 of YYYY starts with a Monday and includes YYYY-01-04.
+  The days in the year before the first week are in the last week of
+  the previous year.
+    %G - Week-based year
+    %g - Last 2 digits of the week-based year (00..99)
+    %V - Week number of the week-based year (01..53)
+            %-V  no-padded (1..53)
+
+  Week number:
+  Week 1 of YYYY starts with a Sunday or Monday (according to %U or %W).
+  The days in the year before the first week are in week 0.
+    %U - Week number of the year.  The week starts with Sunday.  (00..53)
+            %-U  no-padded (0..53)
+    %W - Week number of the year.  The week starts with Monday.  (00..53)
+            %-W  no-padded (0..53)
+
+  Seconds since the Unix Epoch:
+    %s - Number of seconds since 1970-01-01 00:00:00 UTC.
+    %Q - Number of milliseconds since 1970-01-01 00:00:00 UTC.
+
+  Literal string:
+    %n - Newline character (\n)
+    %t - Tab character (\t)
+    %% - Literal % character
+
+  Combination:
+    %c - date and time (%a %b %e %T %Y)
+    %D - Date (%m/%d/%y)
+    %F - ISO 8601 date format (%Y-%m-%d)
+    %v - VMS date (%e-%b-%Y)
+    %x - Same as %D
+    %X - Same as %T
+    %r - 12-hour time (%I:%M:%S %p)
+    %R - 24-hour time (%H:%M)
+    %T - 24-hour time (%H:%M:%S)
+    %+ - date(1) (%a %b %e %H:%M:%S %Z %Y)
+
+The modifiers ``E'' and ``O'' are ignored.
+*/
+package strftime
diff --git a/vendor/github.com/ncruces/go-strftime/specifiers.go b/vendor/github.com/ncruces/go-strftime/specifiers.go
new file mode 100644
index 0000000..065f779
--- /dev/null
+++ b/vendor/github.com/ncruces/go-strftime/specifiers.go
@@ -0,0 +1,241 @@
+package strftime
+
+import "strings"
+
+// https://strftime.org/
+func goLayout(spec, flag byte, parsing bool) string {
+	switch spec {
+	default:
+		return ""
+
+	case 'B':
+		return "January"
+	case 'b', 'h':
+		return "Jan"
+	case 'm':
+		if flag == '-' || parsing {
+			return "1"
+		}
+		return "01"
+	case 'A':
+		return "Monday"
+	case 'a':
+		return "Mon"
+	case 'e':
+		return "_2"
+	case 'd':
+		if flag == '-' || parsing {
+			return "2"
+		}
+		return "02"
+	case 'j':
+		if flag == '-' {
+			if parsing {
+				return "__2"
+			}
+			return ""
+		}
+		return "002"
+	case 'I':
+		if flag == '-' || parsing {
+			return "3"
+		}
+		return "03"
+	case 'H':
+		if flag == '-' && !parsing {
+			return ""
+		}
+		return "15"
+	case 'M':
+		if flag == '-' || parsing {
+			return "4"
+		}
+		return "04"
+	case 'S':
+		if flag == '-' || parsing {
+			return "5"
+		}
+		return "05"
+	case 'y':
+		return "06"
+	case 'Y':
+		return "2006"
+	case 'p':
+		return "PM"
+	case 'P':
+		return "pm"
+	case 'Z':
+		return "MST"
+	case 'z':
+		if flag == ':' {
+			if parsing {
+				return "Z07:00"
+			}
+			return "-07:00"
+		}
+		if parsing {
+			return "Z0700"
+		}
+		return "-0700"
+
+	case '+':
+		if parsing {
+			return "Mon Jan _2 15:4:5 MST 2006"
+		}
+		return "Mon Jan _2 15:04:05 MST 2006"
+	case 'c':
+		if parsing {
+			return "Mon Jan _2 15:4:5 2006"
+		}
+		return "Mon Jan _2 15:04:05 2006"
+	case 'v':
+		return "_2-Jan-2006"
+	case 'F':
+		if parsing {
+			return "2006-1-2"
+		}
+		return "2006-01-02"
+	case 'D', 'x':
+		if parsing {
+			return "1/2/06"
+		}
+		return "01/02/06"
+	case 'r':
+		if parsing {
+			return "3:4:5 PM"
+		}
+		return "03:04:05 PM"
+	case 'T', 'X':
+		if parsing {
+			return "15:4:5"
+		}
+		return "15:04:05"
+	case 'R':
+		if parsing {
+			return "15:4"
+		}
+		return "15:04"
+
+	case '%':
+		return "%"
+	case 't':
+		return "\t"
+	case 'n':
+		return "\n"
+	}
+}
+
+// https://nsdateformatter.com/
+func uts35Pattern(spec, flag byte) string {
+	switch spec {
+	default:
+		return ""
+
+	case 'B':
+		return "MMMM"
+	case 'b', 'h':
+		return "MMM"
+	case 'm':
+		if flag == '-' {
+			return "M"
+		}
+		return "MM"
+	case 'A':
+		return "EEEE"
+	case 'a':
+		return "E"
+	case 'd':
+		if flag == '-' {
+			return "d"
+		}
+		return "dd"
+	case 'j':
+		if flag == '-' {
+			return "D"
+		}
+		return "DDD"
+	case 'I':
+		if flag == '-' {
+			return "h"
+		}
+		return "hh"
+	case 'H':
+		if flag == '-' {
+			return "H"
+		}
+		return "HH"
+	case 'M':
+		if flag == '-' {
+			return "m"
+		}
+		return "mm"
+	case 'S':
+		if flag == '-' {
+			return "s"
+		}
+		return "ss"
+	case 'y':
+		return "yy"
+	case 'Y':
+		return "yyyy"
+	case 'g':
+		return "YY"
+	case 'G':
+		return "YYYY"
+	case 'V':
+		if flag == '-' {
+			return "w"
+		}
+		return "ww"
+	case 'p':
+		return "a"
+	case 'Z':
+		return "zzz"
+	case 'z':
+		if flag == ':' {
+			return "xxx"
+		}
+		return "xx"
+	case 'L':
+		return "SSS"
+	case 'f':
+		return "SSSSSS"
+	case 'N':
+		return "SSSSSSSSS"
+
+	case '+':
+		return "E MMM d HH:mm:ss zzz yyyy"
+	case 'c':
+		return "E MMM d HH:mm:ss yyyy"
+	case 'v':
+		return "d-MMM-yyyy"
+	case 'F':
+		return "yyyy-MM-dd"
+	case 'D', 'x':
+		return "MM/dd/yy"
+	case 'r':
+		return "hh:mm:ss a"
+	case 'T', 'X':
+		return "HH:mm:ss"
+	case 'R':
+		return "HH:mm"
+
+	case '%':
+		return "%"
+	case 't':
+		return "\t"
+	case 'n':
+		return "\n"
+	}
+}
+
+// http://man.he.net/man3/strftime
+func okModifier(mod, spec byte) bool {
+	if mod == 'E' {
+		return strings.Contains("cCxXyY", string(spec))
+	}
+	if mod == 'O' {
+		return strings.Contains("deHImMSuUVwWy", string(spec))
+	}
+	return false
+}
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"