2019-02-02 16:18:25 +08:00
|
|
|
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
2018-07-11 13:51:03 +08:00
|
|
|
//
|
|
|
|
// 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,
|
2019-02-02 16:18:25 +08:00
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
2018-07-11 13:51:03 +08:00
|
|
|
|
|
|
|
package gtime
|
|
|
|
|
2019-07-13 17:48:16 +08:00
|
|
|
import (
|
2019-09-30 15:26:32 +08:00
|
|
|
"bytes"
|
2020-01-02 21:29:06 +08:00
|
|
|
"strconv"
|
2019-07-13 17:48:16 +08:00
|
|
|
"time"
|
|
|
|
)
|
2018-07-11 13:51:03 +08:00
|
|
|
|
2019-09-30 15:26:32 +08:00
|
|
|
// Time is a wrapper for time.Time for additional features.
|
2018-07-11 13:51:03 +08:00
|
|
|
type Time struct {
|
2020-10-25 11:33:30 +08:00
|
|
|
wrapper
|
2018-07-11 13:51:03 +08:00
|
|
|
}
|
|
|
|
|
2020-09-18 23:59:49 +08:00
|
|
|
// apiUnixNano is an interface definition commonly for custom time.Time wrapper.
|
|
|
|
type apiUnixNano interface {
|
|
|
|
UnixNano() int64
|
|
|
|
}
|
|
|
|
|
2020-08-21 23:41:12 +08:00
|
|
|
// New creates and returns a Time object with given parameter.
|
2020-09-18 23:59:49 +08:00
|
|
|
// The optional parameter can be type of: time.Time/*time.Time, string or integer.
|
2020-08-21 23:41:12 +08:00
|
|
|
func New(param ...interface{}) *Time {
|
|
|
|
if len(param) > 0 {
|
|
|
|
switch r := param[0].(type) {
|
|
|
|
case time.Time:
|
|
|
|
return NewFromTime(r)
|
2020-09-18 23:59:49 +08:00
|
|
|
case *time.Time:
|
|
|
|
return NewFromTime(*r)
|
2020-08-21 23:41:12 +08:00
|
|
|
case string:
|
|
|
|
return NewFromStr(r)
|
|
|
|
case []byte:
|
|
|
|
return NewFromStr(string(r))
|
|
|
|
case int:
|
|
|
|
return NewFromTimeStamp(int64(r))
|
|
|
|
case int64:
|
|
|
|
return NewFromTimeStamp(r)
|
2020-09-18 23:59:49 +08:00
|
|
|
default:
|
|
|
|
if v, ok := r.(apiUnixNano); ok {
|
|
|
|
return NewFromTimeStamp(v.UnixNano())
|
|
|
|
}
|
2020-08-21 23:41:12 +08:00
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
return &Time{
|
2020-10-25 11:33:30 +08:00
|
|
|
wrapper{time.Time{}},
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2018-07-11 13:51:03 +08:00
|
|
|
}
|
|
|
|
|
2020-02-10 20:37:53 +08:00
|
|
|
// Now creates and returns a time object of now.
|
2018-07-11 13:51:03 +08:00
|
|
|
func Now() *Time {
|
2019-06-19 09:06:52 +08:00
|
|
|
return &Time{
|
2020-10-25 11:33:30 +08:00
|
|
|
wrapper{time.Now()},
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2018-07-11 13:51:03 +08:00
|
|
|
}
|
|
|
|
|
2019-09-30 15:26:32 +08:00
|
|
|
// NewFromTime creates and returns a Time object with given time.Time object.
|
2019-05-29 11:25:11 +08:00
|
|
|
func NewFromTime(t time.Time) *Time {
|
2019-06-19 09:06:52 +08:00
|
|
|
return &Time{
|
2020-10-25 11:33:30 +08:00
|
|
|
wrapper{t},
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2018-07-11 13:51:03 +08:00
|
|
|
}
|
|
|
|
|
2019-09-30 15:26:32 +08:00
|
|
|
// NewFromStr creates and returns a Time object with given string.
|
2020-06-22 19:46:39 +08:00
|
|
|
// Note that it returns nil if there's error occurs.
|
2019-05-29 11:25:11 +08:00
|
|
|
func NewFromStr(str string) *Time {
|
2019-06-19 09:06:52 +08:00
|
|
|
if t, err := StrToTime(str); err == nil {
|
|
|
|
return t
|
|
|
|
}
|
|
|
|
return nil
|
2018-07-11 17:06:47 +08:00
|
|
|
}
|
|
|
|
|
2020-02-10 20:37:53 +08:00
|
|
|
// NewFromStrFormat creates and returns a Time object with given string and
|
|
|
|
// custom format like: Y-m-d H:i:s.
|
2020-06-22 19:46:39 +08:00
|
|
|
// Note that it returns nil if there's error occurs.
|
2019-05-29 11:25:11 +08:00
|
|
|
func NewFromStrFormat(str string, format string) *Time {
|
2019-06-19 09:06:52 +08:00
|
|
|
if t, err := StrToTimeFormat(str, format); err == nil {
|
|
|
|
return t
|
|
|
|
}
|
|
|
|
return nil
|
2018-07-11 17:06:47 +08:00
|
|
|
}
|
|
|
|
|
2020-02-10 20:37:53 +08:00
|
|
|
// NewFromStrLayout creates and returns a Time object with given string and
|
|
|
|
// stdlib layout like: 2006-01-02 15:04:05.
|
2020-06-22 19:46:39 +08:00
|
|
|
// Note that it returns nil if there's error occurs.
|
2019-05-29 11:25:11 +08:00
|
|
|
func NewFromStrLayout(str string, layout string) *Time {
|
2019-06-19 09:06:52 +08:00
|
|
|
if t, err := StrToTimeLayout(str, layout); err == nil {
|
|
|
|
return t
|
|
|
|
}
|
|
|
|
return nil
|
2018-07-11 13:51:03 +08:00
|
|
|
}
|
|
|
|
|
2020-02-10 20:37:53 +08:00
|
|
|
// NewFromTimeStamp creates and returns a Time object with given timestamp,
|
|
|
|
// which can be in seconds to nanoseconds.
|
2020-09-18 23:59:49 +08:00
|
|
|
// Eg: 1600443866 and 1600443866199266000 are both considered as valid timestamp number.
|
2019-05-29 11:25:11 +08:00
|
|
|
func NewFromTimeStamp(timestamp int64) *Time {
|
2019-06-19 09:06:52 +08:00
|
|
|
if timestamp == 0 {
|
|
|
|
return &Time{}
|
|
|
|
}
|
2020-02-04 17:09:18 +08:00
|
|
|
var sec, nano int64
|
|
|
|
if timestamp > 1e9 {
|
|
|
|
for timestamp < 1e18 {
|
|
|
|
timestamp *= 10
|
|
|
|
}
|
|
|
|
sec = timestamp / 1e9
|
|
|
|
nano = timestamp % 1e9
|
|
|
|
} else {
|
|
|
|
sec = timestamp
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
return &Time{
|
2020-10-25 11:33:30 +08:00
|
|
|
wrapper{time.Unix(sec, nano)},
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2018-07-11 13:51:03 +08:00
|
|
|
}
|
|
|
|
|
2019-12-17 21:06:34 +08:00
|
|
|
// Timestamp returns the timestamp in seconds.
|
|
|
|
func (t *Time) Timestamp() int64 {
|
2019-06-19 09:06:52 +08:00
|
|
|
return t.UnixNano() / 1e9
|
2018-07-11 13:51:03 +08:00
|
|
|
}
|
|
|
|
|
2019-12-17 21:06:34 +08:00
|
|
|
// TimestampMilli returns the timestamp in milliseconds.
|
|
|
|
func (t *Time) TimestampMilli() int64 {
|
|
|
|
return t.UnixNano() / 1e6
|
2018-07-11 13:51:03 +08:00
|
|
|
}
|
|
|
|
|
2019-12-17 21:06:34 +08:00
|
|
|
// TimestampMicro returns the timestamp in microseconds.
|
|
|
|
func (t *Time) TimestampMicro() int64 {
|
2019-06-19 09:06:52 +08:00
|
|
|
return t.UnixNano() / 1e3
|
2018-07-11 13:51:03 +08:00
|
|
|
}
|
|
|
|
|
2019-12-17 21:06:34 +08:00
|
|
|
// TimestampNano returns the timestamp in nanoseconds.
|
|
|
|
func (t *Time) TimestampNano() int64 {
|
|
|
|
return t.UnixNano()
|
|
|
|
}
|
|
|
|
|
2020-01-02 21:29:06 +08:00
|
|
|
// TimestampStr is a convenience method which retrieves and returns
|
|
|
|
// the timestamp in seconds as string.
|
|
|
|
func (t *Time) TimestampStr() string {
|
|
|
|
return strconv.FormatInt(t.Timestamp(), 10)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TimestampMilliStr is a convenience method which retrieves and returns
|
|
|
|
// the timestamp in milliseconds as string.
|
|
|
|
func (t *Time) TimestampMilliStr() string {
|
|
|
|
return strconv.FormatInt(t.TimestampMilli(), 10)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TimestampMicroStr is a convenience method which retrieves and returns
|
|
|
|
// the timestamp in microseconds as string.
|
|
|
|
func (t *Time) TimestampMicroStr() string {
|
|
|
|
return strconv.FormatInt(t.TimestampMicro(), 10)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TimestampNanoStr is a convenience method which retrieves and returns
|
|
|
|
// the timestamp in nanoseconds as string.
|
|
|
|
func (t *Time) TimestampNanoStr() string {
|
|
|
|
return strconv.FormatInt(t.TimestampNano(), 10)
|
|
|
|
}
|
|
|
|
|
2019-12-17 21:06:34 +08:00
|
|
|
// Second returns the second offset within the minute specified by t,
|
|
|
|
// in the range [0, 59].
|
|
|
|
func (t *Time) Second() int {
|
|
|
|
return t.Time.Second()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Millisecond returns the millisecond offset within the second specified by t,
|
|
|
|
// in the range [0, 999].
|
|
|
|
func (t *Time) Millisecond() int {
|
|
|
|
return t.Time.Nanosecond() / 1e6
|
|
|
|
}
|
|
|
|
|
|
|
|
// Microsecond returns the microsecond offset within the second specified by t,
|
|
|
|
// in the range [0, 999999].
|
|
|
|
func (t *Time) Microsecond() int {
|
|
|
|
return t.Time.Nanosecond() / 1e3
|
|
|
|
}
|
|
|
|
|
|
|
|
// Nanosecond returns the nanosecond offset within the second specified by t,
|
|
|
|
// in the range [0, 999999999].
|
|
|
|
func (t *Time) Nanosecond() int {
|
|
|
|
return t.Time.Nanosecond()
|
2018-07-11 13:51:03 +08:00
|
|
|
}
|
|
|
|
|
2020-03-08 22:53:20 +08:00
|
|
|
// String returns current time object as string.
|
2018-07-11 13:51:03 +08:00
|
|
|
func (t *Time) String() string {
|
2019-10-21 19:13:25 +08:00
|
|
|
if t == nil {
|
|
|
|
return ""
|
|
|
|
}
|
2020-02-16 18:07:05 +08:00
|
|
|
if t.IsZero() {
|
|
|
|
return ""
|
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
return t.Format("Y-m-d H:i:s")
|
2018-07-11 13:51:03 +08:00
|
|
|
}
|
|
|
|
|
2019-09-30 15:26:32 +08:00
|
|
|
// Clone returns a new Time object which is a clone of current time object.
|
2018-07-11 13:51:03 +08:00
|
|
|
func (t *Time) Clone() *Time {
|
2019-06-19 09:06:52 +08:00
|
|
|
return New(t.Time)
|
2018-07-11 13:51:03 +08:00
|
|
|
}
|
|
|
|
|
2019-09-30 15:26:32 +08:00
|
|
|
// Add adds the duration to current time.
|
2018-07-20 18:16:51 +08:00
|
|
|
func (t *Time) Add(d time.Duration) *Time {
|
2020-10-12 23:32:32 +08:00
|
|
|
newTime := t.Clone()
|
|
|
|
newTime.Time = newTime.Time.Add(d)
|
|
|
|
return newTime
|
2018-07-11 13:51:03 +08:00
|
|
|
}
|
|
|
|
|
2019-09-30 15:26:32 +08:00
|
|
|
// AddStr parses the given duration as string and adds it to current time.
|
2020-10-12 23:32:32 +08:00
|
|
|
func (t *Time) AddStr(duration string) (*Time, error) {
|
2019-06-29 18:17:33 +08:00
|
|
|
if d, err := time.ParseDuration(duration); err != nil {
|
2020-10-12 23:32:32 +08:00
|
|
|
return nil, err
|
2019-06-29 18:17:33 +08:00
|
|
|
} else {
|
2020-10-12 23:32:32 +08:00
|
|
|
return t.Add(d), nil
|
2019-06-29 18:17:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-30 15:26:32 +08:00
|
|
|
// ToLocation converts current time to specified location.
|
2018-07-20 18:16:51 +08:00
|
|
|
func (t *Time) ToLocation(location *time.Location) *Time {
|
2020-10-12 23:32:32 +08:00
|
|
|
newTime := t.Clone()
|
|
|
|
newTime.Time = newTime.Time.In(location)
|
|
|
|
return newTime
|
2018-07-11 13:51:03 +08:00
|
|
|
}
|
|
|
|
|
2019-09-30 15:26:32 +08:00
|
|
|
// ToZone converts current time to specified zone like: Asia/Shanghai.
|
2019-05-29 11:25:11 +08:00
|
|
|
func (t *Time) ToZone(zone string) (*Time, error) {
|
2019-06-19 09:06:52 +08:00
|
|
|
if l, err := time.LoadLocation(zone); err == nil {
|
2020-10-12 23:32:32 +08:00
|
|
|
return t.ToLocation(l), nil
|
2019-06-19 09:06:52 +08:00
|
|
|
} else {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-10-16 15:49:30 +08:00
|
|
|
}
|
|
|
|
|
2019-09-30 15:26:32 +08:00
|
|
|
// UTC converts current time to UTC timezone.
|
2018-07-20 18:16:51 +08:00
|
|
|
func (t *Time) UTC() *Time {
|
2020-10-12 23:32:32 +08:00
|
|
|
newTime := t.Clone()
|
|
|
|
newTime.Time = newTime.Time.UTC()
|
|
|
|
return newTime
|
2018-07-11 13:51:03 +08:00
|
|
|
}
|
|
|
|
|
2019-09-30 15:26:32 +08:00
|
|
|
// ISO8601 formats the time as ISO8601 and returns it as string.
|
2019-07-25 23:25:30 +08:00
|
|
|
func (t *Time) ISO8601() string {
|
|
|
|
return t.Layout("2006-01-02T15:04:05-07:00")
|
|
|
|
}
|
|
|
|
|
2019-09-30 15:26:32 +08:00
|
|
|
// RFC822 formats the time as RFC822 and returns it as string.
|
2019-07-25 23:25:30 +08:00
|
|
|
func (t *Time) RFC822() string {
|
|
|
|
return t.Layout("Mon, 02 Jan 06 15:04 MST")
|
|
|
|
}
|
|
|
|
|
2019-09-30 15:26:32 +08:00
|
|
|
// Local converts the time to local timezone.
|
2018-07-20 18:16:51 +08:00
|
|
|
func (t *Time) Local() *Time {
|
2020-10-12 23:32:32 +08:00
|
|
|
newTime := t.Clone()
|
|
|
|
newTime.Time = newTime.Time.Local()
|
|
|
|
return newTime
|
2018-07-11 13:51:03 +08:00
|
|
|
}
|
|
|
|
|
2019-09-30 15:26:32 +08:00
|
|
|
// AddDate adds year, month and day to the time.
|
2018-07-20 18:16:51 +08:00
|
|
|
func (t *Time) AddDate(years int, months int, days int) *Time {
|
2020-10-12 23:32:32 +08:00
|
|
|
newTime := t.Clone()
|
|
|
|
newTime.Time = newTime.Time.AddDate(years, months, days)
|
|
|
|
return newTime
|
2018-07-11 13:51:03 +08:00
|
|
|
}
|
|
|
|
|
2019-09-30 15:26:32 +08:00
|
|
|
// Round returns the result of rounding t to the nearest multiple of d (since the zero time).
|
|
|
|
// The rounding behavior for halfway values is to round up.
|
|
|
|
// If d <= 0, Round returns t stripped of any monotonic clock reading but otherwise unchanged.
|
|
|
|
//
|
|
|
|
// Round operates on the time as an absolute duration since the
|
|
|
|
// zero time; it does not operate on the presentation form of the
|
|
|
|
// time. Thus, Round(Hour) may return a time with a non-zero
|
|
|
|
// minute, depending on the time's Location.
|
2018-07-20 18:16:51 +08:00
|
|
|
func (t *Time) Round(d time.Duration) *Time {
|
2020-10-12 23:32:32 +08:00
|
|
|
newTime := t.Clone()
|
|
|
|
newTime.Time = newTime.Time.Round(d)
|
|
|
|
return newTime
|
2018-07-11 13:51:03 +08:00
|
|
|
}
|
|
|
|
|
2019-09-30 15:26:32 +08:00
|
|
|
// Truncate returns the result of rounding t down to a multiple of d (since the zero time).
|
|
|
|
// If d <= 0, Truncate returns t stripped of any monotonic clock reading but otherwise unchanged.
|
|
|
|
//
|
|
|
|
// Truncate operates on the time as an absolute duration since the
|
|
|
|
// zero time; it does not operate on the presentation form of the
|
|
|
|
// time. Thus, Truncate(Hour) may return a time with a non-zero
|
|
|
|
// minute, depending on the time's Location.
|
2018-07-20 18:16:51 +08:00
|
|
|
func (t *Time) Truncate(d time.Duration) *Time {
|
2020-10-12 23:32:32 +08:00
|
|
|
newTime := t.Clone()
|
|
|
|
newTime.Time = newTime.Time.Truncate(d)
|
|
|
|
return newTime
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2019-07-13 17:48:16 +08:00
|
|
|
|
2019-12-17 21:06:34 +08:00
|
|
|
// Equal reports whether t and u represent the same time instant.
|
|
|
|
// Two times can be equal even if they are in different locations.
|
|
|
|
// For example, 6:00 +0200 CEST and 4:00 UTC are Equal.
|
|
|
|
// See the documentation on the Time type for the pitfalls of using == with
|
|
|
|
// Time values; most code should use Equal instead.
|
|
|
|
func (t *Time) Equal(u *Time) bool {
|
|
|
|
return t.Time.Equal(u.Time)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Before reports whether the time instant t is before u.
|
|
|
|
func (t *Time) Before(u *Time) bool {
|
|
|
|
return t.Time.Before(u.Time)
|
|
|
|
}
|
|
|
|
|
|
|
|
// After reports whether the time instant t is after u.
|
|
|
|
func (t *Time) After(u *Time) bool {
|
|
|
|
return t.Time.After(u.Time)
|
|
|
|
}
|
|
|
|
|
2019-12-14 17:01:27 +08:00
|
|
|
// Sub returns the duration t-u. If the result exceeds the maximum (or minimum)
|
|
|
|
// value that can be stored in a Duration, the maximum (or minimum) duration
|
|
|
|
// will be returned.
|
|
|
|
// To compute t-d for a duration d, use t.Add(-d).
|
|
|
|
func (t *Time) Sub(u *Time) time.Duration {
|
|
|
|
return t.Time.Sub(u.Time)
|
|
|
|
}
|
|
|
|
|
2019-07-13 17:48:16 +08:00
|
|
|
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
|
|
|
func (t *Time) MarshalJSON() ([]byte, error) {
|
2019-09-30 15:51:15 +08:00
|
|
|
return []byte(`"` + t.String() + `"`), nil
|
2019-09-30 15:26:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
|
|
|
func (t *Time) UnmarshalJSON(b []byte) error {
|
2019-10-21 19:13:25 +08:00
|
|
|
if len(b) == 0 {
|
|
|
|
t.Time = time.Time{}
|
|
|
|
return nil
|
|
|
|
}
|
2019-09-30 15:51:15 +08:00
|
|
|
newTime, err := StrToTime(string(bytes.Trim(b, `"`)))
|
2019-09-30 15:26:32 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
t.Time = newTime.Time
|
|
|
|
return nil
|
2019-07-13 17:48:16 +08:00
|
|
|
}
|