2022-03-30 10:36:50 -04:00
|
|
|
package strftime
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
func Format(fmt string, t time.Time) string {
|
|
|
|
var res strings.Builder
|
|
|
|
|
|
|
|
var parser parser
|
|
|
|
parser.fmt = fmt
|
|
|
|
parser.goSpecifiers()
|
|
|
|
|
|
|
|
parser.writeLit = res.WriteByte
|
|
|
|
|
|
|
|
parser.writeFmt = func(fmt string) error {
|
|
|
|
switch fmt {
|
|
|
|
case "000", "000000", "000000000":
|
|
|
|
res.WriteString(t.Format("." + fmt)[1:])
|
2022-03-30 14:27:54 -04:00
|
|
|
default:
|
|
|
|
res.WriteString(t.Format(fmt))
|
2022-03-30 10:36:50 -04:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
parser.fallback = func(spec byte, pad bool) error {
|
|
|
|
switch spec {
|
|
|
|
default:
|
|
|
|
return errors.New("strftime: unsupported specifier: %" + string(spec))
|
|
|
|
case 'C':
|
|
|
|
s := t.Format("2006")
|
|
|
|
res.WriteString(s[:len(s)-2])
|
|
|
|
case 'g':
|
|
|
|
y, _ := t.ISOWeek()
|
|
|
|
res.WriteString(time.Date(y, 1, 1, 0, 0, 0, 0, time.UTC).Format("06"))
|
|
|
|
case 'G':
|
|
|
|
y, _ := t.ISOWeek()
|
|
|
|
res.WriteString(time.Date(y, 1, 1, 0, 0, 0, 0, time.UTC).Format("2006"))
|
|
|
|
case 'V':
|
|
|
|
_, w := t.ISOWeek()
|
|
|
|
if w < 10 && pad {
|
|
|
|
res.WriteByte('0')
|
|
|
|
}
|
|
|
|
res.WriteString(strconv.Itoa(w))
|
|
|
|
case 'w':
|
|
|
|
w := int(t.Weekday())
|
|
|
|
res.WriteString(strconv.Itoa(w))
|
|
|
|
case 'u':
|
|
|
|
if w := int(t.Weekday()); w == 0 {
|
|
|
|
res.WriteByte('7')
|
|
|
|
} else {
|
|
|
|
res.WriteString(strconv.Itoa(w))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
parser.parse()
|
|
|
|
return res.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
func Parse(fmt, value string) (time.Time, error) {
|
|
|
|
layout, err := Layout(fmt)
|
|
|
|
if err != nil {
|
|
|
|
return time.Time{}, err
|
|
|
|
}
|
|
|
|
return time.Parse(layout, value)
|
|
|
|
}
|
|
|
|
|
|
|
|
func Layout(fmt string) (string, error) {
|
|
|
|
var res strings.Builder
|
|
|
|
|
|
|
|
var parser parser
|
|
|
|
parser.fmt = fmt
|
|
|
|
parser.goSpecifiers()
|
|
|
|
|
|
|
|
parser.writeLit = func(b byte) error {
|
2022-03-30 21:11:14 -04:00
|
|
|
if '0' <= b && b <= '9' {
|
|
|
|
return errors.New("strftime: unsupported literal digit: '" + string(b) + "'")
|
2022-03-30 10:36:50 -04:00
|
|
|
}
|
|
|
|
res.WriteByte(b)
|
2022-03-30 21:11:14 -04:00
|
|
|
if b == 'M' || b == 'T' || b == 'm' || b == 'n' {
|
|
|
|
cur := res.String()
|
|
|
|
switch {
|
|
|
|
case strings.HasSuffix(cur, "Jan"):
|
|
|
|
return errors.New("strftime: unsupported literal: 'Jan'")
|
|
|
|
case strings.HasSuffix(cur, "Mon"):
|
|
|
|
return errors.New("strftime: unsupported literal: 'Mon'")
|
|
|
|
case strings.HasSuffix(cur, "MST"):
|
|
|
|
return errors.New("strftime: unsupported literal: 'MST'")
|
|
|
|
case strings.HasSuffix(cur, "PM"):
|
|
|
|
return errors.New("strftime: unsupported literal: 'PM'")
|
|
|
|
case strings.HasSuffix(cur, "pm"):
|
|
|
|
return errors.New("strftime: unsupported literal: 'pm'")
|
|
|
|
}
|
|
|
|
}
|
2022-03-30 10:36:50 -04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-03-30 14:27:54 -04:00
|
|
|
parser.writeFmt = func(fmt string) error {
|
|
|
|
switch fmt {
|
|
|
|
case "000", "000000", "000000000":
|
2022-03-30 21:11:14 -04:00
|
|
|
if cur := res.String(); !(strings.HasSuffix(cur, ".") || strings.HasSuffix(cur, ",")) {
|
2022-03-30 14:27:54 -04:00
|
|
|
return errors.New("strftime: unsupported specifier: fractional seconds must follow '.' or ','")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
res.WriteString(fmt)
|
2022-03-30 10:36:50 -04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
parser.fallback = func(spec byte, pad bool) error {
|
|
|
|
return errors.New("strftime: unsupported specifier: %" + string(spec))
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := parser.parse(); err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
parser.writeFmt("")
|
|
|
|
return res.String(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func UTS35(fmt string) (string, error) {
|
|
|
|
var parser parser
|
|
|
|
parser.fmt = fmt
|
|
|
|
parser.uts35Specifiers()
|
|
|
|
|
|
|
|
const quote = '\''
|
|
|
|
var literal bool
|
|
|
|
var res strings.Builder
|
|
|
|
|
|
|
|
parser.writeLit = func(b byte) error {
|
|
|
|
if b == quote {
|
|
|
|
res.WriteByte(quote)
|
|
|
|
res.WriteByte(quote)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if !literal && ('a' <= b && b <= 'z' || 'A' <= b && b <= 'Z') {
|
|
|
|
literal = true
|
|
|
|
res.WriteByte(quote)
|
|
|
|
}
|
|
|
|
res.WriteByte(b)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-03-30 14:27:54 -04:00
|
|
|
parser.writeFmt = func(fmt string) error {
|
2022-03-30 10:36:50 -04:00
|
|
|
if literal {
|
|
|
|
literal = false
|
|
|
|
res.WriteByte(quote)
|
|
|
|
}
|
2022-03-30 14:27:54 -04:00
|
|
|
res.WriteString(fmt)
|
2022-03-30 10:36:50 -04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
parser.fallback = func(spec byte, pad bool) error {
|
|
|
|
return errors.New("strftime: unsupported specifier: %" + string(spec))
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := parser.parse(); err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
parser.writeFmt("")
|
|
|
|
return res.String(), nil
|
|
|
|
}
|