From 7034e2015ebd6c472364c0ae67779e5a2638f9fe Mon Sep 17 00:00:00 2001 From: John Date: Wed, 29 May 2019 11:25:11 +0800 Subject: [PATCH] add FormatTo/LayoutTo functions for gtime; use custom ExpireFunc to close poool items when pool is close for gpool --- .../{gchan_test.go => gchan_bench_test.go} | 0 g/container/gpool/gpool.go | 23 ++- .../{gpool_test.go => gpool_bench_test.go} | 7 +- g/os/gtime/gtime_format.go | 134 ++++++++++-------- g/os/gtime/gtime_time.go | 22 +-- g/os/gtime/gtime_z_unit_format_test.go | 15 ++ g/os/gtime/gtime_z_unit_time_test.go | 2 +- g/util/gconv/gconv_struct.go | 6 +- geg/container/gpool/gpool_expire.go | 16 +++ geg/other/test.go | 35 ++--- 10 files changed, 151 insertions(+), 109 deletions(-) rename g/container/gchan/{gchan_test.go => gchan_bench_test.go} (100%) rename g/container/gpool/{gpool_test.go => gpool_bench_test.go} (87%) create mode 100644 geg/container/gpool/gpool_expire.go diff --git a/g/container/gchan/gchan_test.go b/g/container/gchan/gchan_bench_test.go similarity index 100% rename from g/container/gchan/gchan_test.go rename to g/container/gchan/gchan_bench_test.go diff --git a/g/container/gpool/gpool.go b/g/container/gpool/gpool.go index 69bbfc6cc..43f0647d7 100644 --- a/g/container/gpool/gpool.go +++ b/g/container/gpool/gpool.go @@ -43,10 +43,11 @@ type ExpireFunc func(interface{}) // New returns a new object pool. // To ensure execution efficiency, the expiration time cannot be modified once it is set. -// Expire: +// +// Expiration logistics: // expire = 0 : not expired; -// expire < 0 : immediate recovery after use; -// expire > 0 : timeout recovery; +// expire < 0 : immediate expired after use; +// expire > 0 : timeout expired; // Note that the expiration time unit is ** milliseconds **. func New(expire int, newFunc NewFunc, expireFunc...ExpireFunc) *Pool { r := &Pool { @@ -103,14 +104,26 @@ func (p *Pool) Size() int { return p.list.Len() } -// Close closes the pool. +// Close closes the pool. If

has ExpireFunc, +// then it automatically closes all items using this function before it's closed. func (p *Pool) Close() { p.closed.Set(true) } -// checkExpire secondly removes expired items from pool. +// checkExpire removes expired items from pool every second. func (p *Pool) checkExpire() { if p.closed.Val() { + // If p has ExpireFunc, + // then it must close all items using this function. + if p.ExpireFunc != nil { + for { + if r := p.list.PopFront(); r != nil { + p.ExpireFunc(r.(*poolItem).value) + } else { + break + } + } + } gtimer.Exit() } for { diff --git a/g/container/gpool/gpool_test.go b/g/container/gpool/gpool_bench_test.go similarity index 87% rename from g/container/gpool/gpool_test.go rename to g/container/gpool/gpool_bench_test.go index d86172519..d2f243479 100644 --- a/g/container/gpool/gpool_test.go +++ b/g/container/gpool/gpool_bench_test.go @@ -6,14 +6,15 @@ // go test *.go -bench=".*" -package gpool +package gpool_test import ( - "testing" + "github.com/gogf/gf/g/container/gpool" + "testing" "sync" ) -var pool = New(99999999, nil) +var pool = gpool.New(99999999, nil) var syncp = sync.Pool{} func BenchmarkGPoolPut(b *testing.B) { diff --git a/g/os/gtime/gtime_format.go b/g/os/gtime/gtime_format.go index f0ef77a16..2df378f1f 100644 --- a/g/os/gtime/gtime_format.go +++ b/g/os/gtime/gtime_format.go @@ -75,56 +75,9 @@ var ( dayOfMonth = []int{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334} ) -// 将自定义的格式转换为标准库时间格式 -func formatToStdLayout(format string) string { - b := bytes.NewBuffer(nil) - for i := 0; i < len(format); { - switch format[i] { - case '\\': - if i < len(format)-1 { - b.WriteByte(format[i+1]) - i += 2 - continue - } else { - return b.String() - } - - default: - if f, ok := formats[format[i]]; ok { - // 有几个转换的符号需要特殊处理 - switch format[i] { - case 'j': b.WriteString("02") - case 'G': b.WriteString("15") - case 'u': - if i > 0 && format[i-1] == '.' { - b.WriteString("000") - } else { - b.WriteString(".000") - } - - default: - b.WriteString(f) - } - } else { - b.WriteByte(format[i]) - } - i++ - } - } - return b.String() -} - -// 将format格式转换为正则表达式规则 -func formatToRegexPattern(format string) string { - s := gregex.Quote(formatToStdLayout(format)) - s, _ = gregex.ReplaceString(`[0-9]`, `[0-9]`, s) - s, _ = gregex.ReplaceString(`[A-Za-z]`, `[A-Za-z]`, s) - return s -} - -// 格式化,使用自定义日期格式 +// 使用自定义日期格式格式化输出日期。 func (t *Time) Format(format string) string { - runes := []rune(format) + runes := []rune(format) buffer := bytes.NewBuffer(nil) for i := 0; i < len(runes); { switch runes[i] { @@ -165,14 +118,21 @@ func (t *Time) Format(format string) string { return buffer.String() } -// 每月天数后面的英文后缀,2 个字符st nd,rd 或者 th -func formatMonthDaySuffixMap(day string) string { - switch day { - case "01": return "st" - case "02": return "nd" - case "03": return "rd" - default: return "th" - } +// 通过自定义格式转换当前日期为新的日期。 +func (t *Time) FormatTo(format string) *Time { + t.Time = NewFromStr(t.Format(format)).Time + return t +} + +// 使用标准库格式格式化输出日期。 +func (t *Time) Layout(layout string) string { + return t.Time.Format(layout) +} + +// 通过标准库格式转换当前日期为新的日期。 +func (t *Time) LayoutTo(layout string) *Time { + t.Time = NewFromStr(t.Layout(layout)).Time + return t } // 返回是否是润年 @@ -221,7 +181,61 @@ func (t *Time) WeeksOfYear() int { return week } -// 格式化使用标准库格式 -func (t *Time) Layout(layout string) string { - return t.Time.Format(layout) +// 将自定义的格式转换为标准库时间格式 +func formatToStdLayout(format string) string { + b := bytes.NewBuffer(nil) + for i := 0; i < len(format); { + switch format[i] { + case '\\': + if i < len(format)-1 { + b.WriteByte(format[i+1]) + i += 2 + continue + } else { + return b.String() + } + + default: + if f, ok := formats[format[i]]; ok { + // 有几个转换的符号需要特殊处理 + switch format[i] { + case 'j': b.WriteString("02") + case 'G': b.WriteString("15") + case 'u': + if i > 0 && format[i-1] == '.' { + b.WriteString("000") + } else { + b.WriteString(".000") + } + + default: + b.WriteString(f) + } + } else { + b.WriteByte(format[i]) + } + i++ + } + } + return b.String() } + +// 将format格式转换为正则表达式规则 +func formatToRegexPattern(format string) string { + s := gregex.Quote(formatToStdLayout(format)) + s, _ = gregex.ReplaceString(`[0-9]`, `[0-9]`, s) + s, _ = gregex.ReplaceString(`[A-Za-z]`, `[A-Za-z]`, s) + return s +} + +// 每月天数后面的英文后缀,2 个字符st nd,rd 或者 th +func formatMonthDaySuffixMap(day string) string { + switch day { + case "01": return "st" + case "02": return "nd" + case "03": return "rd" + default: return "th" + } +} + + diff --git a/g/os/gtime/gtime_time.go b/g/os/gtime/gtime_time.go index 3256945e6..f017472cb 100644 --- a/g/os/gtime/gtime_time.go +++ b/g/os/gtime/gtime_time.go @@ -13,7 +13,7 @@ type Time struct { } // 创建一个空的时间对象,参数可以是标准库时间对象,可选 -func New (t...time.Time) *Time { +func New(t...time.Time) *Time { if len(t) > 0 { return NewFromTime(t[0]) } @@ -30,14 +30,14 @@ func Now() *Time { } // 标准时间对象转换为自定义的时间对象 -func NewFromTime (t time.Time) *Time { +func NewFromTime(t time.Time) *Time { return &Time{ t, } } // 从字符串转换为时间对象,复杂的时间字符串需要给定格式 -func NewFromStr (str string) *Time { +func NewFromStr(str string) *Time { if t, err := StrToTime(str); err == nil { return t } @@ -45,7 +45,7 @@ func NewFromStr (str string) *Time { } // 从字符串转换为时间对象,指定字符串时间格式,format格式形如:Y-m-d H:i:s -func NewFromStrFormat (str string, format string) *Time { +func NewFromStrFormat(str string, format string) *Time { if t, err := StrToTimeFormat(str, format); err == nil { return t } @@ -53,7 +53,7 @@ func NewFromStrFormat (str string, format string) *Time { } // 从字符串转换为时间对象,通过标准库layout格式进行解析,layout格式形如:2006-01-02 15:04:05 -func NewFromStrLayout (str string, layout string) *Time { +func NewFromStrLayout(str string, layout string) *Time { if t, err := StrToTimeLayout(str, layout); err == nil { return t } @@ -61,7 +61,7 @@ func NewFromStrLayout (str string, layout string) *Time { } // 时间戳转换为时间对象,时间戳支持到纳秒的数值 -func NewFromTimeStamp (timestamp int64) *Time { +func NewFromTimeStamp(timestamp int64) *Time { if timestamp == 0 { return &Time {} } @@ -98,7 +98,8 @@ func (t *Time) String() string { return t.Format("Y-m-d H:i:s") } -// 转换为标准库日期对象 +// Deprecated. +// Directly use t.Time instead. func (t *Time) ToTime() time.Time { return t.Time } @@ -121,13 +122,12 @@ func (t *Time) ToLocation(location *time.Location) *Time { } // 时区转换为指定的时区(通过时区名称,如:Asia/Shanghai) -func (t *Time) ToZone(zone string) *Time { +func (t *Time) ToZone(zone string) (*Time, error) { if l, err := time.LoadLocation(zone); err == nil { t.Time = t.Time.In(l) - return t + return t, nil } else { - //panic(err) - return nil + return nil, err } } diff --git a/g/os/gtime/gtime_z_unit_format_test.go b/g/os/gtime/gtime_z_unit_format_test.go index 6a67df146..d4abb1b11 100644 --- a/g/os/gtime/gtime_z_unit_format_test.go +++ b/g/os/gtime/gtime_z_unit_format_test.go @@ -85,9 +85,24 @@ func Test_Format(t *testing.T) { }) } +func Test_FormatTo(t *testing.T) { + gtest.Case(t, func() { + timeTemp := gtime.Now() + gtest.Assert(timeTemp.FormatTo("Y-m-01 00:00:01"), timeTemp.Time.Format("2006-01") + "-01 00:00:01") + }) +} + + func Test_Layout(t *testing.T) { gtest.Case(t, func() { timeTemp := gtime.Now() gtest.Assert(timeTemp.Layout("2006-01-02 15:04:05"), timeTemp.Time.Format("2006-01-02 15:04:05")) }) } + +func Test_LayoutTo(t *testing.T) { + gtest.Case(t, func() { + timeTemp := gtime.Now() + gtest.Assert(timeTemp.LayoutTo("2006-01-02 00:00:00"), timeTemp.Time.Format("2006-01-02 00:00:00")) + }) +} diff --git a/g/os/gtime/gtime_z_unit_time_test.go b/g/os/gtime/gtime_z_unit_time_test.go index 22dbe5e46..f00b2d760 100644 --- a/g/os/gtime/gtime_z_unit_time_test.go +++ b/g/os/gtime/gtime_z_unit_time_test.go @@ -137,7 +137,7 @@ func Test_ToZone(t *testing.T) { timeTemp.ToLocation(loc) gtest.Assert(timeTemp.Time.Location().String(), "Asia/Shanghai") - timeTemp1 := timeTemp.ToZone("errZone") + timeTemp1, _ := timeTemp.ToZone("errZone") if timeTemp1 != nil { t.Error("test fail") } diff --git a/g/util/gconv/gconv_struct.go b/g/util/gconv/gconv_struct.go index 8b1b6a325..e84455496 100644 --- a/g/util/gconv/gconv_struct.go +++ b/g/util/gconv/gconv_struct.go @@ -40,10 +40,8 @@ func Struct(params interface{}, pointer interface{}, mapping...map[string]string } // Using reflect to do the converting, // it also supports type of reflect.Value for (always in internal usage). - elem := reflect.Value{} - if v, ok := pointer.(reflect.Value); ok { - elem = v - } else { + elem, ok := pointer.(reflect.Value) + if !ok { rv := reflect.ValueOf(pointer) if kind := rv.Kind(); kind != reflect.Ptr { return fmt.Errorf("object pointer should be type of: %v", kind) diff --git a/geg/container/gpool/gpool_expire.go b/geg/container/gpool/gpool_expire.go new file mode 100644 index 000000000..1a047a625 --- /dev/null +++ b/geg/container/gpool/gpool_expire.go @@ -0,0 +1,16 @@ +package main + +import ( + "fmt" + "github.com/gogf/gf/g/container/gpool" + "time" +) + +func main() { + p := gpool.New(60000, nil, func(i interface{}) { + fmt.Println("expired") + }) + p.Put(1) + time.Sleep(10000*time.Second) + fmt.Println(p.Get()) +} diff --git a/geg/other/test.go b/geg/other/test.go index 4f5b4d622..0d9688c87 100644 --- a/geg/other/test.go +++ b/geg/other/test.go @@ -1,32 +1,17 @@ package main import ( - "fmt" - "github.com/gogf/gf/g" - "github.com/gogf/gf/g/util/gconv" - "log" - "os" + "github.com/gogf/gf/g/os/glog" + "github.com/gogf/gf/g/os/gtime" ) func main() { - var mylog = log.New(os.Stdout, "[Api] ", log.LstdFlags|log.Lshortfile) - mylog.Println(123) - return - a := []int{1,2,3} - fmt.Println(a[:0]) - return - type Person struct{ - Name string - } - type Staff struct{ - Person - StaffId int - } - staff := &Staff{} - params := g.Map{ - "Name" : "john", - "StaffId" : "10000", - } - gconv.Struct(params, staff) - fmt.Println(staff) + Time := gtime.Now().AddDate(0, -1, 0).Format("Y-m") + glog.Debug(Time) + Time = gtime.Now().AddDate(0, -2, 0).Format("Y-m") + glog.Debug(Time) + Time = gtime.Now().AddDate(0, -3, 0).Format("Y-m") + glog.Debug(Time) + Time = gtime.Now().AddDate(0, -4, 0).Format("Y-m") + glog.Debug(Time) } \ No newline at end of file