parser.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. package timefmt
  2. import (
  3. "git.swzry.com/zry/YAGTF/yagtf/tfelem"
  4. "regexp"
  5. "strconv"
  6. "strings"
  7. "time"
  8. )
  9. const parserTokenBufferSize = 128
  10. const regexpTimezoneTag = "^Timezone:([+-][0-9]{4})([A-Z]{3})$"
  11. type TimeElementFactoryFunc func() TimeElement
  12. type NonDisplayTagFunc func(tp *TimePrinter)
  13. type FormatParser struct {
  14. tagList map[string]TimeElementFactoryFunc
  15. ndTagList map[string]NonDisplayTagFunc
  16. tzsReg *regexp.Regexp
  17. }
  18. func NewFormatParser() *FormatParser {
  19. f := &FormatParser{
  20. tagList: make(map[string]TimeElementFactoryFunc),
  21. ndTagList: make(map[string]NonDisplayTagFunc),
  22. }
  23. f.addDefaultElementClasses()
  24. f.tzsReg, _ = regexp.Compile(regexpTimezoneTag)
  25. return f
  26. }
  27. func (this *FormatParser) AddElementClass(tagname string, ff TimeElementFactoryFunc) {
  28. this.tagList[tagname] = ff
  29. }
  30. func (this *FormatParser) AddTagAlias(alias string, tagname string) {
  31. v, ok := this.tagList[tagname]
  32. if ok {
  33. this.tagList[alias] = v
  34. }
  35. }
  36. func (this *FormatParser) AddNonDisplayTag(tagname string, nf NonDisplayTagFunc) {
  37. this.ndTagList[tagname] = nf
  38. }
  39. func (this *FormatParser) ParseFormatString(tp *TimePrinter, fs string) {
  40. if len(fs) < 1 {
  41. return
  42. }
  43. if fs[0] == '!' {
  44. this.parseAdvancedFmt(tp, fs[1:])
  45. } else {
  46. this.parseBasicFmt(tp, fs)
  47. }
  48. }
  49. func (this *FormatParser) parseBasicFmt(tp *TimePrinter, fs string) {
  50. s := fs
  51. s = strings.Replace(s, "!", "<#000>", -1)
  52. s = strings.Replace(s, "yyyy", "<#001>", -1)
  53. s = strings.Replace(s, "yy", "<#002>", -1)
  54. s = strings.Replace(s, "MM", "<#003>", -1)
  55. s = strings.Replace(s, "M3", "<#004>", -1)
  56. s = strings.Replace(s, "M09", "<#005>", -1)
  57. s = strings.Replace(s, "M9", "<#006>", -1)
  58. s = strings.Replace(s, "M", "<#007>", -1)
  59. s = strings.Replace(s, "dd", "<#008>", -1)
  60. s = strings.Replace(s, "d", "<#009>", -1)
  61. s = strings.Replace(s, "HH", "<#010>", -1)
  62. s = strings.Replace(s, "hh", "<#011>", -1)
  63. s = strings.Replace(s, "H", "<#012>", -1)
  64. s = strings.Replace(s, "h", "<#013>", -1)
  65. s = strings.Replace(s, "mm", "<#014>", -1)
  66. s = strings.Replace(s, "ss", "<#015>", -1)
  67. s = strings.Replace(s, "E09", "<#016>", -1)
  68. s = strings.Replace(s, "E9", "<#017>", -1)
  69. s = strings.Replace(s, "E3", "<#018>", -1)
  70. s = strings.Replace(s, "A", "<#019>", -1)
  71. s = strings.Replace(s, "S1", "<#020>", -1)
  72. s = strings.Replace(s, "S2", "<#021>", -1)
  73. s = strings.Replace(s, "S3", "<#022>", -1)
  74. s = strings.Replace(s, "Z", "<#023>", -1)
  75. s = strings.Replace(s, "z", "<#024>", -1)
  76. this.parseAdvancedFmt(tp, s)
  77. }
  78. func (this *FormatParser) parseAdvancedFmt(tp *TimePrinter, fs string) {
  79. if len(fs) > 1 {
  80. if fs[0] == '!' {
  81. this.parseBasicFmt(tp, fs[1:])
  82. return
  83. }
  84. }
  85. stat := false
  86. ba := []byte(fs)
  87. ptbuf := make([]byte, 0, parserTokenBufferSize)
  88. for _, v := range ba {
  89. if stat {
  90. if v == '>' {
  91. this.processTag(tp, string(ptbuf))
  92. ptbuf = make([]byte, 0, parserTokenBufferSize)
  93. stat = false
  94. } else {
  95. ptbuf = append(ptbuf, v)
  96. }
  97. } else {
  98. if v == '<' {
  99. tp.AddPureText(string(ptbuf))
  100. ptbuf = make([]byte, 0, parserTokenBufferSize)
  101. stat = true
  102. } else {
  103. ptbuf = append(ptbuf, v)
  104. }
  105. }
  106. }
  107. }
  108. func (this *FormatParser) processTimezoneTag(tp *TimePrinter, tzs string, tzname string) {
  109. sg := 0
  110. if tzs[0] == '+' {
  111. sg = 1
  112. } else if tzs[0] == '-' {
  113. sg = -1
  114. } else {
  115. return
  116. }
  117. if len(tzs) != 5 {
  118. return
  119. }
  120. hs := tzs[1:3]
  121. ms := tzs[3:5]
  122. hi, err := strconv.Atoi(hs)
  123. if err != nil {
  124. return
  125. }
  126. mi, err := strconv.Atoi(ms)
  127. if err != nil {
  128. return
  129. }
  130. ofs := (hi*3600 + mi*60) * sg
  131. tz := time.FixedZone(tzname, ofs)
  132. tp.UseTimezone(tz)
  133. }
  134. func (this *FormatParser) processTag(tp *TimePrinter, tag string) {
  135. rrs := this.tzsReg.FindStringSubmatch(tag)
  136. if len(rrs) == 3 {
  137. this.processTimezoneTag(tp, rrs[1], rrs[2])
  138. return
  139. }
  140. v1, ok := this.ndTagList[tag]
  141. if ok {
  142. v1(tp)
  143. return
  144. }
  145. v2, ok := this.tagList[tag]
  146. if ok {
  147. tp.AddElement(v2())
  148. } else {
  149. tp.AddPureText("<" + tag + ">")
  150. }
  151. }
  152. func (this *FormatParser) addDefaultElementClasses() {
  153. this.AddNonDisplayTag("UTC", func(tp *TimePrinter) { tp.UseUTC() })
  154. this.AddNonDisplayTag("Local", func(tp *TimePrinter) { tp.UseLocalTimezone() })
  155. this.AddElementClass("year", func() TimeElement { return tfelem.NewYearElement(false) })
  156. this.AddElementClass("shortYear", func() TimeElement { return tfelem.NewYearElement(true) })
  157. this.AddElementClass("month", func() TimeElement { return tfelem.NewNumbericMonthElement(true) })
  158. this.AddElementClass("monthNoFill", func() TimeElement { return tfelem.NewNumbericMonthElement(false) })
  159. this.AddElementClass("monthAbbr", func() TimeElement { return tfelem.NewEnglishMonthElement(true, false) })
  160. this.AddElementClass("monthName", func() TimeElement { return tfelem.NewEnglishMonthElement(false, true) })
  161. this.AddElementClass("monthNameNoFill", func() TimeElement { return tfelem.NewEnglishMonthElement(false, false) })
  162. this.AddElementClass("day", func() TimeElement { return tfelem.NewDayElement(true) })
  163. this.AddElementClass("dayNoFill", func() TimeElement { return tfelem.NewDayElement(false) })
  164. this.AddElementClass("hour24", func() TimeElement { return tfelem.NewHour24hElement(true) })
  165. this.AddElementClass("hour24NoFill", func() TimeElement { return tfelem.NewHour24hElement(false) })
  166. this.AddElementClass("hour12", func() TimeElement { return tfelem.NewHour12hElement(true) })
  167. this.AddElementClass("hour12NoFill", func() TimeElement { return tfelem.NewHour12hElement(false) })
  168. this.AddElementClass("minute", func() TimeElement { return tfelem.NewMinuteElement() })
  169. this.AddElementClass("second", func() TimeElement { return tfelem.NewSecondElement() })
  170. this.AddElementClass("ms", func() TimeElement { return tfelem.NewSecondFloatPartElementWithMilliSec() })
  171. this.AddElementClass("us", func() TimeElement { return tfelem.NewSecondFloatPartElementWithMicroSec() })
  172. this.AddElementClass("ns", func() TimeElement { return tfelem.NewSecondFloatPartElementWithNanoSec() })
  173. this.AddElementClass("weekday", func() TimeElement { return tfelem.NewNumbericWeekDayElement() })
  174. this.AddElementClass("weekdayAbbr", func() TimeElement { return tfelem.NewEnglishWeekDayElement(true, false) })
  175. this.AddElementClass("weekdayName", func() TimeElement { return tfelem.NewEnglishWeekDayElement(false, true) })
  176. this.AddElementClass("weekdayNameNoFill", func() TimeElement { return tfelem.NewEnglishWeekDayElement(false, false) })
  177. this.AddElementClass("ampm", func() TimeElement { return tfelem.NewAMPMElement() })
  178. this.AddElementClass("yearweek", func() TimeElement { return tfelem.NewWeekElement(true) })
  179. this.AddElementClass("yearweekNoFill", func() TimeElement { return tfelem.NewWeekElement(false) })
  180. this.AddElementClass("yearday", func() TimeElement { return tfelem.NewYearDayElement(true) })
  181. this.AddElementClass("yeardayNoFill", func() TimeElement { return tfelem.NewYearDayElement(false) })
  182. this.AddElementClass("timezone", func() TimeElement { return tfelem.NewTimeZoneUTCOffsetElement() })
  183. this.AddElementClass("timezoneAbbr", func() TimeElement { return tfelem.NewTimeZoneAbbrElement() })
  184. this.AddElementClass("timezoneSec", func() TimeElement { return tfelem.NewTimeZoneNumbericOffsetElement(true) })
  185. this.AddElementClass("timezoneSecNoFill", func() TimeElement { return tfelem.NewTimeZoneNumbericOffsetElement(false) })
  186. this.AddElementClass("iso8601date", func() TimeElement { return tfelem.NewISO8601DateElement() })
  187. this.AddElementClass("iso8601time", func() TimeElement { return tfelem.NewISO8601TimeElement() })
  188. this.AddElementClass("iso8601full", func() TimeElement { return tfelem.NewISO8601FullElement() })
  189. this.AddElementClass("common", func() TimeElement { return tfelem.NewCommonDatetimeElement() })
  190. this.AddElementClass("nginx", func() TimeElement { return tfelem.NewNginxDefaultElement() })
  191. this.AddElementClass("!", func() TimeElement { return &tfelem.PureTextElement{PureText: "!"} })
  192. this.AddElementClass("lt", func() TimeElement { return &tfelem.PureTextElement{PureText: "<"} })
  193. this.AddElementClass("gt", func() TimeElement { return &tfelem.PureTextElement{PureText: ">"} })
  194. this.AddElementClass("q", func() TimeElement { return &tfelem.PureTextElement{PureText: `"`} })
  195. this.AddElementClass("sq", func() TimeElement { return &tfelem.PureTextElement{PureText: "'"} })
  196. this.AddElementClass("tab", func() TimeElement { return &tfelem.PureTextElement{PureText: "\t"} })
  197. this.AddElementClass("br", func() TimeElement { return &tfelem.PureTextElement{PureText: "\n"} })
  198. this.AddElementClass("cr", func() TimeElement { return &tfelem.PureTextElement{PureText: "\r"} })
  199. this.AddElementClass("sp", func() TimeElement { return &tfelem.PureTextElement{PureText: "!"} })
  200. this.AddTagAlias("y", "year")
  201. this.AddTagAlias("sy", "shortYear")
  202. this.AddTagAlias("mon", "month")
  203. this.AddTagAlias("monNF", "monthNoFill")
  204. this.AddTagAlias("monA", "monthAbbr")
  205. this.AddTagAlias("monN", "monthName")
  206. this.AddTagAlias("monNNF", "monthNameNoFill")
  207. this.AddTagAlias("d", "day")
  208. this.AddTagAlias("dNF", "dayNoFill")
  209. this.AddTagAlias("h24", "hour24")
  210. this.AddTagAlias("h12", "hour12")
  211. this.AddTagAlias("h24NF", "hour24NoFill")
  212. this.AddTagAlias("h12NF", "hour12NoFill")
  213. this.AddTagAlias("min", "minute")
  214. this.AddTagAlias("s", "second")
  215. this.AddTagAlias("wd", "weekday")
  216. this.AddTagAlias("wdN", "weekdayName")
  217. this.AddTagAlias("wdNNF", "weekdayNameNoFill")
  218. this.AddTagAlias("wdA", "weekdayAbbr")
  219. this.AddTagAlias("yw", "yearweek")
  220. this.AddTagAlias("ywNF", "yearweekNoFill")
  221. this.AddTagAlias("yd", "yearday")
  222. this.AddTagAlias("ydNF", "yeardayNoFill")
  223. this.AddTagAlias("tz", "timezone")
  224. this.AddTagAlias("tzA", "timezoneAbbr")
  225. this.AddTagAlias("tzS", "timezoneSec")
  226. this.AddTagAlias("tzSNF", "timezoneSecNoFill")
  227. this.AddTagAlias("i8d", "iso8601date")
  228. this.AddTagAlias("i8t", "iso8601time")
  229. this.AddTagAlias("i8f", "iso8601full")
  230. this.AddTagAlias("#000", "!")
  231. this.AddTagAlias("#001", "year")
  232. this.AddTagAlias("#002", "shortYear")
  233. this.AddTagAlias("#003", "month")
  234. this.AddTagAlias("#004", "monthAbbr")
  235. this.AddTagAlias("#005", "monthName")
  236. this.AddTagAlias("#006", "monthNameNoFill")
  237. this.AddTagAlias("#007", "monthNoFill")
  238. this.AddTagAlias("#008", "day")
  239. this.AddTagAlias("#009", "dayNoFill")
  240. this.AddTagAlias("#010", "hour24")
  241. this.AddTagAlias("#011", "hour12")
  242. this.AddTagAlias("#012", "hour24NoFill")
  243. this.AddTagAlias("#013", "hour12NoFill")
  244. this.AddTagAlias("#014", "minute")
  245. this.AddTagAlias("#015", "second")
  246. this.AddTagAlias("#016", "weekdayName")
  247. this.AddTagAlias("#017", "weekdayNameNoFill")
  248. this.AddTagAlias("#018", "weekdayAbbr")
  249. this.AddTagAlias("#019", "ampm")
  250. this.AddTagAlias("#020", "ms")
  251. this.AddTagAlias("#021", "us")
  252. this.AddTagAlias("#022", "ns")
  253. this.AddTagAlias("#023", "timezoneAbbr")
  254. this.AddTagAlias("#024", "timezone")
  255. }