瀏覽代碼

201909051400

zry 4 年之前
父節點
當前提交
e5e3e92c9a

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

+ 191 - 1
README.md

@@ -1,3 +1,193 @@
 # YAGTF
 
-Yet Another Golang Time Formatter
+Yet Another Golang Time Formatter
+
+## English Documentation
+
+### Tradition Mode
+
+Directly using the format string like 'yyyy-MM-dd HH:mm:ss'. It will be translated into advanced mode format string by simply string replacing.
+
+Just for compatibility, not recommend for complex format.
+
+Symbols:
+
+
+Symbol      | Function Description                  | Will Be Replaced To   | Output Example
+:-:         | :-:                                   | :-:                   | :-:
+yyyy        | long year                             | <year>                | 2019
+yy          | short year                            | <shortYear>           | 96
+MM          | month with zero fill                  | <month>               | 02
+M3          | month in English abbr.                | <monthAbbr>           | Jan
+M09         | month in English with zero fill       | <monthName>           | January
+M9          | month in English without zero fill    | <monthNameNoFill>     | January
+M           | month without zero fill               | <monthNoFill>         | 2
+dd          | day with zero fill                    | <day>                 | 05
+d           | day without zero fill                 | <dayNoFill>           | 5
+HH          | 24h hour with zero fill               | <hour24>              | 13
+hh          | 12h hour with zero fill               | <hour12>              | 01
+H           | 24h hour without zero fill            | <hour24NoFill>        | 13
+h           | 12h hour without zero fill            | <hour12NoFill>        | 1
+mm          | minute with zero fill                 | <minute>              | 01
+ss          | second with zero fill                 | <second>              | 05
+E09         | weekday in English with zero fill     | <weekdayName>         | Monday
+E9          | weekday in English without zero fill  | <weekdayNameNoFill>   | Monday
+E3          | weekday in English abbr.              | <weekdayAbbr>         | Mon
+A           | AM/PM                                 | <ampm>                | AM
+S1          | millisecond                           | <ms>                  | 026
+S2          | microsecond                           | <us>                  | 114514
+S3          | nanosecond                            | <ns>                  | 019810019
+Z           | timezone abbr.                        | <timezoneAbbr>        | CST
+z           | timezone UTC offset                   | <timezone>            | +0800
+
+Examples:
+
+`yyyy-MM-dd HH:mm:ss` -> `2000-02-15 19:27:35`
+
+`yy M3 dd E09 hh:mm:ss.S2 A` -> `96 Nov 14 Thursday  01:05:27.114514 PM`
+
+### Advanced Mode
+
+Start your format string with `!`. If you want to use tradition mode, but your formatting string start with `!`, please start with `!!` to instead of `!`.
+
+(The `!` in middle of string will be auto-escaped)
+
+#### Pure Text
+
+Directly type pure text. For escaping `!`, use `<!>`
+
+Examples:
+
+`hello, gensokyo<!>` -> `hello, gensokyo!`
+
+#### Tag
+
+Use `<` and `>` to wrap the name of tag. For escaping `<` and '>', using `<lt>` and `<gt>`
+
+Examples:
+
+`<year>-<month>-<day>` -> `2019-01-02`
+`<lt><hour>:<minute>:<second><gt><!>` -> `<16:05:27>!`
+
+#### Non-display Tags
+
+Some of tags will not be displayed, they just be used for set some options.
+
+Examples:
+
+`<UTC><hour>:<minute>` -> `08:05`
+
+#### Display Tag List
+
+Tag                   | Function Description                            | Output Example
+:-:                   | :-:                                             | :-:
+<year>                | long year                                       | 2019
+<shortYear>           | short year                                      | 96
+<month>               | month with zero fill                            | 02
+<monthNoFill>         | month without zero fill                         | 2
+<monthAbbr>           | month in English abbr.                          | Jan
+<monthName>           | month in English with zero fill                 | January
+<monthNameNoFill>     | month in English without zero fill              | January
+<day>                 | day with zero fill                              | 05
+<dayNoFill>           | day without zero fill                           | 5
+<hour24>              | 24h hour with zero fill                         | 13
+<hour12>              | 12h hour with zero fill                         | 01
+<hour24NoFill>        | 24h hour without zero fill                      | 13
+<hour12NoFill>        | 12h hour without zero fill                      | 1
+<minute>              | minute with zero fill                           | 01
+<second>              | second with zero fill                           | 05
+<weekday>             | weekday in numberic                             | 1
+<weekdayName>         | weekday in English with zero fill               | Monday
+<weekdayNameNoFill>   | weekday in English without zero fill            | Monday
+<weekdayAbbr>         | weekday in English abbr.                        | Mon
+<ampm>                | AM/PM                                           | AM
+<ms>                  | millisecond                                     | 026
+<us>                  | microsecond                                     | 114514
+<ns>                  | nanosecond                                      | 019810019
+<yearweek>            | the week in this year with zero fill            | 06
+<yearweekNoFill>      | the week in this year without zero fill         | 6
+<yearday>             | the day in this year with zero fill             | 034
+<yeardayNoFill>       | the day in this year without zero fill          | 34
+<timezone>            | timezone UTC offset                             | +0800
+<timezoneAbbr>        | timezone abbr.                                  | CST
+<timezoneSec>         | timezone offset in seconds with zero fill       | 03600
+<timezoneSecNoFill>   | timezone offset in seconds without zero fill    | 3600
+<iso8601date>         | ISO8601 date                                    | 2019-01-01
+<iso8601time>         | ISO8601 time                                    | 19:28:31
+<iso8601full>         | ISO8601 full format                             | 2019-01-01T19:28:31+0800
+<common>              | common format                                   | 2019-01-01 19:28:31
+<nginx>               | nginx default time format                       | 01/Jan/2019:19:28:31 +0800
+<!>                   | exclamation mark                                | !
+<lt>                  | less-than mark                                  | <
+<gt>                  | great-than mark                                 | >
+<q>                   | quote mark                                      | "
+<sq>                  | single quote mark                               | '
+<sp>                  | space                                           |
+<tab>                 | tab                                             |
+<br>                  | linebreak (valid in multi-line mode only)       |
+
+#### Alias
+
+Alias               | For Tag
+<y>                 | <year>
+<sy>                | <shortYear>
+<mon>               | <month>
+<monNF>             | <monthNoFill>
+<monA>              | <monthAbbr>
+<monN>              | <monthName>
+<monNNF>            | <monthNameNoFill>
+<d>                 | <day>
+<dNF>               | <dayNoFill>
+<h24>               | <hour24>
+<h12>               | <hour12>
+<h24NF>             | <hour24NoFill>
+<h12NF>             | <hour12NoFill>
+<min>               | <minute>
+<s>                 | <second>
+<wd>                | <weekday>
+<wdN>               | <weekdayName>
+<wdNNF>             | <weekdayNameNoFill>
+<wdA>               | <weekdayAbbr>
+<yw>                | <yearweek>
+<ywNF>              | <yearweekNoFill>
+<yd>                | <yearday>
+<ydNF>              | <yeardayNoFill>
+<tz>                | <timezone>
+<tzA>               | <timezoneAbbr>
+<tzS>               | <timezoneSec>
+<tzSNF>             | <timezoneSecNoFill>
+<i8d>               | <iso8601date>
+<i8t>               | <iso8601time>
+<i8f>               | <iso8601full>
+
+### Non-display Tag List
+
+Tag                   | Function Description
+:-:                   | :-:
+<UTC>                 | use UTC timezone for output
+<Local>               | use local timezone for output
+<Timezone:>           | *use specified timezone for output
+
+* Instuction For `<Timezone:>` Tag:
+
+Specified timezone to use follow the colon. Using UTC offset format.
+
+Example:
+
+`<Timezone:+0800>` will specified the timezone to CST(+0800) for output.
+
+### Using This Package In Go
+
+* Installation *
+
+```
+go get git.swzry.com/zry/YAGTF
+```
+
+* Coding *
+
+```
+
+
+
+```

+ 114 - 0
tests/test1/main.go

@@ -0,0 +1,114 @@
+package main
+
+import (
+	"fmt"
+	"git.swzry.com/zry/YAGTF/yagtf/tfelem"
+	"git.swzry.com/zry/YAGTF/yagtf/timefmt"
+	"time"
+)
+
+func main() {
+	test1()
+	test2()
+}
+
+func test1() {
+	tp := timefmt.NewTimePrinter()
+	tp.AddPureText("hello")
+	tp.AddPureText(",")
+	tp.AddPureText(" ")
+	tp.AddPureText("gensokyo")
+	fmt.Println("Test1", tp.PrintTime(time.Now()))
+}
+
+func test2() {
+	tp := timefmt.NewTimePrinter()
+	tp.AddPureText("\n")
+	tp.AddPureText("short_year=")
+	tp.AddElement(tfelem.NewYearElement(true))
+	tp.AddPureText("\n")
+	tp.AddPureText("long_year=")
+	tp.AddElement(tfelem.NewYearElement(false))
+	tp.AddPureText("\n")
+	tp.AddPureText("number_month_nofill=")
+	tp.AddElement(tfelem.NewNumbericMonthElement(false))
+	tp.AddPureText("\n")
+	tp.AddPureText("number_month_fill=")
+	tp.AddElement(tfelem.NewNumbericMonthElement(true))
+	tp.AddPureText("\n")
+	tp.AddPureText("month_name_nofill=")
+	tp.AddElement(tfelem.NewEnglishMonthElement(false, false))
+	tp.AddPureText("\n")
+	tp.AddPureText("month_name_fill=")
+	tp.AddElement(tfelem.NewEnglishMonthElement(false, true))
+	tp.AddPureText("\n")
+	tp.AddPureText("month_name_abbr=")
+	tp.AddElement(tfelem.NewEnglishMonthElement(true, false))
+	tp.AddPureText("\n")
+	tp.AddPureText("day_nofill=")
+	tp.AddElement(tfelem.NewDayElement(false))
+	tp.AddPureText("\n")
+	tp.AddPureText("day_fill=")
+	tp.AddElement(tfelem.NewDayElement(true))
+	tp.AddPureText("\n")
+	tp.AddPureText("24h_nofill=")
+	tp.AddElement(tfelem.NewHour24hElement(false))
+	tp.AddPureText("\n")
+	tp.AddPureText("24h_fill=")
+	tp.AddElement(tfelem.NewHour24hElement(true))
+	tp.AddPureText("\n")
+	tp.AddPureText("12h_nofill=")
+	tp.AddElement(tfelem.NewHour12hElement(false))
+	tp.AddPureText("\n")
+	tp.AddPureText("12h_fill=")
+	tp.AddElement(tfelem.NewHour12hElement(true))
+	tp.AddPureText("\n")
+	tp.AddPureText("millisecond=")
+	tp.AddElement(tfelem.NewSecondFloatPartElementWithMilliSec())
+	tp.AddPureText("\n")
+	tp.AddPureText("microsecond=")
+	tp.AddElement(tfelem.NewSecondFloatPartElementWithMicroSec())
+	tp.AddPureText("\n")
+	tp.AddPureText("nanosecond=")
+	tp.AddElement(tfelem.NewSecondFloatPartElementWithNanoSec())
+	tp.AddPureText("\n")
+	tp.AddPureText("yearday_nofill=")
+	tp.AddElement(tfelem.NewYearDayElement(false))
+	tp.AddPureText("\n")
+	tp.AddPureText("yearday_fill=")
+	tp.AddElement(tfelem.NewYearDayElement(true))
+	tp.AddPureText("\n")
+	tp.AddPureText("week_nofill=")
+	tp.AddElement(tfelem.NewWeekElement(false))
+	tp.AddPureText("\n")
+	tp.AddPureText("week_fill=")
+	tp.AddElement(tfelem.NewWeekElement(true))
+	tp.AddPureText("\n")
+	tp.AddPureText("weekday_english_nofill=")
+	tp.AddElement(tfelem.NewEnglishWeekDayElement(false, false))
+	tp.AddPureText("\n")
+	tp.AddPureText("weekday_english_fill=")
+	tp.AddElement(tfelem.NewEnglishWeekDayElement(false, true))
+	tp.AddPureText("\n")
+	tp.AddPureText("weekday_english_abbr=")
+	tp.AddElement(tfelem.NewEnglishWeekDayElement(true, false))
+	tp.AddPureText("\n")
+	tp.AddPureText("weekday_numberic=")
+	tp.AddElement(tfelem.NewNumbericWeekDayElement())
+	tp.AddPureText("\n")
+	tp.AddPureText("timezone_abbr=")
+	tp.AddElement(tfelem.NewTimeZoneAbbrElement())
+	tp.AddPureText("\n")
+	tp.AddPureText("timezone_utc_offset=")
+	tp.AddElement(tfelem.NewTimeZoneUTCOffsetElement())
+	tp.AddPureText("\n")
+	tp.AddPureText("timezone_utc_second_nofill=")
+	tp.AddElement(tfelem.NewTimeZoneNumbericOffsetElement(false))
+	tp.AddPureText("\n")
+	tp.AddPureText("timezone_utc_second_fill=")
+	tp.AddElement(tfelem.NewTimeZoneNumbericOffsetElement(true))
+	tp.AddPureText("\n")
+	fmt.Println("Test2-Now", tp.PrintTime(time.Now()))
+	t1, _ := time.Parse(time.RFC3339, "2000-02-15T13:02:59+08:00")
+	fmt.Println("Test2- 2000-02-15 13:02:59 ", tp.PrintTime(t1))
+}

+ 37 - 0
tests/test2/main.go

@@ -0,0 +1,37 @@
+package main
+
+import (
+	"fmt"
+	"time"
+)
+
+func main() {
+	fmt.Println("==== Now ====")
+	ptz(time.Now())
+	fmt.Println("==== 1996-11-14 00:00:00 +0800 ====")
+	t1, _ := time.Parse(time.RFC3339, "1996-11-14T00:00:00+08:00")
+	ptz(t1)
+	fmt.Println("==== 1996-11-14 00:00:00 +0600 ====")
+	t2, _ := time.Parse(time.RFC3339, "1996-11-14T00:00:00+06:00")
+	ptz(t2)
+}
+
+func p(t time.Time) {
+	fmt.Println(t.Year(), t.Month().String(), t.Day(), t.Hour(), t.Minute(), t.Second())
+}
+
+func ptz(t time.Time) {
+	t1 := t
+	t2 := t1.Local()
+	t3 := t1.UTC()
+	l1 := t1.Location()
+	l2 := t2.Location()
+	l3 := t3.Location()
+	fmt.Println("Location", l1, l2, l3)
+	fmt.Println("Raw:")
+	p(t1)
+	fmt.Println("Local:")
+	p(t2)
+	fmt.Println("UTC:")
+	p(t3)
+}

+ 12 - 0
tests/test3/main.go

@@ -0,0 +1,12 @@
+package main
+
+import (
+	"fmt"
+	"time"
+)
+
+func main() {
+	fmt.Println(time.Now().Nanosecond())
+	fmt.Println(time.Now().Format(time.RFC1123Z))
+	fmt.Println(time.Now().UTC().Format(time.RFC1123Z))
+}

+ 25 - 0
yagtf/tfelem/ampm.go

@@ -0,0 +1,25 @@
+package tfelem
+
+import (
+	"time"
+)
+
+type AMPMElement struct {
+}
+
+func (this *AMPMElement) ExpectedSize() int {
+	return 2
+}
+
+func (this AMPMElement) PrintElement(t time.Time) string {
+	h := t.Hour()
+	if h > 12 {
+		return "PM"
+	} else {
+		return "AM"
+	}
+}
+
+func NewAMPMElement() *AMPMElement {
+	return &AMPMElement{}
+}

+ 29 - 0
yagtf/tfelem/day.go

@@ -0,0 +1,29 @@
+package tfelem
+
+import (
+	"git.swzry.com/zry/YAGTF/yagtf/utils"
+	"strconv"
+	"time"
+)
+
+type DayElement struct {
+	Fill bool
+}
+
+func (this *DayElement) ExpectedSize() int {
+	return 2
+}
+
+func (this *DayElement) PrintElement(t time.Time) string {
+	if this.Fill {
+		return utils.GetFilledNumberWithTruncate(t.Day(), 2)
+	} else {
+		return strconv.Itoa(t.Day())
+	}
+}
+
+func NewDayElement(fill bool) *DayElement {
+	return &DayElement{
+		Fill: fill,
+	}
+}

+ 73 - 0
yagtf/tfelem/gofmt.go

@@ -0,0 +1,73 @@
+package tfelem
+
+import (
+	"time"
+)
+
+const (
+	GFL_ISO8601Date    = "2006-01-02"
+	GFL_ISO8601Time    = "15:04:05"
+	GFL_ISO8601Full    = "2006-01-02T15:04:05-0700"
+	GFL_CommonDatetime = "2006-01-02 15:04:05"
+	GFL_NginxDefault   = "02/Jan/2006:15:04:05 -0700"
+)
+
+type GoFormatElement struct {
+	GoFmtLayout string
+}
+
+func (this *GoFormatElement) ExpectedSize() int {
+	return len(this.GoFmtLayout)
+}
+
+func (this *GoFormatElement) PrintElement(t time.Time) string {
+	return t.Format(this.GoFmtLayout)
+}
+
+func NewGoFormatElement(layout string) *GoFormatElement {
+	return &GoFormatElement{
+		GoFmtLayout: layout,
+	}
+}
+
+func NewISO8601DateElement() *GoFormatElement {
+	return &GoFormatElement{
+		GoFmtLayout: GFL_ISO8601Date,
+	}
+}
+
+func NewISO8601TimeElement() *GoFormatElement {
+	return &GoFormatElement{
+		GoFmtLayout: GFL_ISO8601Time,
+	}
+}
+
+func NewISO8601FullElement() *GoFormatElement {
+	return &GoFormatElement{
+		GoFmtLayout: GFL_ISO8601Full,
+	}
+}
+
+func NewCommonDatetimeElement() *GoFormatElement {
+	return &GoFormatElement{
+		GoFmtLayout: GFL_CommonDatetime,
+	}
+}
+
+func NewRFC3339Element() *GoFormatElement {
+	return &GoFormatElement{
+		GoFmtLayout: time.RFC3339,
+	}
+}
+
+func NewRFC3339NanoElement() *GoFormatElement {
+	return &GoFormatElement{
+		GoFmtLayout: time.RFC3339Nano,
+	}
+}
+
+func NewNginxDefaultElement() *GoFormatElement {
+	return &GoFormatElement{
+		GoFmtLayout: GFL_NginxDefault,
+	}
+}

+ 42 - 0
yagtf/tfelem/hour.go

@@ -0,0 +1,42 @@
+package tfelem
+
+import (
+	"git.swzry.com/zry/YAGTF/yagtf/utils"
+	"strconv"
+	"time"
+)
+
+type HourElement struct {
+	Fill         bool
+	Use12hFormat bool
+}
+
+func (this *HourElement) ExpectedSize() int {
+	return 2
+}
+
+func (this *HourElement) PrintElement(t time.Time) string {
+	h := t.Hour()
+	if h > 12 && this.Use12hFormat {
+		h -= 12
+	}
+	if this.Fill {
+		return utils.GetFilledNumberWithTruncate(h, 2)
+	} else {
+		return strconv.Itoa(h)
+	}
+}
+
+func NewHour24hElement(fill bool) *HourElement {
+	return &HourElement{
+		Use12hFormat: false,
+		Fill:         fill,
+	}
+}
+
+func NewHour12hElement(fill bool) *HourElement {
+	return &HourElement{
+		Use12hFormat: true,
+		Fill:         fill,
+	}
+}

+ 21 - 0
yagtf/tfelem/minute.go

@@ -0,0 +1,21 @@
+package tfelem
+
+import (
+	"git.swzry.com/zry/YAGTF/yagtf/utils"
+	"time"
+)
+
+type MinuteElement struct {
+}
+
+func (this *MinuteElement) ExpectedSize() int {
+	return 2
+}
+
+func (this *MinuteElement) PrintElement(t time.Time) string {
+	return utils.GetFilledNumberWithTruncate(t.Minute(), 2)
+}
+
+func NewMinuteElement() *MinuteElement {
+	return &MinuteElement{}
+}

+ 64 - 0
yagtf/tfelem/month.go

@@ -0,0 +1,64 @@
+package tfelem
+
+import (
+	"git.swzry.com/zry/YAGTF/yagtf/utils"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type MonthElement struct {
+	UseMonthName bool
+	Fill         bool
+	UseAbbr      bool
+}
+
+func (this *MonthElement) ExpectedSize() int {
+	if this.UseMonthName {
+		if this.UseAbbr {
+			return 3
+		} else {
+			return 9
+		}
+	} else {
+		return 2
+	}
+}
+
+func (this *MonthElement) PrintElement(t time.Time) string {
+	m := t.Month()
+	if this.UseMonthName {
+		s := m.String()
+		if this.UseAbbr {
+			return s[:3]
+		} else {
+			if this.Fill {
+				return s + strings.Repeat(" ", 9-len(s))
+			} else {
+				return s
+			}
+		}
+	} else {
+		mint := int(m)
+		if this.Fill {
+			return utils.GetFilledNumberWithTruncate(mint, 2)
+		} else {
+			return strconv.Itoa(mint)
+		}
+	}
+}
+
+func NewNumbericMonthElement(fill bool) *MonthElement {
+	return &MonthElement{
+		UseMonthName: false,
+		Fill:         fill,
+	}
+}
+
+func NewEnglishMonthElement(abbrevation bool, fill bool) *MonthElement {
+	return &MonthElement{
+		UseMonthName: true,
+		UseAbbr:      abbrevation,
+		Fill:         fill,
+	}
+}

+ 15 - 0
yagtf/tfelem/puretext.go

@@ -0,0 +1,15 @@
+package tfelem
+
+import "time"
+
+type PureTextElement struct {
+	PureText string
+}
+
+func (this *PureTextElement) ExpectedSize() int {
+	return len(this.PureText)
+}
+
+func (this *PureTextElement) PrintElement(t time.Time) string {
+	return this.PureText
+}

+ 70 - 0
yagtf/tfelem/secfloat.go

@@ -0,0 +1,70 @@
+package tfelem
+
+import (
+	"git.swzry.com/zry/YAGTF/yagtf/utils"
+	"time"
+)
+
+type SecondFloatPartPrecision uint8
+
+const (
+	SFPP_Millisecond SecondFloatPartPrecision = 0
+	SFPP_Microsecond SecondFloatPartPrecision = 1
+	SFPP_Nanosecond  SecondFloatPartPrecision = 2
+)
+
+type SecondFloatPartElement struct {
+	Precision SecondFloatPartPrecision
+}
+
+func (this *SecondFloatPartElement) ExpectedSize() int {
+	switch this.Precision {
+	case SFPP_Millisecond:
+		return 3
+	case SFPP_Microsecond:
+		return 6
+	case SFPP_Nanosecond:
+		return 9
+	default:
+		return 0
+	}
+}
+
+func (this *SecondFloatPartElement) PrintElement(t time.Time) string {
+	l := t.Nanosecond()
+	switch this.Precision {
+	case SFPP_Nanosecond:
+		return utils.GetFilledNumberWithTruncate(l, 9)
+	case SFPP_Microsecond:
+		l = utils.IntDivWithRound(l, 1000)
+		return utils.GetFilledNumberWithTruncate(l, 6)
+	case SFPP_Millisecond:
+		l = utils.IntDivWithRound(l, 1000000)
+		return utils.GetFilledNumberWithTruncate(l, 3)
+	default:
+		return ""
+	}
+}
+
+func NewSecondFloatPartElement(precision SecondFloatPartPrecision) *SecondFloatPartElement {
+	return &SecondFloatPartElement{
+		Precision: precision,
+	}
+}
+
+func NewSecondFloatPartElementWithMilliSec() *SecondFloatPartElement {
+	return &SecondFloatPartElement{
+		Precision: SFPP_Millisecond,
+	}
+}
+func NewSecondFloatPartElementWithMicroSec() *SecondFloatPartElement {
+	return &SecondFloatPartElement{
+		Precision: SFPP_Microsecond,
+	}
+}
+
+func NewSecondFloatPartElementWithNanoSec() *SecondFloatPartElement {
+	return &SecondFloatPartElement{
+		Precision: SFPP_Nanosecond,
+	}
+}

+ 21 - 0
yagtf/tfelem/second.go

@@ -0,0 +1,21 @@
+package tfelem
+
+import (
+	"git.swzry.com/zry/YAGTF/yagtf/utils"
+	"time"
+)
+
+type SecondElement struct {
+}
+
+func (this *SecondElement) ExpectedSize() int {
+	return 2
+}
+
+func (this *SecondElement) PrintElement(t time.Time) string {
+	return utils.GetFilledNumberWithTruncate(t.Second(), 2)
+}
+
+func NewSecondElement() *SecondElement {
+	return &SecondElement{}
+}

+ 30 - 0
yagtf/tfelem/week.go

@@ -0,0 +1,30 @@
+package tfelem
+
+import (
+	"git.swzry.com/zry/YAGTF/yagtf/utils"
+	"strconv"
+	"time"
+)
+
+type WeekElement struct {
+	Fill bool
+}
+
+func (this *WeekElement) ExpectedSize() int {
+	return 2
+}
+
+func (this *WeekElement) PrintElement(t time.Time) string {
+	_, w := t.ISOWeek()
+	if this.Fill {
+		return utils.GetFilledNumberWithTruncate(w, 2)
+	} else {
+		return strconv.Itoa(w)
+	}
+}
+
+func NewWeekElement(fill bool) *WeekElement {
+	return &WeekElement{
+		Fill: fill,
+	}
+}

+ 60 - 0
yagtf/tfelem/weekday.go

@@ -0,0 +1,60 @@
+package tfelem
+
+import (
+	"strconv"
+	"strings"
+	"time"
+)
+
+type WeekDayElement struct {
+	UseEnglishWeekday bool
+	UseAbbr           bool
+	Fill              bool
+}
+
+func (this *WeekDayElement) ExpectedSize() int {
+	if this.UseEnglishWeekday {
+		if this.UseAbbr {
+			return 3
+		} else {
+			return 9
+		}
+	} else {
+		return 1
+	}
+}
+
+func (this *WeekDayElement) PrintElement(t time.Time) string {
+	m := t.Weekday()
+	if this.UseEnglishWeekday {
+		s := m.String()
+		if this.UseAbbr {
+			return s[:3]
+		} else {
+			if this.Fill {
+				return s + strings.Repeat(" ", 9-len(s))
+			} else {
+				return s
+			}
+		}
+	} else {
+		mint := int(m) + 1
+		return strconv.Itoa(mint)
+	}
+}
+
+func NewEnglishWeekDayElement(abbrevation bool, fill bool) *WeekDayElement {
+	return &WeekDayElement{
+		UseEnglishWeekday: true,
+		UseAbbr:           abbrevation,
+		Fill:              fill,
+	}
+}
+
+func NewNumbericWeekDayElement() *WeekDayElement {
+	return &WeekDayElement{
+		UseEnglishWeekday: false,
+		UseAbbr:           false,
+		Fill:              false,
+	}
+}

+ 32 - 0
yagtf/tfelem/year.go

@@ -0,0 +1,32 @@
+package tfelem
+
+import (
+	"git.swzry.com/zry/YAGTF/yagtf/utils"
+	"time"
+)
+
+type YearElement struct {
+	ShortYear bool
+}
+
+func (this *YearElement) ExpectedSize() int {
+	if this.ShortYear {
+		return 2
+	} else {
+		return 4
+	}
+}
+
+func (this *YearElement) PrintElement(t time.Time) string {
+	if this.ShortYear {
+		return utils.GetFilledNumberWithTruncate(t.Year(), 2)
+	} else {
+		return utils.GetFilledNumberWithTruncate(t.Year(), 4)
+	}
+}
+
+func NewYearElement(useShortYear bool) *YearElement {
+	return &YearElement{
+		ShortYear: useShortYear,
+	}
+}

+ 29 - 0
yagtf/tfelem/yearday.go

@@ -0,0 +1,29 @@
+package tfelem
+
+import (
+	"git.swzry.com/zry/YAGTF/yagtf/utils"
+	"strconv"
+	"time"
+)
+
+type YearDayElement struct {
+	Fill bool
+}
+
+func (this *YearDayElement) ExpectedSize() int {
+	return 2
+}
+
+func (this *YearDayElement) PrintElement(t time.Time) string {
+	if this.Fill {
+		return utils.GetFilledNumberWithTruncate(t.YearDay(), 3)
+	} else {
+		return strconv.Itoa(t.YearDay())
+	}
+}
+
+func NewYearDayElement(fill bool) *YearDayElement {
+	return &YearDayElement{
+		Fill: fill,
+	}
+}

+ 78 - 0
yagtf/tfelem/zone.go

@@ -0,0 +1,78 @@
+package tfelem
+
+import (
+	"git.swzry.com/zry/YAGTF/yagtf/utils"
+	"strconv"
+	"time"
+)
+
+type TimeZoneElement struct {
+	UseAbbr      bool
+	UseUTCOffset bool
+	Fill         bool
+}
+
+func (this *TimeZoneElement) ExpectedSize() int {
+	if this.UseAbbr {
+		return 3
+	} else {
+		if this.UseUTCOffset {
+			return 5
+		} else {
+			return 5
+		}
+	}
+}
+
+func (this *TimeZoneElement) PrintElement(t time.Time) string {
+	tzn, tzo := t.Zone()
+	if this.UseAbbr {
+		return tzn
+	} else {
+		if this.UseUTCOffset {
+			zm := utils.IntDivWithRound(tzo, 60)
+			zh := utils.IntDivWithRound(tzo, 3600)
+			if zm < 0 {
+				zm = -zm
+				zh = -zh
+				zhm := zm - zh*60
+				ztxt := zh*100 + zhm
+				return "-" + utils.GetFilledNumberWithTruncate(ztxt, 4)
+			} else {
+				zhm := zm - zh*60
+				ztxt := zh*100 + zhm
+				return "+" + utils.GetFilledNumberWithTruncate(ztxt, 4)
+			}
+		} else {
+			if this.Fill {
+				return utils.GetFilledNumberWithTruncate(tzo, 5)
+			} else {
+				return strconv.Itoa(tzo)
+			}
+		}
+	}
+}
+
+func NewTimeZoneAbbrElement() *TimeZoneElement {
+	return &TimeZoneElement{
+		UseAbbr:      true,
+		UseUTCOffset: false,
+		Fill:         false,
+	}
+}
+
+func NewTimeZoneUTCOffsetElement() *TimeZoneElement {
+	return &TimeZoneElement{
+		UseAbbr:      false,
+		UseUTCOffset: true,
+		Fill:         false,
+	}
+}
+
+func NewTimeZoneNumbericOffsetElement(fill bool) *TimeZoneElement {
+	return &TimeZoneElement{
+		UseAbbr:      false,
+		UseUTCOffset: false,
+		Fill:         fill,
+	}
+}

+ 34 - 0
yagtf/timefmt/parser.go

@@ -0,0 +1,34 @@
+package timefmt
+
+import "strings"
+
+func ParseFormatString(tp *TimePrinter, fs string) {
+	if len(fs) < 1 {
+		return
+	}
+	if fs[0] == '!' {
+		parseAdvancedFmt(tp, fs)
+	} else {
+		parseBasicFmt(tp, fs)
+	}
+}
+
+func 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)
+
+}
+
+func parseAdvancedFmt(tp *TimePrinter, fs string) {
+	if len(fs) > 1 {
+		if fs[1] == '!' {
+			parseBasicFmt(tp, fs[1:])
+			return
+		}
+	}
+
+}

+ 84 - 0
yagtf/timefmt/tprinter.go

@@ -0,0 +1,84 @@
+package timefmt
+
+import (
+	"bytes"
+	"git.swzry.com/zry/YAGTF/yagtf/tfelem"
+	"time"
+)
+
+type TimeElement interface {
+	PrintElement(t time.Time) string
+	ExpectedSize() int
+}
+
+const bufSizeRedunt = 64
+
+type TimePrinter struct {
+	elementList  []TimeElement
+	expectedSize int
+	forceTz      bool
+	forceUTC     bool
+	forceLocal   bool
+	forceTzVal   *time.Location
+}
+
+func (this *TimePrinter) UseArgumentSpecifiedTimezone() {
+	this.forceTz = false
+}
+
+func (this *TimePrinter) UseTimezone(tz *time.Location) {
+	this.forceTz = true
+	this.forceLocal = false
+	this.forceUTC = false
+	this.forceTzVal = tz
+}
+
+func (this *TimePrinter) UseLocalTimezone() {
+	this.forceTz = true
+	this.forceLocal = true
+	this.forceUTC = false
+}
+
+func (this *TimePrinter) UseUTC() {
+	this.forceTz = true
+	this.forceLocal = false
+	this.forceUTC = true
+}
+
+func (this *TimePrinter) AddPureText(text string) {
+	e := &tfelem.PureTextElement{
+		PureText: text,
+	}
+	this.AddElement(e)
+}
+
+func (this *TimePrinter) AddElement(e TimeElement) {
+	this.elementList = append(this.elementList, e)
+	this.expectedSize += e.ExpectedSize()
+}
+
+func (this *TimePrinter) PrintTime(t time.Time) string {
+	bsl := make([]byte, 0, this.expectedSize+bufSizeRedunt)
+	buf := bytes.NewBuffer(bsl)
+	ttz := t
+	if this.forceTz {
+		if this.forceLocal {
+			ttz = t.Local()
+		} else if this.forceUTC {
+			ttz = t.UTC()
+		} else {
+			ttz = t.In(this.forceTzVal)
+		}
+	}
+	for _, v := range this.elementList {
+		buf.WriteString(v.PrintElement(ttz))
+	}
+	return buf.String()
+}
+
+func NewTimePrinter() *TimePrinter {
+	tp := &TimePrinter{}
+	tp.elementList = make([]TimeElement, 0)
+	tp.expectedSize = 0
+	return tp
+}

+ 33 - 0
yagtf/timefmt/yagtf.go

@@ -0,0 +1,33 @@
+package timefmt
+
+import (
+	"time"
+)
+
+type TimeFormatter struct {
+	printer *TimePrinter
+}
+
+func (this *TimeFormatter) Format(t time.Time) string {
+	return this.printer.PrintTime(t)
+}
+
+func (this *TimeFormatter) ForceTimezone(tz *time.Location) {
+	this.printer.UseTimezone(tz)
+}
+
+func (this *TimeFormatter) ForceLocalTimezone() {
+	this.printer.UseLocalTimezone()
+}
+
+func (this *TimeFormatter) ForceUTC() {
+	this.printer.UseUTC()
+}
+
+func NewTimeFormatter(fmtstr string) *TimeFormatter {
+	tf := &TimeFormatter{
+		printer: NewTimePrinter(),
+	}
+	ParseFormatString(tf.printer, fmtstr)
+	return tf
+}

+ 40 - 0
yagtf/utils/number_utils.go

@@ -0,0 +1,40 @@
+package utils
+
+import (
+	"math"
+	"strconv"
+	"strings"
+)
+
+func GetFilledNumber(n int, f int) string {
+	i := strconv.Itoa(n)
+	li := len(i)
+	if li > f {
+		return strings.Repeat("#", f)
+	}
+	if li < f {
+		return strings.Repeat("0", f-li) + i
+	}
+	return i
+}
+
+func GetFilledNumberWithTruncate(n int, f int) string {
+	i := strconv.Itoa(n)
+	li := len(i)
+	if li > f {
+		return i[(li - 2):]
+	}
+	if li < f {
+		return strings.Repeat("0", f-li) + i
+	}
+	return i
+}
+
+func IntDivWithRound(opn int, divn int) int {
+	var t float64
+	var fdivn float64
+	t = float64(opn)
+	fdivn = float64(divn)
+	t /= fdivn
+	return int(math.Round(t))
+}