Browse Source

First Distribution.

zry 4 years ago
parent
commit
78ebdfc565

+ 2 - 0
.idea/.gitignore

@@ -0,0 +1,2 @@
+# Default ignored files
+/workspace.xml

+ 8 - 0
.idea/YAGTF.iml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 82 - 0
.idea/markdown-navigator.xml

@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="MarkdownProjectSettings" wasCopied="false">
+    <PreviewSettings splitEditorLayout="SPLIT" splitEditorPreview="PREVIEW" useGrayscaleRendering="false" zoomFactor="1.0" maxImageWidth="0" showGitHubPageIfSynced="false" allowBrowsingInPreview="false" synchronizePreviewPosition="true" highlightPreviewType="NONE" highlightFadeOut="5" highlightOnTyping="true" synchronizeSourcePosition="true" verticallyAlignSourceAndPreviewSyncPosition="true" showSearchHighlightsInPreview="false" showSelectionInPreview="true" openRemoteLinks="true" replaceUnicodeEmoji="false" lastLayoutSetsDefault="false">
+      <PanelProvider>
+        <provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.panel" providerName="Default - Swing" />
+      </PanelProvider>
+    </PreviewSettings>
+    <ParserSettings gitHubSyntaxChange="false" emojiShortcuts="1" emojiImages="0">
+      <PegdownExtensions>
+        <option name="ABBREVIATIONS" value="false" />
+        <option name="ANCHORLINKS" value="true" />
+        <option name="ASIDE" value="false" />
+        <option name="ATXHEADERSPACE" value="true" />
+        <option name="AUTOLINKS" value="true" />
+        <option name="DEFINITIONS" value="false" />
+        <option name="DEFINITION_BREAK_DOUBLE_BLANK_LINE" value="false" />
+        <option name="FENCED_CODE_BLOCKS" value="true" />
+        <option name="FOOTNOTES" value="false" />
+        <option name="HARDWRAPS" value="false" />
+        <option name="HTML_DEEP_PARSER" value="false" />
+        <option name="INSERTED" value="false" />
+        <option name="QUOTES" value="false" />
+        <option name="RELAXEDHRULES" value="true" />
+        <option name="SMARTS" value="false" />
+        <option name="STRIKETHROUGH" value="true" />
+        <option name="SUBSCRIPT" value="false" />
+        <option name="SUPERSCRIPT" value="false" />
+        <option name="SUPPRESS_HTML_BLOCKS" value="false" />
+        <option name="SUPPRESS_INLINE_HTML" value="false" />
+        <option name="TABLES" value="true" />
+        <option name="TASKLISTITEMS" value="true" />
+        <option name="TOC" value="false" />
+        <option name="WIKILINKS" value="true" />
+      </PegdownExtensions>
+      <ParserOptions>
+        <option name="ADMONITION_EXT" value="false" />
+        <option name="ATTRIBUTES_EXT" value="false" />
+        <option name="COMMONMARK_LISTS" value="true" />
+        <option name="DUMMY" value="false" />
+        <option name="EMOJI_SHORTCUTS" value="true" />
+        <option name="ENUMERATED_REFERENCES_EXT" value="false" />
+        <option name="FLEXMARK_FRONT_MATTER" value="false" />
+        <option name="GFM_LOOSE_BLANK_LINE_AFTER_ITEM_PARA" value="false" />
+        <option name="GFM_TABLE_RENDERING" value="true" />
+        <option name="GITBOOK_URL_ENCODING" value="false" />
+        <option name="GITHUB_LISTS" value="false" />
+        <option name="GITHUB_WIKI_LINKS" value="true" />
+        <option name="GITLAB_EXT" value="false" />
+        <option name="GITLAB_MATH_EXT" value="false" />
+        <option name="GITLAB_MERMAID_EXT" value="false" />
+        <option name="HEADER_ID_NO_DUPED_DASHES" value="false" />
+        <option name="JEKYLL_FRONT_MATTER" value="false" />
+        <option name="MACROS_EXT" value="false" />
+        <option name="NO_TEXT_ATTRIBUTES" value="false" />
+        <option name="PARSE_HTML_ANCHOR_ID" value="false" />
+        <option name="SIM_TOC_BLANK_LINE_SPACER" value="true" />
+      </ParserOptions>
+    </ParserSettings>
+    <HtmlSettings headerTopEnabled="false" headerBottomEnabled="false" bodyTopEnabled="false" bodyBottomEnabled="false" embedUrlContent="false" addPageHeader="true" embedImages="false" embedHttpImages="false" imageUriSerials="false" addDocTypeHtml="true">
+      <GeneratorProvider>
+        <provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.generator" providerName="Default Swing HTML Generator" />
+      </GeneratorProvider>
+      <headerTop />
+      <headerBottom />
+      <bodyTop />
+      <bodyBottom />
+    </HtmlSettings>
+    <CssSettings previewScheme="UI_SCHEME" cssUri="" isCssUriEnabled="false" isCssUriSerial="true" isCssTextEnabled="false" isDynamicPageWidth="true">
+      <StylesheetProvider>
+        <provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.css" providerName="Default Swing Stylesheet" />
+      </StylesheetProvider>
+      <ScriptProviders />
+      <cssText />
+      <cssUriHistory />
+    </CssSettings>
+    <HtmlExportSettings updateOnSave="false" parentDir="" targetDir="" cssDir="" scriptDir="" plainHtml="false" imageDir="" copyLinkedImages="false" imageUniquifyType="0" targetExt="" useTargetExt="false" noCssNoScripts="false" linkToExportedHtml="true" exportOnSettingsChange="true" regenerateOnProjectOpen="false" linkFormatType="HTTP_ABSOLUTE" />
+    <LinkMapSettings>
+      <textMaps />
+    </LinkMapSettings>
+  </component>
+</project>

+ 3 - 0
.idea/markdown-navigator/profiles_settings.xml

@@ -0,0 +1,3 @@
+<component name="MarkdownNavigator.ProfileManager">
+  <settings default="" pdf-export="" />
+</component>

+ 10 - 0
.idea/misc.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="JavaScriptSettings">
+    <option name="languageLevel" value="ES6" />
+  </component>
+  <component name="RustProjectSettings">
+    <option name="explicitPathToStdlib" value="Z:\Public\Rust\Rust\lib\" />
+    <option name="toolchainHomeDirectory" value="$PROJECT_DIR$/../../../../../../Rust/Rust/bin" />
+  </component>
+</project>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/YAGTF.iml" filepath="$PROJECT_DIR$/.idea/YAGTF.iml" />
+    </modules>
+  </component>
+</project>

+ 12 - 4
README.md

@@ -67,6 +67,7 @@ Use `<` and `>` to wrap the name of tag. For escaping `<` and '>', using `<lt>`
 Examples:
 
 `<year>-<month>-<day>` -&gt; `2019-01-02`
+
 `<lt><hour>:<minute>:<second><gt><!>` -&gt; `<16:05:27>!`
 
 #### Non-display Tags
@@ -124,7 +125,9 @@ Examples:
 |&lt;sq&gt;                  | single quote mark                               | '                            |
 |&lt;sp&gt;                  | space                                           |                              |
 |&lt;tab&gt;                 | tab                                             |                              |
-|&lt;br&gt;                  | linebreak (valid in multi-line mode only)       |                              |
+|&lt;br&gt;                  | linebreak '\n' (valid in multi-line mode only)  |                              |
+|&lt;cr&gt;                  | linebreak '\r' (valid in multi-line mode only)  |                              |
+
 
 #### Alias
 
@@ -160,6 +163,7 @@ Examples:
 |&lt;i8d&gt;               | &lt;iso8601date&gt;            |
 |&lt;i8t&gt;               | &lt;iso8601time&gt;            |
 |&lt;i8f&gt;               | &lt;iso8601full&gt;            |
+|&lt;lf&gt;                | &lt;br&gt;                     |
 
 ### Non-display Tag List
 
@@ -171,11 +175,11 @@ Examples:
 
  * Instuction For `<Timezone:>` Tag:
 
-Specified timezone to use follow the colon. Using UTC offset format.
+Specified timezone to use follow the colon. Using UTC offset format with name followed.
 
 Example:
 
-`<Timezone:+0800>` will specified the timezone to CST(+0800) for output.
+`<Timezone:+0800CST>` will specified the timezone to CST(+0800) for output.
 
 ### Using This Package In Go
 
@@ -191,4 +195,8 @@ go get git.swzry.com/zry/YAGTF
 
 
 
-```
+```
+
+## 中文文档
+
+待完善...

+ 24 - 0
tests/test4/main.go

@@ -0,0 +1,24 @@
+package main
+
+import (
+	"fmt"
+	"git.swzry.com/zry/YAGTF/yagtf/timefmt"
+	"time"
+)
+
+func main() {
+	tf := timefmt.NewTimeFormatter("!<y>-<mon>-<d> <h24>:<min>:<s> <tz> <tzA>", false)
+	fmt.Println(tf.Format(time.Now()))
+	tf = timefmt.NewTimeFormatter("!<UTC><y>-<mon>-<d> <h24>:<min>:<s> <tz> <tzA>", false)
+	fmt.Println(tf.Format(time.Now()))
+	tf = timefmt.NewTimeFormatter("!<Timezone:+0900JST><y>-<mon>-<d> <h24>:<min>:<s><br><tz> <tzA>", true)
+	fmt.Println(tf.Format(time.Now()))
+	tf = timefmt.NewTimeFormatter("!<Timezone:+0900JST><y>-<mon>-<d> <h24>:<min>:<s><br><tz> <tzA>", false)
+	fmt.Println(tf.Format(time.Now()))
+	tf = timefmt.NewTimeFormatter("yyyy-MM-dd HH:mm:ss z Z", false)
+	fmt.Println(tf.Format(time.Now()))
+	tf = timefmt.NewTimeFormatter("!yyyy-MM-dd HH:mm:ss z Z", false)
+	fmt.Println(tf.Format(time.Now()))
+	tf = timefmt.NewTimeFormatter("!!yyyy-MM-dd HH:mm:ss z Z", false)
+	fmt.Println(tf.Format(time.Now()))
+}

+ 249 - 14
yagtf/timefmt/parser.go

@@ -1,34 +1,269 @@
 package timefmt
 
-import "strings"
+import (
+	"git.swzry.com/zry/YAGTF/yagtf/tfelem"
+	"regexp"
+	"strconv"
+	"strings"
+	"time"
+)
 
-func ParseFormatString(tp *TimePrinter, fs string) {
+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] == '!' {
-		parseAdvancedFmt(tp, fs)
+		this.parseAdvancedFmt(tp, fs[1:])
 	} else {
-		parseBasicFmt(tp, fs)
+		this.parseBasicFmt(tp, fs)
 	}
 }
 
-func parseBasicFmt(tp *TimePrinter, fs string) {
+func (this *FormatParser) parseBasicFmt(tp *TimePrinter, fs string) {
 	s := fs
-	s := strings.Replace(s, "!", "<!>", -1)
-	s := strings.Replace(s, "yyyy", "2006", -1)
-	s := strings.Replace(s, "yy", "06", -1)
-	s := strings.Replace(s, "MM", "01", -1)
-	s := strings.Replace(s, "M", "1", -1)
-
+	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 parseAdvancedFmt(tp *TimePrinter, fs string) {
+func (this *FormatParser) parseAdvancedFmt(tp *TimePrinter, fs string) {
 	if len(fs) > 1 {
-		if fs[1] == '!' {
-			parseBasicFmt(tp, 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")
 }

+ 16 - 4
yagtf/timefmt/yagtf.go

@@ -1,14 +1,24 @@
 package timefmt
 
 import (
+	"strings"
 	"time"
 )
 
 type TimeFormatter struct {
-	printer *TimePrinter
+	printer   *TimePrinter
+	multiline bool
 }
 
 func (this *TimeFormatter) Format(t time.Time) string {
+	fs := this.printer.PrintTime(t)
+	if this.multiline {
+		return fs
+	} else {
+		fs = strings.Replace(fs, "\r", "", -1)
+		fs = strings.Replace(fs, "\n", "", -1)
+		return fs
+	}
 	return this.printer.PrintTime(t)
 }
 
@@ -24,10 +34,12 @@ func (this *TimeFormatter) ForceUTC() {
 	this.printer.UseUTC()
 }
 
-func NewTimeFormatter(fmtstr string) *TimeFormatter {
+func NewTimeFormatter(fmtstr string, multiline bool) *TimeFormatter {
 	tf := &TimeFormatter{
-		printer: NewTimePrinter(),
+		printer:   NewTimePrinter(),
+		multiline: multiline,
 	}
-	ParseFormatString(tf.printer, fmtstr)
+	parser := NewFormatParser()
+	parser.ParseFormatString(tf.printer, fmtstr)
 	return tf
 }