gotimeparser

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Mar 8, 2023 License: BSD-3-Clause Imports: 4 Imported by: 0

README

Go universal time format parser

GitHub Workflow Status License GitHub issues GitHub issues The latest release version GoDoc

Background

Many companies use service to service integration through different API porotocols. I had the same situation in my production environment. At some point, clients of my service started to send me dates in different formats.

Some of them sent timestamps in int, some of them used ISO 8601, etc. But what was clear, these dates were valid and we could not request to change it in one day.

As a result of this issue, I implemented some solution that solved the issue and wrote a couple of articles that shared the issue and the approach:

  1. Parse timestamp formats
  2. Parse time from different non timestamp formats
  3. Universal time UnmarshalJSON implementation

But I did not want to create an Open Source package, because of I believe that Open Source cannot be just few lines of code. It's a right formatting of the code, some code coverage by tests, examples and the most important - is commitment to support it.

Documentation

To make documentation more standartized and always up-to-date, we use GoDoc (pkg.go.dev/github.com/aohorodnyk/gotimeparser). It is the best documentation tool for Go.

Every feature or feature change should introduce some changes in comments, doc.go, README.md and tests include examples.

Contributing

The library is open source and you can contribute to it.

Before contrbution, make sure that githook is configured for you and all your commits contain the correct issue tag.

Branch Name

Before you start the contribution, make sure that you are on the correct branch. Branch name should start from the issue number dash and short explanation with spaces replaced by underscores. Example:

  • 1-my_feature
  • 2-fix_bug
  • 234-my_important_pr
Git Hook

To configure the git hook, you need to simply run the command: git config core.hooksPath .githooks

It will configure the git hook to run the pre-commit script. Source code of the hook is in .githooks/prepare-commit-msg.

This git-hook will parse branch name and add the issue tag to the commit message.

Documentation

Index

Examples

Constants

View Source
const (
	// Positive values, bigger than 0 nanoseconds.
	MaxNanoseconds  = int64(math.MaxInt64)
	MaxMicroseconds = MaxNanoseconds / 1000
	MaxMilliseconds = MaxMicroseconds / 1000
	MaxSeconds      = MaxMilliseconds / 1000

	// Negative values, smaller than 0 nanoseconds.
	MinNanoseconds  = int64(math.MinInt64)
	MinMicroseconds = MinNanoseconds / 1000
	MinMilliseconds = MinMicroseconds / 1000
	MinSeconds      = MinMilliseconds / 1000
)

List of times in int64 formats.

Variables

This section is empty.

Functions

func DefaultAllLayouts

func DefaultAllLayouts() []string

DefaultAllLayouts returns a default list of ALL supported layouts. This function returns new copy of a slice.

func Parse

func Parse(input string) (time.Time, error)

Parse function parses time from string. It supports all Go-defined layouts and int64 values. This function supports strings with `"` and `'` quotes marks, but only valid one, like: * "2022-05-06T03:35:02Z" * '1651808102' * `2022-05-06T03:35:02.363368423Z` One quote like "1651808102 or multiple quotes like "'1651808102'" are not supported, because of they are not valid strings.

Example
package main

import (
	"fmt"

	"github.com/aohorodnyk/gotimeparser"
)

func main() {
	dateTime := "1651808102"
	fmt.Println(gotimeparser.Parse(dateTime))

	dateTime = `"1651808102"`
	fmt.Println(gotimeparser.Parse(dateTime))

	dateTime = `'1651808102'`
	fmt.Println(gotimeparser.Parse(dateTime))

	dateTime = "'2022-05-06T03:35:02Z'"
	fmt.Println(gotimeparser.Parse(dateTime))

	dateTime = `"Fri, 06 May 2022 03:35:02 UTC"`
	fmt.Println(gotimeparser.Parse(dateTime))

	fmt.Println("=-=-=-=-=-=-=")

	dateTime = ``
	fmt.Println(gotimeparser.Parse(dateTime))

	dateTime = `Friday on 06 May 2022 03:35:02 in UTC`
	fmt.Println(gotimeparser.Parse(dateTime))

}
Output:

2022-05-05 20:35:02 -0700 PDT <nil>
2022-05-05 20:35:02 -0700 PDT <nil>
2022-05-05 20:35:02 -0700 PDT <nil>
2022-05-06 03:35:02 +0000 UTC <nil>
2022-05-06 03:35:02 +0000 UTC <nil>
=-=-=-=-=-=-=
0001-01-01 00:00:00 +0000 UTC Unsupported time format for string: ''
0001-01-01 00:00:00 +0000 UTC Unsupported time format for string: 'Friday on 06 May 2022 03:35:02 in UTC'

func ParseAllLayouts

func ParseAllLayouts(dateTime string) (time.Time, error)

ParseAllLayouts uses layouts from `DefaultAllLayouts` to parse the time from a provided input string.

Example
package main

import (
	"fmt"

	"github.com/aohorodnyk/gotimeparser"
)

func main() {
	rfc3339 := "2022-05-06T03:35:02Z"
	fmt.Println(gotimeparser.ParseAllLayouts(rfc3339))

	rfc3339Nano := "2022-05-06T03:35:02.363368423Z"
	fmt.Println(gotimeparser.ParseAllLayouts(rfc3339Nano))

	rfc1123 := "Fri, 06 May 2022 03:35:02 UTC"
	fmt.Println(gotimeparser.ParseAllLayouts(rfc1123))

	rfc850 := "Friday, 06-May-22 03:35:02 UTC"
	fmt.Println(gotimeparser.ParseAllLayouts(rfc850))

	rfc822 := "06 May 22 03:35 UTC"
	fmt.Println(gotimeparser.ParseAllLayouts(rfc822))

	fmt.Println("=-=-=-=-=-=-=-=-=")

	wrong := "06 of May 22 03:35 in UTC"
	fmt.Println(gotimeparser.ParseAllLayouts(wrong))

}
Output:

2022-05-06 03:35:02 +0000 UTC <nil>
2022-05-06 03:35:02.363368423 +0000 UTC <nil>
2022-05-06 03:35:02 +0000 UTC <nil>
2022-05-06 03:35:02 +0000 UTC <nil>
2022-05-06 03:35:00 +0000 UTC <nil>
=-=-=-=-=-=-=-=-=
0001-01-01 00:00:00 +0000 UTC could not parse time: 06 of May 22 03:35 in UTC

func ParseLayouts

func ParseLayouts(layouts []string, dateTime string) (time.Time, error)

ParseLayouts parses time based on a list of provided layouts. If layouts is empty list or nil, the error with unknown layout will be returned.

Example
package main

import (
	"fmt"
	"time"

	"github.com/aohorodnyk/gotimeparser"
)

func main() {
	rfc3339 := "2022-05-06T03:35:02Z"
	fmt.Println(gotimeparser.ParseLayouts([]string{time.RFC3339}, rfc3339))

	rfc3339Nano := "2022-05-06T03:35:02.363368423Z"
	fmt.Println(gotimeparser.ParseLayouts([]string{time.RFC3339, time.RFC3339Nano}, rfc3339Nano))

	rfc1123 := "Fri, 06 May 2022 03:35:02 UTC"
	fmt.Println(gotimeparser.ParseLayouts([]string{time.RFC1123}, rfc1123))

	fmt.Println("=-=-=-=-=-=-=-=-=")

	// Use RFC3339 layout, but support only RFC1123.
	fmt.Println(gotimeparser.ParseLayouts([]string{time.RFC1123}, rfc3339))

	wrong := "06 of May 22 03:35 in UTC"
	fmt.Println(gotimeparser.ParseAllLayouts(wrong))

}
Output:

2022-05-06 03:35:02 +0000 UTC <nil>
2022-05-06 03:35:02.363368423 +0000 UTC <nil>
2022-05-06 03:35:02 +0000 UTC <nil>
=-=-=-=-=-=-=-=-=
0001-01-01 00:00:00 +0000 UTC could not parse time: 2022-05-06T03:35:02Z
0001-01-01 00:00:00 +0000 UTC could not parse time: 06 of May 22 03:35 in UTC

func ParseTimestamp

func ParseTimestamp(timestamp int64) time.Time

ParseTimestamp parses time from int64. Support all time formats from nanoseconds to seconds. There is a small overlap around 0 between all formats, but this overlap is insignificant.

Example
package main

import (
	"fmt"

	"github.com/aohorodnyk/gotimeparser"
)

func main() {
	seconds := int64(1651808102)
	fmt.Println(gotimeparser.ParseTimestamp(seconds))

	milliseconds := int64(1651808102363)
	fmt.Println(gotimeparser.ParseTimestamp(milliseconds))

	microseconds := int64(1651808102363368)
	fmt.Println(gotimeparser.ParseTimestamp(microseconds))

	nanoseconds := int64(1651808102363368423)
	fmt.Println(gotimeparser.ParseTimestamp(nanoseconds))

}
Output:

2022-05-05 20:35:02 -0700 PDT
2022-05-05 20:35:02.363 -0700 PDT
2022-05-05 20:35:02.363368 -0700 PDT
2022-05-05 20:35:02.363368423 -0700 PDT

Types

type EmptyInputError

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

EmptyInputError represents empty input in Parse function.

func (EmptyInputError) Error

func (e EmptyInputError) Error() string

Implementation of the error type for EmptyInputError struct.

type Time

type Time struct {
	time.Time
}

Time is a custom Time type that can be used during a parsing process. This Time type meant to be used during parsing type. It extends all default behaviour from time.Time, but one method `GoTime` added to get time.Time.

func FromGoTime added in v0.0.3

func FromGoTime(t time.Time) Time

This function converts `time.Time` to `gotimepareser.Time`.

func (*Time) GoTime added in v0.0.3

func (t *Time) GoTime() time.Time

Return time.Time from gotimeparser.Time.

func (*Time) UnmarshalJSON

func (t *Time) UnmarshalJSON(input []byte) error

UnmarshalJSON implements universal parser for the custom Time type.

Example
package main

import (
	"encoding/json"
	"fmt"
	"time"

	"github.com/aohorodnyk/gotimeparser"
)

func main() {
	type jsonType struct {
		NumSeconds      gotimeparser.Time `json:"num_seconds"`
		NumMilliseconds gotimeparser.Time `json:"num_milliseconds"`
		NumMicroseconds gotimeparser.Time `json:"num_microseconds"`
		NumNanoseconds  gotimeparser.Time `json:"num_nanoseconds"`

		HexSeconds gotimeparser.Time `json:"hex_seconds"`

		StrSeconds      gotimeparser.Time `json:"str_seconds"`
		StrMilliseconds gotimeparser.Time `json:"str_milliseconds"`
		StrMicroseconds gotimeparser.Time `json:"str_microseconds"`
		StrNanoseconds  gotimeparser.Time `json:"str_nanoseconds"`

		StrRFC3339     gotimeparser.Time `json:"str_rfc3339"`
		StrRFC3339Nano gotimeparser.Time `json:"str_rfc3339_nano"`
		StrRFC1123     gotimeparser.Time `json:"str_rfc1123"`
		StrRFC850      gotimeparser.Time `json:"str_rfc850"`
		StrRFC822      gotimeparser.Time `json:"str_rfc822"`
	}

	jsonStr := `{
    "num_seconds": 1651808102,
    "num_milliseconds": 1651808102363,
    "num_microseconds": 1651808102363368,
    "num_nanoseconds": 1651808102363368423,

    "hex_seconds": "0x62749766",

    "str_seconds": "1651808102",
    "str_milliseconds": "1651808102363",
    "str_microseconds": "1651808102363368",
    "str_nanoseconds": "1651808102363368423",

    "str_rfc3339": "2022-05-06T03:35:02Z",
    "str_rfc3339_nano": "2022-05-06T03:35:02.363368423Z",
    "str_rfc1123": "Fri, 06 May 2022 03:35:02 UTC",
    "str_rfc850": "Friday, 06-May-22 03:35:02 UTC",
    "str_rfc822": "06 May 22 03:35 UTC"
  }`

	var parsed jsonType

	err := json.Unmarshal([]byte(jsonStr), &parsed)
	if err != nil {
		fmt.Println(err)

		return
	}

	fmt.Println("NumSeconds:", parsed.NumSeconds)
	fmt.Println("HexSeconds:", parsed.HexSeconds)
	fmt.Println("NumMicroseconds:", parsed.NumMicroseconds)
	fmt.Println("NumMilliseconds:", parsed.NumMilliseconds)
	fmt.Println("NumNanoseconds:", parsed.NumNanoseconds)
	fmt.Println("StrMicroseconds:", parsed.StrMicroseconds)
	fmt.Println("StrMilliseconds:", parsed.StrMilliseconds)
	fmt.Println("StrNanoseconds:", parsed.StrNanoseconds)
	fmt.Println("StrSeconds:", parsed.StrSeconds)
	fmt.Println("StrRFC1123:", parsed.StrRFC1123)
	fmt.Println("StrRFC3339:", parsed.StrRFC3339)
	fmt.Println("StrRFC3339Nano:", parsed.StrRFC3339Nano)
	fmt.Println("StrRFC822:", parsed.StrRFC822)
	fmt.Println("StrRFC850:", parsed.StrRFC850)

	// Covert time.Time to gotimeparser.Time.
	gotime := time.Date(2023, 3, 7, 19, 33, 23, 523, time.UTC)
	fmt.Println("gotimeparser.Time:", gotimeparser.FromGoTime(gotime))

}
Output:

NumSeconds: 2022-05-05 20:35:02 -0700 PDT
HexSeconds: 2022-05-05 20:35:02 -0700 PDT
NumMicroseconds: 2022-05-05 20:35:02.363368 -0700 PDT
NumMilliseconds: 2022-05-05 20:35:02.363 -0700 PDT
NumNanoseconds: 2022-05-05 20:35:02.363368423 -0700 PDT
StrMicroseconds: 2022-05-05 20:35:02.363368 -0700 PDT
StrMilliseconds: 2022-05-05 20:35:02.363 -0700 PDT
StrNanoseconds: 2022-05-05 20:35:02.363368423 -0700 PDT
StrSeconds: 2022-05-05 20:35:02 -0700 PDT
StrRFC1123: 2022-05-06 03:35:02 +0000 UTC
StrRFC3339: 2022-05-06 03:35:02 +0000 UTC
StrRFC3339Nano: 2022-05-06 03:35:02.363368423 +0000 UTC
StrRFC822: 2022-05-06 03:35:00 +0000 UTC
StrRFC850: 2022-05-06 03:35:02 +0000 UTC
gotimeparser.Time: 2023-03-07 19:33:23.000000523 +0000 UTC

type UnknownFormatError

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

UnknownFormatError returned when we did not find any supported format to parse the time.

func (UnknownFormatError) Error

func (e UnknownFormatError) Error() string

Implementation of the error type for UnknownFormatError struct.

type UnknownLayoutError

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

UnknownLayoutError returned from `ParseLayouts` and `ParseAllLayouts` when supported layout was not found.

func (UnknownLayoutError) Error

func (e UnknownLayoutError) Error() string

Implementation of the error type for UnknownLayoutError struct.

Jump to

Keyboard shortcuts

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