diff options
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 000000000..66fd13c90 --- /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 000000000..7f0f5534c --- /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 000000000..5b0573cf0 --- /dev/null +++ b/vendor/github.com/ncruces/go-strftime/README.md @@ -0,0 +1,5 @@ +# `strftime`/`strptime` compatible time formatting and parsing for Go + +[](https://pkg.go.dev/github.com/ncruces/go-strftime) +[](https://goreportcard.com/report/github.com/ncruces/go-strftime) +[](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 000000000..b006de38a --- /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 000000000..9a3bbd327 --- /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 000000000..065f77963 --- /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 000000000..5308ef772 --- /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" | 
