improve time parsing for package gtime

This commit is contained in:
John Guo
2021-01-03 23:37:45 +08:00
parent 4991e14dff
commit d9bd3153ea
5 changed files with 97 additions and 26 deletions

View File

@ -45,7 +45,7 @@ const (
// "2018/10/31 - 16:38:46"
// "2018-02-09",
// "2018.02.09",
TIME_REAGEX_PATTERN1 = `(\d{4}[-/\.]\d{2}[-/\.]\d{2})[:\sT-]*(\d{0,2}:{0,1}\d{0,2}:{0,1}\d{0,2}){0,1}\.{0,1}(\d{0,9})([\sZ]{0,1})([\+-]{0,1})([:\d]*)`
timeRegexPattern1 = `(\d{4}[-/\.]\d{2}[-/\.]\d{2})[:\sT-]*(\d{0,2}:{0,1}\d{0,2}:{0,1}\d{0,2}){0,1}\.{0,1}(\d{0,9})([\sZ]{0,1})([\+-]{0,1})([:\d]*)`
// Regular expression2(datetime separator supports '-', '/', '.').
// Eg:
@ -53,14 +53,21 @@ const (
// 01/Nov/2018 11:50:28
// 01.Nov.2018 11:50:28
// 01.Nov.2018:11:50:28
TIME_REAGEX_PATTERN2 = `(\d{1,2}[-/\.][A-Za-z]{3,}[-/\.]\d{4})[:\sT-]*(\d{0,2}:{0,1}\d{0,2}:{0,1}\d{0,2}){0,1}\.{0,1}(\d{0,9})([\sZ]{0,1})([\+-]{0,1})([:\d]*)`
timeRegexPattern2 = `(\d{1,2}[-/\.][A-Za-z]{3,}[-/\.]\d{4})[:\sT-]*(\d{0,2}:{0,1}\d{0,2}:{0,1}\d{0,2}){0,1}\.{0,1}(\d{0,9})([\sZ]{0,1})([\+-]{0,1})([:\d]*)`
// Regular expression3(time).
// Eg:
// 11:50:28
// 11:50:28.897
timeRegexPattern3 = `(\d{2}):(\d{2}):(\d{2})\.{0,1}(\d{0,9})`
)
var (
// It's more high performance using regular expression
// than time.ParseInLocation to parse the datetime string.
timeRegex1, _ = regexp.Compile(TIME_REAGEX_PATTERN1)
timeRegex2, _ = regexp.Compile(TIME_REAGEX_PATTERN2)
timeRegex1, _ = regexp.Compile(timeRegexPattern1)
timeRegex2, _ = regexp.Compile(timeRegexPattern2)
timeRegex3, _ = regexp.Compile(timeRegexPattern3)
// Month words to arabic numerals mapping.
monthMap = map[string]int{
@ -247,15 +254,31 @@ func StrToTime(str string, format ...string) (*Time, error) {
local = time.Local
)
if match = timeRegex1.FindStringSubmatch(str); len(match) > 0 && match[1] != "" {
for k, v := range match {
match[k] = strings.TrimSpace(v)
}
//for k, v := range match {
// match[k] = strings.TrimSpace(v)
//}
year, month, day = parseDateStr(match[1])
} else if match = timeRegex2.FindStringSubmatch(str); len(match) > 0 && match[1] != "" {
for k, v := range match {
match[k] = strings.TrimSpace(v)
}
//for k, v := range match {
// match[k] = strings.TrimSpace(v)
//}
year, month, day = parseDateStr(match[1])
} else if match = timeRegex3.FindStringSubmatch(str); len(match) > 0 && match[1] != "" {
//for k, v := range match {
// match[k] = strings.TrimSpace(v)
//}
s := strings.Replace(match[2], ":", "", -1)
if len(s) < 6 {
s += strings.Repeat("0", 6-len(s))
}
hour, _ = strconv.Atoi(match[1])
min, _ = strconv.Atoi(match[2])
sec, _ = strconv.Atoi(match[3])
nsec, _ = strconv.Atoi(match[4])
for i := 0; i < 9-len(match[4]); i++ {
nsec *= 10
}
return NewFromTime(time.Date(0, time.Month(1), 1, hour, min, sec, nsec, local)), nil
} else {
return nil, errors.New("unsupported time format")
}
@ -387,6 +410,8 @@ func ParseTimeFromContent(content string, format ...string) *Time {
return NewFromStr(strings.Trim(match[0], "./_- \n\r"))
} else if match := timeRegex2.FindStringSubmatch(content); len(match) >= 1 {
return NewFromStr(strings.Trim(match[0], "./_- \n\r"))
} else if match := timeRegex3.FindStringSubmatch(content); len(match) >= 1 {
return NewFromStr(strings.Trim(match[0], "./_- \n\r"))
}
}
return nil

View File

@ -1,4 +1,4 @@
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
@ -36,8 +36,24 @@ func New(param ...interface{}) *Time {
case *Time:
return r
case string:
if len(param) > 1 {
switch t := param[1].(type) {
case string:
return NewFromStrFormat(r, t)
case []byte:
return NewFromStrFormat(r, string(t))
}
}
return NewFromStr(r)
case []byte:
if len(param) > 1 {
switch t := param[1].(type) {
case string:
return NewFromStrFormat(string(r), t)
case []byte:
return NewFromStrFormat(string(r), string(t))
}
}
return NewFromStr(string(r))
case int:
return NewFromTimeStamp(int64(r))

View File

@ -1,4 +1,4 @@
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
@ -8,6 +8,7 @@ package gtime_test
import (
"testing"
"time"
"github.com/gogf/gf/os/gtime"
)
@ -42,6 +43,18 @@ func Benchmark_StrToTime(b *testing.B) {
}
}
func Benchmark_StrToTime_Format(b *testing.B) {
for i := 0; i < b.N; i++ {
gtime.StrToTime("2018-02-09 20:46:17.897", "Y-m-d H:i:su")
}
}
func Benchmark_StrToTime_Layout(b *testing.B) {
for i := 0; i < b.N; i++ {
gtime.StrToTimeLayout("2018-02-09T20:46:17.897Z", time.RFC3339)
}
}
func Benchmark_ParseTimeFromContent(b *testing.B) {
for i := 0; i < b.N; i++ {
gtime.ParseTimeFromContent("2018-02-09T20:46:17.897Z")

View File

@ -1,4 +1,4 @@
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
@ -7,6 +7,7 @@
package gtime_test
import (
"github.com/gogf/gf/frame/g"
"testing"
"time"
@ -86,6 +87,7 @@ func Test_RFC822(t *testing.T) {
func Test_StrToTime(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
// Correct datetime string.
var testDateTimes = []string{
"2006-01-02 15:04:05",
"2006/01/02 15:04:05",
@ -103,13 +105,11 @@ func Test_StrToTime(t *testing.T) {
for _, item := range testDateTimes {
timeTemp, err := gtime.StrToTime(item)
if err != nil {
t.Error("test fail")
}
t.Assert(err, nil)
t.Assert(timeTemp.Time.Format("2006-01-02 15:04:05"), "2006-01-02 15:04:05")
}
//正常日期列表时间00:00:00
// Correct date string,.
var testDates = []string{
"2006.01.02",
"2006.01.02 00:00",
@ -118,13 +118,25 @@ func Test_StrToTime(t *testing.T) {
for _, item := range testDates {
timeTemp, err := gtime.StrToTime(item)
if err != nil {
t.Error("test fail")
}
t.Assert(err, nil)
t.Assert(timeTemp.Time.Format("2006-01-02 15:04:05"), "2006-01-02 00:00:00")
}
//测试格式化formatToStdLayout
// Correct time string.
var testTimes = g.MapStrStr{
"16:12:01": "15:04:05",
"16:12:01.789": "15:04:05.000",
}
for k, v := range testTimes {
time1, err := gtime.StrToTime(k)
t.Assert(err, nil)
time2, err := time.ParseInLocation(v, k, time.Local)
t.Assert(err, nil)
t.Assert(time1.Time, time2)
}
// formatToStdLayout
var testDateFormats = []string{
"Y-m-d H:i:s",
"\\T\\i\\m\\e Y-m-d H:i:s",
@ -149,7 +161,7 @@ func Test_StrToTime(t *testing.T) {
t.Assert(timeTemp.Time.Format("2006-01-02 15:04:05.000"), "2007-01-02 15:04:05.000")
}
//异常日期列表
// 异常日期列表
var testDatesFail = []string{
"2006.01",
"06..02",

View File

@ -1,4 +1,4 @@
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
@ -17,9 +17,14 @@ import (
func Test_Time(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
t1 := "2011-10-10 01:02:03.456"
t.AssertEQ(gconv.GTime(t1), gtime.NewFromStr(t1))
t.AssertEQ(gconv.Time(t1), gtime.NewFromStr(t1).Time)
s := "2011-10-10 01:02:03.456"
t.AssertEQ(gconv.GTime(s), gtime.NewFromStr(s))
t.AssertEQ(gconv.Time(s), gtime.NewFromStr(s).Time)
t.AssertEQ(gconv.Duration(100), 100*time.Nanosecond)
})
gtest.C(t, func(t *gtest.T) {
s := "01:02:03.456"
t.AssertEQ(gconv.GTime(s), gtime.NewFromStr(s))
t.AssertEQ(gconv.Time(s), gtime.NewFromStr(s).Time)
})
}