package timefmt import ( "git.swzry.com/zry/YAGTF/yagtf/tfelem" "regexp" "strconv" "strings" "time" ) const parserTokenBufferSize = 128 const regexpTimezoneTag = "^Timezone:([+-][0-9]{4})([A-Z]{3})$" type TimeElementFactoryFunc func() TimeElement type NonDisplayTagFunc func(tp *TimePrinter) type FormatParser struct { tagList map[string]TimeElementFactoryFunc ndTagList map[string]NonDisplayTagFunc tzsReg *regexp.Regexp } func NewFormatParser() *FormatParser { f := &FormatParser{ tagList: make(map[string]TimeElementFactoryFunc), ndTagList: make(map[string]NonDisplayTagFunc), } f.addDefaultElementClasses() f.tzsReg, _ = regexp.Compile(regexpTimezoneTag) return f } func (this *FormatParser) AddElementClass(tagname string, ff TimeElementFactoryFunc) { this.tagList[tagname] = ff } func (this *FormatParser) AddTagAlias(alias string, tagname string) { v, ok := this.tagList[tagname] if ok { this.tagList[alias] = v } } func (this *FormatParser) AddNonDisplayTag(tagname string, nf NonDisplayTagFunc) { this.ndTagList[tagname] = nf } func (this *FormatParser) ParseFormatString(tp *TimePrinter, fs string) { if len(fs) < 1 { return } if fs[0] == '!' { this.parseAdvancedFmt(tp, fs[1:]) } else { this.parseBasicFmt(tp, fs) } } func (this *FormatParser) parseBasicFmt(tp *TimePrinter, fs string) { s := fs s = strings.Replace(s, "!", "<#000>", -1) s = strings.Replace(s, "yyyy", "<#001>", -1) s = strings.Replace(s, "yy", "<#002>", -1) s = strings.Replace(s, "MM", "<#003>", -1) s = strings.Replace(s, "M3", "<#004>", -1) s = strings.Replace(s, "M09", "<#005>", -1) s = strings.Replace(s, "M9", "<#006>", -1) s = strings.Replace(s, "M", "<#007>", -1) s = strings.Replace(s, "dd", "<#008>", -1) s = strings.Replace(s, "d", "<#009>", -1) s = strings.Replace(s, "HH", "<#010>", -1) s = strings.Replace(s, "hh", "<#011>", -1) s = strings.Replace(s, "H", "<#012>", -1) s = strings.Replace(s, "h", "<#013>", -1) s = strings.Replace(s, "mm", "<#014>", -1) s = strings.Replace(s, "ss", "<#015>", -1) s = strings.Replace(s, "E09", "<#016>", -1) s = strings.Replace(s, "E9", "<#017>", -1) s = strings.Replace(s, "E3", "<#018>", -1) s = strings.Replace(s, "A", "<#019>", -1) s = strings.Replace(s, "S1", "<#020>", -1) s = strings.Replace(s, "S2", "<#021>", -1) s = strings.Replace(s, "S3", "<#022>", -1) s = strings.Replace(s, "Z", "<#023>", -1) s = strings.Replace(s, "z", "<#024>", -1) this.parseAdvancedFmt(tp, s) } func (this *FormatParser) parseAdvancedFmt(tp *TimePrinter, fs string) { if len(fs) > 1 { if fs[0] == '!' { this.parseBasicFmt(tp, fs[1:]) return } } stat := false ba := []byte(fs) ptbuf := make([]byte, 0, parserTokenBufferSize) for _, v := range ba { if stat { if v == '>' { this.processTag(tp, string(ptbuf)) ptbuf = make([]byte, 0, parserTokenBufferSize) stat = false } else { ptbuf = append(ptbuf, v) } } else { if v == '<' { tp.AddPureText(string(ptbuf)) ptbuf = make([]byte, 0, parserTokenBufferSize) stat = true } else { ptbuf = append(ptbuf, v) } } } } func (this *FormatParser) processTimezoneTag(tp *TimePrinter, tzs string, tzname string) { sg := 0 if tzs[0] == '+' { sg = 1 } else if tzs[0] == '-' { sg = -1 } else { return } if len(tzs) != 5 { return } hs := tzs[1:3] ms := tzs[3:5] hi, err := strconv.Atoi(hs) if err != nil { return } mi, err := strconv.Atoi(ms) if err != nil { return } ofs := (hi*3600 + mi*60) * sg tz := time.FixedZone(tzname, ofs) tp.UseTimezone(tz) } func (this *FormatParser) processTag(tp *TimePrinter, tag string) { rrs := this.tzsReg.FindStringSubmatch(tag) if len(rrs) == 3 { this.processTimezoneTag(tp, rrs[1], rrs[2]) return } v1, ok := this.ndTagList[tag] if ok { v1(tp) return } v2, ok := this.tagList[tag] if ok { tp.AddElement(v2()) } else { tp.AddPureText("<" + tag + ">") } } func (this *FormatParser) addDefaultElementClasses() { this.AddNonDisplayTag("UTC", func(tp *TimePrinter) { tp.UseUTC() }) this.AddNonDisplayTag("Local", func(tp *TimePrinter) { tp.UseLocalTimezone() }) this.AddElementClass("year", func() TimeElement { return tfelem.NewYearElement(false) }) this.AddElementClass("shortYear", func() TimeElement { return tfelem.NewYearElement(true) }) this.AddElementClass("month", func() TimeElement { return tfelem.NewNumbericMonthElement(true) }) this.AddElementClass("monthNoFill", func() TimeElement { return tfelem.NewNumbericMonthElement(false) }) this.AddElementClass("monthAbbr", func() TimeElement { return tfelem.NewEnglishMonthElement(true, false) }) this.AddElementClass("monthName", func() TimeElement { return tfelem.NewEnglishMonthElement(false, true) }) this.AddElementClass("monthNameNoFill", func() TimeElement { return tfelem.NewEnglishMonthElement(false, false) }) this.AddElementClass("day", func() TimeElement { return tfelem.NewDayElement(true) }) this.AddElementClass("dayNoFill", func() TimeElement { return tfelem.NewDayElement(false) }) this.AddElementClass("hour24", func() TimeElement { return tfelem.NewHour24hElement(true) }) this.AddElementClass("hour24NoFill", func() TimeElement { return tfelem.NewHour24hElement(false) }) this.AddElementClass("hour12", func() TimeElement { return tfelem.NewHour12hElement(true) }) this.AddElementClass("hour12NoFill", func() TimeElement { return tfelem.NewHour12hElement(false) }) this.AddElementClass("minute", func() TimeElement { return tfelem.NewMinuteElement() }) this.AddElementClass("second", func() TimeElement { return tfelem.NewSecondElement() }) this.AddElementClass("ms", func() TimeElement { return tfelem.NewSecondFloatPartElementWithMilliSec() }) this.AddElementClass("us", func() TimeElement { return tfelem.NewSecondFloatPartElementWithMicroSec() }) this.AddElementClass("ns", func() TimeElement { return tfelem.NewSecondFloatPartElementWithNanoSec() }) this.AddElementClass("weekday", func() TimeElement { return tfelem.NewNumbericWeekDayElement() }) this.AddElementClass("weekdayAbbr", func() TimeElement { return tfelem.NewEnglishWeekDayElement(true, false) }) this.AddElementClass("weekdayName", func() TimeElement { return tfelem.NewEnglishWeekDayElement(false, true) }) this.AddElementClass("weekdayNameNoFill", func() TimeElement { return tfelem.NewEnglishWeekDayElement(false, false) }) this.AddElementClass("ampm", func() TimeElement { return tfelem.NewAMPMElement() }) this.AddElementClass("yearweek", func() TimeElement { return tfelem.NewWeekElement(true) }) this.AddElementClass("yearweekNoFill", func() TimeElement { return tfelem.NewWeekElement(false) }) this.AddElementClass("yearday", func() TimeElement { return tfelem.NewYearDayElement(true) }) this.AddElementClass("yeardayNoFill", func() TimeElement { return tfelem.NewYearDayElement(false) }) this.AddElementClass("timezone", func() TimeElement { return tfelem.NewTimeZoneUTCOffsetElement() }) this.AddElementClass("timezoneAbbr", func() TimeElement { return tfelem.NewTimeZoneAbbrElement() }) this.AddElementClass("timezoneSec", func() TimeElement { return tfelem.NewTimeZoneNumbericOffsetElement(true) }) this.AddElementClass("timezoneSecNoFill", func() TimeElement { return tfelem.NewTimeZoneNumbericOffsetElement(false) }) this.AddElementClass("iso8601date", func() TimeElement { return tfelem.NewISO8601DateElement() }) this.AddElementClass("iso8601time", func() TimeElement { return tfelem.NewISO8601TimeElement() }) this.AddElementClass("iso8601full", func() TimeElement { return tfelem.NewISO8601FullElement() }) this.AddElementClass("common", func() TimeElement { return tfelem.NewCommonDatetimeElement() }) this.AddElementClass("nginx", func() TimeElement { return tfelem.NewNginxDefaultElement() }) this.AddElementClass("!", func() TimeElement { return &tfelem.PureTextElement{PureText: "!"} }) this.AddElementClass("lt", func() TimeElement { return &tfelem.PureTextElement{PureText: "<"} }) this.AddElementClass("gt", func() TimeElement { return &tfelem.PureTextElement{PureText: ">"} }) this.AddElementClass("q", func() TimeElement { return &tfelem.PureTextElement{PureText: `"`} }) this.AddElementClass("sq", func() TimeElement { return &tfelem.PureTextElement{PureText: "'"} }) this.AddElementClass("tab", func() TimeElement { return &tfelem.PureTextElement{PureText: "\t"} }) this.AddElementClass("br", func() TimeElement { return &tfelem.PureTextElement{PureText: "\n"} }) this.AddElementClass("cr", func() TimeElement { return &tfelem.PureTextElement{PureText: "\r"} }) this.AddElementClass("sp", func() TimeElement { return &tfelem.PureTextElement{PureText: "!"} }) this.AddTagAlias("y", "year") this.AddTagAlias("sy", "shortYear") this.AddTagAlias("mon", "month") this.AddTagAlias("monNF", "monthNoFill") this.AddTagAlias("monA", "monthAbbr") this.AddTagAlias("monN", "monthName") this.AddTagAlias("monNNF", "monthNameNoFill") this.AddTagAlias("d", "day") this.AddTagAlias("dNF", "dayNoFill") this.AddTagAlias("h24", "hour24") this.AddTagAlias("h12", "hour12") this.AddTagAlias("h24NF", "hour24NoFill") this.AddTagAlias("h12NF", "hour12NoFill") this.AddTagAlias("min", "minute") this.AddTagAlias("s", "second") this.AddTagAlias("wd", "weekday") this.AddTagAlias("wdN", "weekdayName") this.AddTagAlias("wdNNF", "weekdayNameNoFill") this.AddTagAlias("wdA", "weekdayAbbr") this.AddTagAlias("yw", "yearweek") this.AddTagAlias("ywNF", "yearweekNoFill") this.AddTagAlias("yd", "yearday") this.AddTagAlias("ydNF", "yeardayNoFill") this.AddTagAlias("tz", "timezone") this.AddTagAlias("tzA", "timezoneAbbr") this.AddTagAlias("tzS", "timezoneSec") this.AddTagAlias("tzSNF", "timezoneSecNoFill") this.AddTagAlias("i8d", "iso8601date") this.AddTagAlias("i8t", "iso8601time") this.AddTagAlias("i8f", "iso8601full") this.AddTagAlias("#000", "!") this.AddTagAlias("#001", "year") this.AddTagAlias("#002", "shortYear") this.AddTagAlias("#003", "month") this.AddTagAlias("#004", "monthAbbr") this.AddTagAlias("#005", "monthName") this.AddTagAlias("#006", "monthNameNoFill") this.AddTagAlias("#007", "monthNoFill") this.AddTagAlias("#008", "day") this.AddTagAlias("#009", "dayNoFill") this.AddTagAlias("#010", "hour24") this.AddTagAlias("#011", "hour12") this.AddTagAlias("#012", "hour24NoFill") this.AddTagAlias("#013", "hour12NoFill") this.AddTagAlias("#014", "minute") this.AddTagAlias("#015", "second") this.AddTagAlias("#016", "weekdayName") this.AddTagAlias("#017", "weekdayNameNoFill") this.AddTagAlias("#018", "weekdayAbbr") this.AddTagAlias("#019", "ampm") this.AddTagAlias("#020", "ms") this.AddTagAlias("#021", "us") this.AddTagAlias("#022", "ns") this.AddTagAlias("#023", "timezoneAbbr") this.AddTagAlias("#024", "timezone") }