Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to format Duration

Tags:

date

go

iso8601

How can I format/stringify a time.Duration into ISO8601 ? e.g. P3Y6M4DT12H30M5S

like image 570
The user with no hat Avatar asked Jan 21 '26 10:01

The user with no hat


1 Answers

If you just have a time.Duration and no context, you're out of luck: Duration just counts nanoseconds, and the number of nanoseconds in a month varies with the number of days. There are similar, smaller irregularities with daylight savings transitions (mentioned in docs), leap days, and leap seconds (Go's time package doesn't even consider leap seconds).

Given two time.Time values, it looks like github.com/rickb777/date/period will do what you want, including formatting--this prints P3Y1M21DT17H18M58S:

package main

import (
    "fmt"
    "github.com/rickb777/date/period"
    "log"
    "time"
)

func main() {
    t1, err := time.Parse(time.RFC3339, "2012-11-03T13:41:02Z")
    if err != nil {
        log.Fatal(err)
    }
    t2, err := time.Parse(time.RFC3339, "2015-12-25T07:00:00Z")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(period.Between(t1, t2))
}

I found the link to that, along with other info, in another question user icza linked to about the closely-related problem of printing a human-readable "X months ago" string.

Underneath, you're calling Year(), Month(), etc. on both Times, and getting their differences (accounting for varying lengths of months). icza wrote out code for that answering that other question. Then formatting and storing those differences is the relatively easier part, and is also done by, e.g. ChannelMeter/iso8601duration's Duration (adapted from BrianHicks/finch).

I don't know what nits there might still be for total standard compliance, but that gets you pretty close.

like image 108
twotwotwo Avatar answered Jan 23 '26 04:01

twotwotwo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!