zenity/internal/strftime/strftime.go
2022-03-30 19:27:54 +01:00

156 lines
3.1 KiB
Go

package strftime
import (
"bytes"
"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:])
default:
res.WriteString(t.Format(fmt))
}
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 {
if bytes.IndexByte([]byte("MonJan_0123456789"), b) >= 0 {
return errors.New("strftime: unsupported literal: '" + string(b) + "'")
}
res.WriteByte(b)
return nil
}
parser.writeFmt = func(fmt string) error {
switch fmt {
case "000", "000000", "000000000":
res := res.String()
if len := len(res); len <= 0 || res[len-1] != '.' && res[len-1] != ',' {
return errors.New("strftime: unsupported specifier: fractional seconds must follow '.' or ','")
}
}
res.WriteString(fmt)
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
}
parser.writeFmt = func(fmt string) error {
if literal {
literal = false
res.WriteByte(quote)
}
res.WriteString(fmt)
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
}