Skip to content
AgileLogics
7 min read

Working with Dates & Time

Prerequisites: File I/O

The time package has two central types:

  • time.Time — an instant, with a location (time zone).
  • time.Duration — an elapsed time, stored as an int64 count of nanoseconds. Build durations from constants: 90 * time.Second, 2*time.Hour + 30*time.Minute.

Go does not use YYYY-MM-DD style patterns for formatting. Instead you write how one specific reference time would look:

Mon Jan 2 15:04:05 MST 2006

Each part has a fixed value you can remember as 1 2 3 4 5 6 7: month 01, day 02, hour 03 (or 15 for 24-hour), minute 04, second 05, year 2006, time zone offset -0700. So "2006-01-02" means "year-month-day".

Syntax

now := time.Now()
t := time.Date(2024, time.March, 9, 14, 5, 0, 0, time.UTC)

s := t.Format("2006-01-02 15:04")
p, err := time.Parse("2006-01-02", "2024-12-25")

later := t.Add(90 * time.Minute)
next := t.AddDate(0, 1, 0)   // years, months, days
d := later.Sub(t)            // time.Duration
elapsed := time.Since(start) // shorthand for time.Now().Sub(start)

Example

package main

import (
    "fmt"
    "log"
    "time"
)

func main() {
    // A fixed time keeps the output repeatable; real code often uses time.Now().
    t := time.Date(2024, time.March, 9, 14, 5, 0, 0, time.UTC)

    fmt.Println(t.Format("2006-01-02"))
    fmt.Println(t.Format("02/01/2006 15:04"))
    fmt.Println(t.Format("Mon, Jan 2 2006 at 3:04 PM"))
    fmt.Println(t.Format(time.RFC3339))

    later := t.Add(90 * time.Minute)
    fmt.Println(later.Format(time.Kitchen))

    nextMonth := t.AddDate(0, 1, 0)
    fmt.Println(nextMonth.Format("2006-01-02"), nextMonth.Weekday())

    meeting, err := time.Parse("2006-01-02 15:04", "2024-03-12 09:30")
    if err != nil {
        log.Fatal(err)
    }
    until := meeting.Sub(t)
    fmt.Println(until, until.Hours())
    fmt.Println(meeting.After(t), meeting.Equal(t))

    d := 2*time.Hour + 30*time.Minute
    fmt.Println(d, d.Minutes())

    parsed, err := time.ParseDuration("1h15m30s")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(parsed.Seconds())

    minutes := 3
    fmt.Println(time.Duration(minutes) * time.Minute)
}

Expected output

2024-03-09
09/03/2024 14:05
Sat, Mar 9 2024 at 2:05 PM
2024-03-09T14:05:00Z
3:35PM
2024-04-09 Tuesday
67h25m0s 67.41666666666667
true false
2h30m0s 150
4530
3m0s

To measure how long something takes, record start := time.Now() and later print time.Since(start) — that output naturally differs on every run.

Common mistakes

  • Writing layouts with letters ("YYYY-MM-DD") or the wrong reference numbers ("2006-02-01" swaps month and day). Stick to 2006-01-02 15:04:05.
  • Passing a bare number where a duration is expected: time.Sleep(5) sleeps for 5 nanoseconds. Write 5 * time.Second.
  • Multiplying an int variable by a duration without converting it: n * time.Second does not compile when n is an int; use time.Duration(n) * time.Second.
  • Comparing times with ==. Two time.Time values for the same instant can differ in location or internal clock data; use t.Equal(u).
  • Forgetting that time.Parse without zone information returns UTC. Use time.ParseInLocation for local times.

Practice

Parse the date 2024-02-28, add one day, and print the result in the format Feb 29, 2024 followed by its weekday.

Show solution
package main

import (
    "fmt"
    "log"
    "time"
)

func main() {
    d, err := time.Parse("2006-01-02", "2024-02-28")
    if err != nil {
        log.Fatal(err)
    }
    next := d.AddDate(0, 0, 1)
    fmt.Println(next.Format("Jan 2, 2006"), next.Weekday()) // Feb 29, 2024 Thursday
}