How can I format/stringify a time.Duration into ISO8601 ? e.g. P3Y6M4DT12H30M5S
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With