utc

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 27, 2024 License: MIT Imports: 7 Imported by: 13

README

UTC - A time.Time Wrapper for ISO8601 / RFC3339

CodeQL

The package utc consists of a single struct UTC that is a small wrapper around the standard lib's time.Time. It provides the following main functions:

  • times in the UTC timezone (Coordinated Universal Time)
  • consistent formatting and parsing of the ISO8601 / RFC3339 format '2006-01-02T15:04:05.000Z' with fixed milliseconds
  • performance-optimized string formatting, binary marshal/unmarshal
  • mocking of "Now()" for tests

Usage

Use just like time.Time:

import (
	"fmt"
	"time"

	"github.com/eluv-io/utc-go"
)

func ExampleUTC() {
	// standard lib time.Time
	location, _ := time.LoadLocation("Indian/Mayotte")
	d0std := time.Date(2000, 1, 1, 0, 0, 0, 0, location)
	fmt.Println("d0 std ", d0std)

	// utc.UTC
	d0 := utc.New(d0std)
	fmt.Println("d0     ", d0.String())

	// utc.UTC.Time is the underlying time.Time (in UTC timezone)
	fmt.Println("d0.Time", d0.Time)

	// ISO8601 / RFC3339
	d1 := utc.MustParse("2021-12-25T12:20:00.000Z")
	fmt.Println("d1     ", d1)

	// All methods of time.Time are available on utc.UTC
	fmt.Println("d1-d0  ", d1.Sub(d0))

	// JSON and text marshalling produce & parse ISO8601 / RFC3339
	jsn, _ := d1.MarshalText()
	fmt.Println("d1     ", string(jsn), "MarshalText()")

	// Output:
	//
	// d0 std  2000-01-01 00:00:00 +0300 EAT
	// d0      1999-12-31T21:00:00.000Z
	// d0.Time 1999-12-31 21:00:00 +0000 UTC
	// d1      2021-12-25T12:20:00.000Z
	// d1-d0   192711h20m0s
	// d1      2021-12-25T12:20:00.000Z MarshalText()
}

Mocking Now():

import (
	"fmt"
	"time"
	
	"github.com/eluv-io/utc-go"
)

func ExampleMockNowFn() {
	d0 := utc.MustParse("2020-01-01T00:00:00.000Z")
	now := d0.Add(38*time.Hour + 30*time.Minute)

	// replace Now() with a custom function that provides the mocked time
	reset := utc.MockNowFn(func() utc.UTC {
	return now
	})
	defer reset()

	fmt.Println("now   ", utc.Now(), "mocked")
	time.Sleep(1 * time.Second)
	fmt.Println("now   ", utc.Now(), "one real second later: still the same")
	fmt.Println("now-d0", utc.Now().Sub(d0))

	now = now.Add(time.Second)
	fmt.Println("now   ", utc.Now(), "one mocked second later")
    
	// Output:
	//
	// now    2020-01-02T14:30:00.000Z mocked
	// now    2020-01-02T14:30:00.000Z one real second later: still the same
	// now-d0 38h30m0s
	// now    2020-01-02T14:30:01.000Z one mocked second later
}

Documentation

Index

Examples

Constants

View Source
const (
	ISO8601             = "2006-01-02T15:04:05.000Z07:00"
	ISO8601DateOnlyNoTZ = "2006-01-02"
	ISO8601DateOnly     = "2006-01-02Z07:00"
	ISO8601NoMilli      = "2006-01-02T15:04:05Z07:00"
	ISO8601NoSec        = "2006-01-02T15:04Z07:00"
	ISO8601NoMilliNoTZ  = "2006-01-02T15:04:05"
	ISO8601NoSecNoTZ    = "2006-01-02T15:04"
)

Variables

View Source
var (
	Zero = UTC{}                                                           // 0001-01-01T00:00:00.000000000 the zero value of UTC
	Min  = New(time.Date(0, 1, 1, 0, 0, 0, 0, time.UTC))                   // 0000-01-01T00:00:00.000000000 (Zero - 1 year!)
	Max  = New(time.Date(9999, 12, 31, 23, 59, 59, 999_999_999, time.UTC)) // 9999-12-31T23:59:59.999999999

)

Functions

func MockNow

func MockNow(time UTC) (restore func())

MockNow allows to replace the Now func variable with a function that returns the given constant time and returns itself a function to restore the default Now() implementation.

Usage: defer MockNow(utc.MustParse("2020-01-01"))() or reset := MockNow(utc.MustParse("2020-01-01")) defer reset()

Example
d0 := utc.MustParse("2020-01-01T00:00:00.000Z")

reset := utc.MockNow(d0)
defer reset()

fmt.Println(utc.Now())
Output:


2020-01-01T00:00:00.000Z

func MockNowClock added in v1.0.1

func MockNowClock(clock TestClock)

MockNowClock mocks now with a test clock. Equivalent to calling clock.MockNow().

func MockNowFn

func MockNowFn(fn func() UTC) (restore func())

MockNowFn allows to replace the Now func variable with a mock function and returns a function to restore the default Now() implementation.

Usage: defer MockNow(func() UTC { ... })() or reset := MockNow(func() UTC { ... }) defer reset()

Using MockNowFn like below and updating the local variable from multiple go routines is racy, hence the function is marked as deprecated.

now := utc.Now()
reset := utc.MockNowFn(func() utc.UTC { return now })
...
now = now.Add(time.Duration(i+1)*time.Second))

Deprecated use one of the NewXXClock().MockNow()

Example
d0 := utc.MustParse("2020-01-01T00:00:00.000Z")
now := d0.Add(38*time.Hour + 30*time.Minute)

// replace Now() with a custom function that provides the mocked time
reset := utc.MockNowFn(func() utc.UTC {
	return now
})
defer reset()

fmt.Println("now   ", utc.Now(), "mocked")
time.Sleep(1 * time.Second)
fmt.Println("now   ", utc.Now(), "one real second later: still the same")
fmt.Println("now-d0", utc.Now().Sub(d0))

now = now.Add(time.Second)
fmt.Println("now   ", utc.Now(), "one mocked second later")
Output:


now    2020-01-02T14:30:00.000Z mocked
now    2020-01-02T14:30:00.000Z one real second later: still the same
now-d0 38h30m0s
now    2020-01-02T14:30:01.000Z one mocked second later

func ResetNow

func ResetNow()

ResetNow resets the Now func to the default implementation.

func Since

func Since(t UTC) time.Duration

Since returns Now().Sub(t)

func Until

func Until(t UTC) time.Duration

Until returns t.Sub(Now())

Types

type Clock added in v1.0.1

type Clock interface {
	Now() UTC
}

type ClockFn added in v1.0.1

type ClockFn func() UTC

ClockFn is a function implementing Clock

func (ClockFn) Now added in v1.0.1

func (fn ClockFn) Now() UTC

type TestClock added in v1.0.1

type TestClock struct {
	// contains filtered or unexported fields
}

TestClock is a Clock that can be set to a given UTC value or reset. Function Now: - returns the previously set UTC or - returns the wall clock if no value or Zero was set A TestClock becomes effectively used as 'the global clock' after calling its function MockNow(). When the clock is effective, func IsMock returns true.

func NewMonoClock added in v1.0.1

func NewMonoClock(u ...UTC) TestClock

NewMonoClock returns a TestClock with the monotonic clock reading.

func NewWallClock added in v1.0.1

func NewWallClock(u ...UTC) TestClock

NewWallClock returns a TestClock with the monotonic clock reading stripped.

func NewWallClockMs added in v1.0.1

func NewWallClockMs(u ...UTC) TestClock

NewWallClockMs returns a TestClock with the monotonic clock reading stripped and time rounded to the millisecond.

func (TestClock) Add added in v1.0.1

func (c TestClock) Add(t time.Duration) UTC

Add adds the given duration to the UTC time of this TestClock and returns the resulting UTC. If this TestClock was started without a time, the addition is made on top of the current wall clock (and results in a time in the future when t is positive).

func (TestClock) Get added in v1.0.1

func (c TestClock) Get() UTC

Get returns the previously set time or Zero if it was not set.

func (TestClock) IsMock added in v1.0.1

func (c TestClock) IsMock() bool

IsMock returns true if this clock is effectively the 'global clock'.

func (TestClock) MockNow added in v1.0.1

func (c TestClock) MockNow() TestClock

MockNow sets this clock as the global clock. After this call utc.Now returns what the function Now of this clock returns.

func (TestClock) Now added in v1.0.1

func (c TestClock) Now() UTC

Now returns the current time. The returned time is taken from the wall clock if this TestClock was started without any time or with Zero or if it was set to Zero or no time.

func (TestClock) Set added in v1.0.1

func (c TestClock) Set(u UTC) UTC

Set sets the given UTC time and returns the previously set time or Zero if it was not set. If the parameter is Zero, the function works as if Unset was called.

func (TestClock) SetNow added in v1.0.1

func (c TestClock) SetNow() UTC

SetNow sets this TestClock to the current wall clock and returns the previously set value. This is equivalent to calling c.Set( wall-clock ).

func (TestClock) UnmockNow added in v1.0.1

func (c TestClock) UnmockNow()

UnmockNow removes this clock from being the 'global clock' and resets the utc.Now func to the default.

func (TestClock) Unset added in v1.0.1

func (c TestClock) Unset() UTC

Unset unsets the current time and returns the previously set value. This resets this TestClock to behave as a wall clock in future calls to Now. This is equivalent to calling c.Set(Zero)

type UTC

type UTC struct {
	time.Time // time in UTC
	// contains filtered or unexported fields
}

UTC is a standard time.Time in the UTC timezone with marshaling to and from ISO 8601 / RFC 3339 format with fixed milliseconds: 2006-01-02T15:04:05.000Z

Years smaller than "0000" and larger than "9999" cannot be marshaled to bytes, text, or JSON, and generate an error if attempted.

time.Time keeps track of a "wall clock" for "time telling" as well as a "monotonic clock" for "time measurements" - see documentation of the time package. The monotonic clock is automatically stripped from a Time instance that results from a time operation (e.g. Add, Truncate) as well as timezone changes, unmarshalling, etc.

Since UTC changes the timezone from "local" to "UTC", this also strips the monotonic clock. However, we want to be able to use UTC also for reliable time measurements... Hence we retain the original Time instance and use that for time measurements.

Prefer the Equals() method over comparison with Go's == operator - the latter also compares the monotonic clock and Location, which might lead to undesired results. If time measurements are not needed, the monotonic clock can be removed with StripMono(). Also see the documentation of time.Time for this problem.

See https://en.wikipedia.org/wiki/ISO_8601 See https://tools.ietf.org/html/rfc3339

Example
// standard lib time.Time
location, _ := time.LoadLocation("Indian/Mayotte")
d0std := time.Date(2000, 1, 1, 0, 0, 0, 0, location)
fmt.Println("d0 std ", d0std)

// utc.UTC
d0 := utc.New(d0std)
fmt.Println("d0     ", d0.String())

// utc.UTC.Time is the underlying time.Time (in UTC timezone)
fmt.Println("d0.Time", d0.Time)

// ISO8601 / RFC3339
d1 := utc.MustParse("2021-12-25T12:20:00.000Z")
fmt.Println("d1     ", d1)

// All methods of time.Time are available on utc.UTC
fmt.Println("d1-d0  ", d1.Sub(d0))

// JSON and text marshalling produce & parse ISO8601 / RFC3339
jsn, _ := d1.MarshalText()
fmt.Println("d1     ", string(jsn), "MarshalText()")
Output:


d0 std  2000-01-01 00:00:00 +0300 EAT
d0      1999-12-31T21:00:00.000Z
d0.Time 1999-12-31 21:00:00 +0000 UTC
d1      2021-12-25T12:20:00.000Z
d1-d0   192711h20m0s
d1      2021-12-25T12:20:00.000Z MarshalText()

func FromString

func FromString(s string) (UTC, error)

FromString parses the given time string.

func Mono added in v1.0.1

func Mono() UTC

Mono returns the current time with the monotonic clock.

func MustParse

func MustParse(s string) UTC

MustParse parses the given time string according to ISO 8601 format, panicking in case of errors.

func New

func New(t time.Time) UTC

New creates a new UTC instance from the given time. Use utc.Now() to get the current time.

func Now

func Now() UTC

Now returns the current time as UTC instance. Now can be mocked for tests: see MockNow() function.

func Parse

func Parse(layout string, value string) (UTC, error)

Parse parses the given time value string with the provided layout - see Time.Parse()

func Unix

func Unix(sec int64, nsec int64) UTC

Unix returns the local Time corresponding to the given Unix time, sec seconds and nsec nanoseconds since January 1, 1970 UTC. It is valid to pass nsec outside the range [0, 999999999]. Not all sec values have a corresponding time value. One such value is 1<<63-1 (the largest int64 value).

func UnixMilli

func UnixMilli(millis int64) UTC

UnixMilli returns the local Time corresponding to the given Unix time in milliseconds since January 1, 1970 UTC. This is the reverse operation of UTC.UnixMilli()

func WallClock added in v1.0.1

func WallClock() UTC

WallClock returns the wall clock (i.e. where the monotonic clock reading has been stripped).

func WallClockMs added in v1.0.1

func WallClockMs() UTC

WallClockMs is like WallClock rounded to the millisecond.

func WallNow added in v1.0.1

func WallNow() UTC

WallNow returns Now as a wall clock, i.e. with the monotonic clock reading stripped. WallNow is equivalent to calling Now().StripMono().

func WallNowMs added in v1.0.1

func WallNowMs() UTC

WallNowMs returns Now as a wall clock rounded to the millisecond. WallNowMs is equivalent to calling WallNow().Round(time.Millisecond) and useful in tests where UTC instances are serialized and compared.

func (UTC) Add

func (u UTC) Add(d time.Duration) UTC

func (UTC) After

func (u UTC) After(other UTC) bool

func (UTC) Before

func (u UTC) Before(other UTC) bool

func (UTC) Equal

func (u UTC) Equal(other UTC) bool

func (UTC) MarshalBinary

func (u UTC) MarshalBinary() ([]byte, error)

MarshalBinary implements the encoding.BinaryMarshaler interface.

func (UTC) MarshalJSON

func (u UTC) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface. Unlike time.Time, it always marshals milliseconds, even if they are all zeros, i.e. 2006-01-02T15:04:05.000Z instead of 2006-01-02T15:04:05Z

func (UTC) MarshalText

func (u UTC) MarshalText() ([]byte, error)

MarshalText implements the encoding.TextMarshaler interface. Unlike time.Time, it always marshals milliseconds, even if they are all zeros (i.e. 2006-01-02T15:04:05.000Z instead of 2006-01-02T15:04:05Z)

func (*UTC) Mono

func (u *UTC) Mono() time.Time

Mono returns the time.Time instance for time measurement operations. Note that the returned instance has an actual monotonic clock only if the original Time instance, from which this UTC was created, had a monotonic clock. This is the case if created through utc.Now() (unless mocked) or New(time.Now())

func (UTC) Round

func (u UTC) Round(d time.Duration) UTC

func (UTC) String

func (u UTC) String() string

String returns the time formatted ISO 8601 format: 2006-01-02T15:04:05.000Z

func (UTC) StripMono

func (u UTC) StripMono() UTC

StripMono returns a new UTC instance stripped of the monotonic clock.

This is sometimes needed when comparing UTC instances with Go's == operator, which when used on time.Time instances, also compares the mono clock. See doc of time package.

func (UTC) Sub

func (u UTC) Sub(other UTC) time.Duration

func (UTC) Truncate

func (u UTC) Truncate(d time.Duration) UTC

func (UTC) UnixMilli

func (u UTC) UnixMilli() int64

UnixMilli returns the unix time in milliseconds since 1970-01-01T00:00:00.000Z.

func (*UTC) UnmarshalBinary

func (u *UTC) UnmarshalBinary(data []byte) error

UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.

func (*UTC) UnmarshalJSON

func (u *UTC) UnmarshalJSON(data []byte) error

UnmarshalJSON implements the json.Unmarshaler interface.

func (*UTC) UnmarshalText

func (u *UTC) UnmarshalText(data []byte) error

UnmarshalText implements the encoding.TextUnmarshaler interface.

func (UTC) ValidateISO8601

func (u UTC) ValidateISO8601() error

ValidateISO8601 validates that this UTC represents a valid ISO 8601 date, where the year is in [0000, 9999].

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL