diff options
author | Emile <git@emile.space> | 2024-08-16 19:50:26 +0200 |
---|---|---|
committer | Emile <git@emile.space> | 2024-08-16 19:50:26 +0200 |
commit | 1a57267a17c2fc17fb6e104846fabc3e363c326c (patch) | |
tree | 1e574e3a80622086dc3c81ff9cba65ef7049b1a9 /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/.gitignore | 15 | ||||
-rw-r--r-- | vendor/github.com/ncruces/go-strftime/LICENSE | 21 | ||||
-rw-r--r-- | vendor/github.com/ncruces/go-strftime/README.md | 5 | ||||
-rw-r--r-- | vendor/github.com/ncruces/go-strftime/parser.go | 107 | ||||
-rw-r--r-- | vendor/github.com/ncruces/go-strftime/pkg.go | 96 | ||||
-rw-r--r-- | vendor/github.com/ncruces/go-strftime/specifiers.go | 241 | ||||
-rw-r--r-- | vendor/github.com/ncruces/go-strftime/strftime.go | 324 |
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" |