diff --git a/date/carbon/carbon.go b/date/carbon/carbon.go index f7bb5c8..fc4341f 100644 --- a/date/carbon/carbon.go +++ b/date/carbon/carbon.go @@ -1,9 +1,12 @@ package carbon import ( + "fmt" + "strconv" "time" "github.com/Kretech/xgo/date" + "github.com/pkg/errors" ) // Carbon @@ -12,19 +15,32 @@ type Carbon struct { } // 假定多数情况下,一个进程给一个location就够了 -var defaultLoc = time.Local +var currentLoc = time.Local // 设置全局时区 func In(loc *time.Location) { - defaultLoc = loc + currentLoc = loc + time.Local = loc } func Now() *Carbon { return &Carbon{time.Now()} } +func Today() *Carbon { + return &Carbon{time.Time{}.Truncate(24 * Hour)} +} + +func Yestoday() *Carbon { + return Today().Sub(Day) +} + +func Tomorrow() *Carbon { + return Today().Add(Day) +} + func UnixOf(sec int64, nsec int64) *Carbon { - t := time.Unix(sec, nsec).In(defaultLoc) + t := time.Unix(sec, nsec) return &Carbon{t} } @@ -33,21 +49,29 @@ func TimeOf(t time.Time) *Carbon { } // 解析时间文本 -func StrOf(str string) *Carbon { - return Parse(str) +func strOf(str string) *Carbon { + return parse(str) } // todo // alias to StrOf -func Parse(str string) *Carbon { - t := time.Now().In(defaultLoc) +func parse(str string) *Carbon { + t := time.Now().In(currentLoc) return &Carbon{t} } // wrap of time.Parse but with the carbon layout // 使用 Go time.Time 解析时间文本 -func TParse(layout, value string) *Carbon { - t, _ := time.Parse(date.ToGoFormat(layout), value) +func ParseUTC(layout, value string) *Carbon { + return ParseIn(layout, value, UTC) +} + +func ParseLocal(layout, value string) *Carbon { + return ParseIn(layout, value, time.Local) +} + +func ParseIn(layout, value string, loc *time.Location) *Carbon { + t, _ := time.ParseInLocation(date.ToGoFormat(layout), value, loc) return TimeOf(t) } @@ -75,7 +99,7 @@ func (c Carbon) Add(d time.Duration) *Carbon { } // 减去另一个时间:计算两个时间的差 -func (c *Carbon) SubTime(t time.Time) time.Duration { +func (c *Carbon) Diff(t time.Time) time.Duration { return c.Time().Sub(t) } @@ -88,7 +112,47 @@ func (c Carbon) Sub(d time.Duration) *Carbon { // Format 格式化代码 // c.Format("Y-m-d H:i:s") // @see http://php.net/manual/zh/function.date.php#refsect1-function.date-parameters -func (c *Carbon) Format(format string) string { - format = date.ToGoFormat(format) - return c.t.Format(format) +func (c *Carbon) Format(layout string) string { + layout = date.ToGoFormat(layout) + return c.t.Format(layout) +} + +func (this *Carbon) Unix() int64 { + return this.t.Unix() +} + +func (this *Carbon) UnixNano() int64 { + return this.t.UnixNano() +} + +func (this *Carbon) Truncate(d time.Duration) *Carbon { + return TimeOf(this.t.Truncate(d)) +} + +func (c *Carbon) String() string { + return c.DatetimeString() +} + +func (c *Carbon) DateString() string { + return c.Format("Y-m-d") +} + +func (c *Carbon) DatetimeString() string { + return c.Format("Y-m-d H:i:s") +} + +func (c *Carbon) UnmarshalJSON(b []byte) (err error) { + unix, err := strconv.Atoi(string(b)) + if err != nil { + err = errors.WithMessage(err, `Carbon UnmarshalJSON`) + return + } + + *c = *UnixOf(int64(unix), 0) + + return +} + +func (c *Carbon) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprint(c.Unix())), nil } diff --git a/date/carbon/carbon_test.go b/date/carbon/carbon_test.go index 3e4f1c9..f377728 100644 --- a/date/carbon/carbon_test.go +++ b/date/carbon/carbon_test.go @@ -1,6 +1,9 @@ package carbon import ( + "encoding/json" + "fmt" + "strconv" "testing" "time" @@ -25,8 +28,8 @@ func TestUnixOf(t *testing.T) { } func TestParse(t *testing.T) { - Parse("2012-1-1 01:02:03") - Parse("+1 day") + parse("2012-1-1 01:02:03") + parse("+1 day") } func TestCarbon_Format(t *testing.T) { @@ -49,7 +52,55 @@ func TestCarbon_In(t *testing.T) { } func TestCarbon_Sub(t *testing.T) { - t1 := TParse("Y-m-d H:i:s", "2018-01-02 09:00:00") + t1 := ParseUTC("Y-m-d H:i:s", "2018-01-02 09:00:00") t2 := t1.Sub(time.Hour) test.AssertEqual(t, t2.Format("Y-m-d H:i:s"), "2018-01-02 08:00:00") } + +func TestCarbon_MarshalJSO2N(t *testing.T) { + + t0 := ParseUTC("Y-m-d H:i:s", "1970-01-01 00:00:00") + js, err := json.Marshal(t0) + test.AssertNil(t, err) + + test.AssertEqual(t, string(js), `0`) + + t1 := ParseUTC("Y-m-d H:i:s", "2018-01-02 01:00:00") + js, err = json.Marshal(t1) + test.AssertNil(t, err) + + test.AssertEqual(t, string(js), `1514854800`) +} + +func TestCarbon_MarshalJSON(t *testing.T) { + type args struct { + *time.Location + str string + unixStr string + } + tests := []struct { + name string + args args + }{ + // TODO: Add test cases. + {``, args{UTC, `1970-01-01 00:00:00`, `0`}}, + {``, args{Shanghai, `1970-01-01 08:00:00`, `0`}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := ParseIn(`Y-m-d H:i:s`, tt.args.str, tt.args.Location) + unixBytes, err := c.MarshalJSON() + + test.AssertNil(t, err) + test.AssertEqual(t, string(unixBytes), tt.args.unixStr) + + unix, _ := strconv.Atoi(tt.args.unixStr) + unix += 3600 + unixStr := fmt.Sprint(unix) + var c2 Carbon + err = json.Unmarshal([]byte(unixStr), &c2) + test.AssertNil(t, err) + test.AssertEqual(t, c.Add(time.Hour).String(), c2.String()) + }) + } +} diff --git a/date/carbon/location.go b/date/carbon/location.go index 8f50715..1661bac 100644 --- a/date/carbon/location.go +++ b/date/carbon/location.go @@ -3,5 +3,6 @@ package carbon import "time" var ( + UTC = time.UTC Shanghai, _ = time.LoadLocation("Asia/Shanghai") ) diff --git a/date/carbon/readme.md b/date/carbon/readme.md new file mode 100644 index 0000000..b40eb6d --- /dev/null +++ b/date/carbon/readme.md @@ -0,0 +1,2 @@ +# Carbon + diff --git a/date/date.go b/date/date.go index e81c4b0..d538449 100644 --- a/date/date.go +++ b/date/date.go @@ -12,6 +12,7 @@ func TimeOffset(offset time.Duration) { } // ToGoFormat 把 Y-m-d 转成 Go 格式 +// cache ? func ToGoFormat(format string) string { rule := []string{ `Y`, `2006`, // 年 @@ -80,7 +81,7 @@ func LocalFormat(format string, timestamp ...int64) string { // @see http://php.net/manual/en/function.strtotime.php#example-2803 func StrToTime(expr string) int64 { t := time.Now().Local() - //pattern := `\d+ [(year)|(month)|(day)|(hour)|(minute)|(second)]` + //pattern := `(\d+|[(last)|(next)]) [(year)|(month)|(day)|(hour)|(minute)|(second)|(Monday)]` for i := 1; i < 10; i++ {