Practical guide to parsing your Date and Time in Go
Tags: go
Published: 2021-08-27 17:00:08

![Gopher with a watch](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gasknkntr6pkmrn656z5.png)
Often we find ourselves with a Date Time that is not in some standard format. This is where we identify the pattern of the date time and then try to write a custom layout.

Let us see how we can achieve this in go using the standard **time** package. The **time** package provides us with several functionalities which includes functions like **Parse** and **Format** that serves our purpose.

**Parse**

> Parse parses a formatted string and returns the time value it represents. 

```go
func Parse(layout, value string) (Time, error)
```


```go
package main

import (
	"fmt"
	"time"
)

func main() {
	const longForm = "Jan 2, 2006 at 3:04pm (MST)"
	t, _ := time.Parse(longForm, "Feb 3, 2013 at 7:54pm (PST)")
	fmt.Println(t)

	const shortForm = "2006-Jan-02"
	t, _ = time.Parse(shortForm, "2013-Feb-03")
	fmt.Println(t)
}
```

```
Output:
2013-02-03 19:54:00 +0000 PST
2013-02-03 00:00:00 +0000 UTC
```

Go Playground Link: [Parse Example](https://play.golang.org/p/jYyQtEPTW--)

**Format**

> Format returns a textual representation of the time value formatted according to the layout defined by the argument.

```go
func (t Time) Format(layout string) string
```

```go
func main() {
	t, err := time.Parse(time.UnixDate, "Wed Feb 25 11:06:39 PST 2015")
	if err != nil { // Always check errors even if they should not happen.
		panic(err)
	}

	fmt.Println("default format:", t)

	fmt.Println("Unix format:", t.Format(time.UnixDate))
}
```

```
Output:
default format: 2015-02-25 11:06:39 +0000 PST
Unix format: Wed Feb 25 11:06:39 PST 2015
```

Go Playground Link: [Format Example](https://play.golang.org/p/QnOrTVGpGLI)

### [Predefined Layouts](https://pkg.go.dev/time#pkg-constants) available in **time** package 

| Label       | Definition                          |
|-------------|-------------------------------------|
| Layout      | 01/02 03:04:05PM '06 -0700          |
| ANSIC       | Mon Jan _2 15:04:05 2006            |
| UnixDate    | Mon Jan _2 15:04:05 MST 2006        |
| RubyDate    | Mon Jan 02 15:04:05 -0700 2006      |
| RFC822      | 02 Jan 06 15:04 MST                 |
| RFC822Z     | 02 Jan 06 15:04 -0700               |
| RFC850      | Monday, 02-Jan-06 15:04:05 MST      |
| RFC1123     | Mon, 02 Jan 2006 15:04:05 MST       |
| RFC1123Z    | Mon, 02 Jan 2006 15:04:05 -0700     |
| RFC3339     | 2006-01-02T15:04:05Z07:00           |
| RFC3339Nano | 2006-01-02T15:04:05.999999999Z07:00 |
| Kitchen     | 3:04PM                              |
| Stamp       | Jan _2 15:04:05                     |
| StampMilli  | Jan _2 15:04:05.000                 |
| StampMicro  | Jan _2 15:04:05.000000              |
| StampNano   | Jan _2 15:04:05.000000000           |

### Building Blocks for creating your own layout

| Type                    | Options |
|--------------------------|-------------------------------------|
| Year                     | "2006", "06"                        |
| Month                    | "Jan", "January", "1", "01"         |
| Textual day of the week  | "Mon", "Monday"                     |
| Numeric day of the month | "2", "_2", "02"                     |
| Numeric day of the year  | "__2", "002"                        |
| Hour                     | "15", "3", "03" (PM or AM)          |
| Minute                   | "4", "04"                           |
| Second                   | "5", "05"                           |
| AM/PM mark               | "PM"                                |


For layouts specifying the two-digit year 06, a value NN >= 69 will be treated as 19NN and a value NN < 69 will be treated as 20NN.

### Numeric time zone offsets format as follows:

| Value    | Format |
|----------|--------|
| "-0700"  | ±hhmm  |
| "-07:00" | ±hh:mm |
| "-07"    | ±hh    |


Replacing the sign in the format with a Z triggers the ISO 8601 behavior of printing Z instead of an offset for the UTC zone. Thus:

| Value    | Format      |
|----------|-------------|
| "Z0700"  | Z or ±hhmm  |
| "Z07:00" | Z or ±hh:mm |
| "Z07"    | Z or ±hh    |

### Final Example

```go
func main() {
	ipTimes := []string{
		"24 Aug 2021 7:20:50 PM",
		"Aug 24 2021 07:20:50PM",
		"24-08-2021 17:20:50",
		"08-24-2021 13:12:32",
		"24/8/21 9:00:12",
		"8/24/2021 10:10:10",
		"1993-11-23 7**12**44PM",
		"24 October 97 7:12:45PM+05:30", // 24 th January 1997
	}

	layouts := []string{
		"2 Jan 2006 3:04:05 PM",
		"Jan 2 2006 03:04:05PM",
		"2-01-2006 15:04:05",
		"01-02-2006 15:4:5",
		"2/1/06 3:4:5",
		"1/2/2006 3:4:5",
		"2006-01-02 3**4**5PM",
		"2 January 06 3:4:5PMZ07:00",
	}

	for i := 0; i < len(ipTimes); i++ {
		t, err := time.Parse(layouts[i], ipTimes[i]) // parsing to get time value
		if err != nil {                              // check for errors
			fmt.Println(err)
			return
		}
		
		fmt.Println("    Input DateTime String: ", ipTimes[i])
		fmt.Println("                   Layout: ", layouts[i])
		fmt.Println("Time value Default Format: ", t)
		fmt.Println("   Time in RFC3339 Format: ", t.Format(time.RFC3339))
	}
}

```
Let us take one such example to iterate through it


Input: 	"24 October 97 7:12:45PM+05:30"
Layout: "2 January 06 3:4:5PMZ07:00"

From the building blocks listed above we can map things 

| Layout Key | Actual Value | Description              |
|------------|--------------|--------------------------|
| 2          | 24           | Numeric day of the month |
| January    | October      | month                    |
| 06         | 97           | Year (1997)              |
| 3          | 7            | Hour                     |
| 4          | 12           | Minute                   |
| 5          | 45           | Second                   |
| Z07:00     | +05:30       | Offset                      |

Since PM is specified 7:12:45 is in 12 hour format.

Using the Layout blocks specified we can easily see the pattern and can create our own layout.

#### Fun Tip
Ever wondered why `time.Now()` on [golang playground](https://play.golang.org/) prints the same time (2009-11-10 23:00:00 +0000 UTC m=+0.000000001) ?

Drum roll!!!!!!

_**It is the time and date of Go Lang's birthday.**_

Hope you learnt something new or had your concepts revised.

Let me know if I missed something.

[Complete Working Date Time Example](https://play.golang.org/p/_D90gfCLnDS)

#### References

[Time Format](https://pkg.go.dev/time@go1.17#Time.Format)
[Time Parse](https://pkg.go.dev/time@go1.17#Parse)
[Constants](https://pkg.go.dev/time@go1.17#pkg-constants)