:clock8: Better time duration formatting in Go!

durafmt

Build Status Go Report Card codecov GoDoc Open Source Helpers

durafmt is a tiny Go library that formats time.Duration strings (and types) into a human readable format.

go get github.com/hako/durafmt

Why

If you've worked with time.Duration in Go, you most likely have come across this:

53m28.587093086s // :)

The above seems very easy to read, unless your duration looks like this:

354h22m3.24s // :S

Usage

durafmt.ParseString()

package main

import (
	"fmt"
	
	"github.com/hako/durafmt"
)

func main() {
	duration, err := durafmt.ParseString("354h22m3.24s")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(duration) // 2 weeks 18 hours 22 minutes 3 seconds
	// duration.String() // String representation. "2 weeks 18 hours 22 minutes 3 seconds"
}

durafmt.ParseStringShort()

Version of durafmt.ParseString() that only returns the first part of the duration string.

package main

import (
	"fmt"
	
	"github.com/hako/durafmt"
)

func main() {
	duration, err := durafmt.ParseStringShort("354h22m3.24s")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(duration) // 2 weeks
	// duration.String() // String short representation. "2 weeks"
}

durafmt.Parse()

package main

import (
	"fmt"
	"time"
	
	"github.com/hako/durafmt"
)

func main() {
	timeduration := (354 * time.Hour) + (22 * time.Minute) + (3 * time.Second)
	duration := durafmt.Parse(timeduration).String()
	fmt.Println(duration) // 2 weeks 18 hours 22 minutes 3 seconds
}

LimitFirstN()

Like durafmt.ParseStringShort() but for limiting the first N parts of the duration string.

package main

import (
	"fmt"
	"time"
	
	"github.com/hako/durafmt"
)

func main() {
	timeduration := (354 * time.Hour) + (22 * time.Minute) + (3 * time.Second)
	duration := durafmt.Parse(timeduration).LimitFirstN(2) // // limit first two parts.
	fmt.Println(duration) // 2 weeks 18 hours
}

Contributing

Contributions are welcome! Fork this repo, add your changes and submit a PR.

If you would like to fix a bug, add a feature or provide feedback you can do so in the issues section.

durafmt is tested against golangci-lint and you can run tests with go test.

When contributing, running go test; go vet; golint or golangci-lint is recommended.

License

MIT

Owner
Wesley Hill
software engineer & (hobbyist) animator. building @fullcycleapp and other things.
Wesley Hill
Comments
  • remove plural from international units

    remove plural from international units

    The InternationalString units need no plural, and stripping the trailing 's' would result in some unusual output: 1 ms 1 ยตs => 1 m 1 ยต 1 s 1 ms => 1 1 m etc This change should fix that

  • Merge open pull requests and rewrite for other upgrades.

    Merge open pull requests and rewrite for other upgrades.

    This merges #25 and #20 I have also made the following changes.

    • Reformatted readme slightly.
    • Ran against golang-ci to test for errors, refacturing code so all checks pass.
    • Remove unneeded function from unit tests.
    • Add module support, this will be the default in go 1.17.
    • Added GitHub Actions for another way to perform automated tests.
  • Add LimitToUnit() method to limit conversion until this unit.

    Add LimitToUnit() method to limit conversion until this unit.

    Example :

           duration, _ := ParseString("354h22m3.24s")
           fmt.Println(duration) // 2 weeks 18 hours 22 minutes 3 seconds
    
           duration, _ = ParseString("354h22m3.24s")
           duration = duration.LimitToUnit("days")
           fmt.Println(duration) // 14 days 18 hours 22 minutes 3 seconds
    
  • durafmt incorrectly calculates the duration.

    durafmt incorrectly calculates the duration.

    As you can see from this gist: https://gist.github.com/adewale/da804cc1db00c26e4892eb0da6463789 durafmt incorrectly calculates the duration in some scenarios.

    A duration that should be "1 year 1 day" becomes "1 year 1 month 3 days"

  • Pass the time.Duration directly to Parse?

    Pass the time.Duration directly to Parse?

    It seems like with the current API a common pattern would arise:

    var dur time.Duration
    ...
    if d, err := durafmt.Parse(dur.String()); err != nil {
        check(err)
    }
    

    Passing it directly it becomes:

    var dur time.Duration
    ...
    d := durafmt.Parse(dur)
    

    And allows for this chain:

    str := durafmt.Parse(dur).String()
    
  • Add CodeTriage badge to hako/durafmt

    Add CodeTriage badge to hako/durafmt

    Adds a badge showing the number of people helping this repo on CodeTriage.

    Open Source Helpers

    What is CodeTriage?

    CodeTriage is an Open Source app that is designed to make contributing to Open Source projects easier. It works by sending subscribers a few open issues in their inbox. If subscribers get busy, there is an algorithm that backs off issue load so they do not get overwhelmed

    Read more about the CodeTriage project.

    Why am I getting this PR?

    Your project was picked by the human, @schneems. They selected it from the projects submitted to https://www.codetriage.com and hand edited the PR. How did your project get added to CodeTriage? Roughly about 1 year ago, omkar-dev added this project to CodeTriage in order to start contributing. Since then, 2 people have subscribed to help this repo.

    What does adding a badge accomplish?

    Adding a badge invites people to help contribute to your project. It also lets developers know that others are invested in the longterm success and maintainability of the project.

    You can see an example of a CodeTriage badge on these popular OSS READMEs:

    • https://github.com/rails/rails
    • https://github.com/crystal-lang/crystal

    Have a question or comment?

    While I am a bot, this PR was manually reviewed and monitored by a human - @schneems. My job is writing commit messages and handling PR logistics.

    If you have any questions, you can reply back to this PR and they will be answered by @schneems. If you do not want a badge right now, no worries, close the PR, you will not hear from me again.

    Thanks for making your project Open Source! Any feedback is greatly appreciated.

  • Parsing almost exactly one year returns one day (almost)

    Parsing almost exactly one year returns one day (almost)

    Example:

    package main
    
    import "time"
    import "fmt"
    import "github.com/hako/durafmt"
    
    func main() {
    	x := time.Now().AddDate(1, 0, 0).Sub(time.Now())
    	fmt.Println(x)
    	y := durafmt.Parse(x).String()
    	fmt.Println(y)
    	z, _ := durafmt.ParseString(x.String())
    	fmt.Println(z)
    }
    

    Result:

    [ugjka@archee remindtest]$ go run main.go 
    8759h59m59.999859268s
    23 hours 59 minutes 59 seconds 31449600999 milliseconds
    23 hours 59 minutes 59 seconds 31449600999 milliseconds
    
    
    [ugjka@archee remindtest]$ go version
    go version go1.9.1 linux/amd64
    
  • constant 31536000000 overflows int

    constant 31536000000 overflows int

    When cross compiling for 32-bit architectures durafmt doesn't compile. For example running GOOS=linux GOARCH=386 go build results in vendor/github.com/hako/durafmt/durafmt.go:59:45: constant 31536000000 overflows int. This should probably be fixed.

  • Return nil pointer from ParseString() called with invalid argument

    Return nil pointer from ParseString() called with invalid argument

    It is better to return a nil pointer when invalid string is passed to ParseString(), because calling Durafmt.String() has no sense in this case (runtime error).

    // Expected behavior.
    d, err := durafmt.ParseString("invalid")
    fmt.Println(err != nil) // true
    fmt.Println(d == nil)   // true
    
  • panic: slice bounds out of range when calling String()

    panic: slice bounds out of range when calling String()

    Hi! I made a quick fuzzing harness and ran go-fuzz against this project and found this.

    Repro case (playground link: https://play.golang.org/p/c4rOFJKTZUW):

    package main
    
    import (
    	"fmt"
    
    	"github.com/hako/durafmt"
    )
    
    func main() {
    	d, err := durafmt.ParseStringShort("1us")
    	if err != nil {
    		return
    	}
    	fmt.Println(d.String())
    }
    

    Panics with:

    panic: runtime error: slice bounds out of range [:2] with capacity 1
    
    goroutine 1 [running]:
    github.com/hako/durafmt.(*Durafmt).String(0x43e280, 0x3, 0x43e280, 0x0)
    	/tmp/gopath255955293/pkg/mod/github.com/hako/[email protected]/durafmt.go:143 +0xd40
    main.main()
    	/tmp/sandbox835880566/prog.go:14 +0x80
    
  • Limit to adjacent time units

    Limit to adjacent time units

    I'd like a way to limit duration strings to the first N adjacent time units.

    Existing behaviour:

    package main
    
    import (
    	"fmt"
    	"time"
    
    	"github.com/hako/durafmt"
    )
    
    func main() {
    	duration := durafmt.Parse(2*time.Hour + 58*time.Second).LimitFirstN(2).String()
    	fmt.Println(duration)
    }
    

    This returns 2 hours 58 seconds.

    I don't love this behaviour because the "58 seconds" part is not important and should be truncated. But if I had 58 minutes, that would be important.

    Desired behaviour:

    	duration := durafmt.Parse(2*time.Hour + 58*time.Second).LimitFirstAdjacentN(2).String()
    

    Would return 2 hours.

    	duration := durafmt.Parse(2*time.Hour + 15*time.Minute).LimitFirstAdjacentN(2).String()
    

    Would return 2 hours 15 minutes.

  • Semver release

    Semver release

    Can you create a release for this project and follow semantic versioning please? It is ok to start with v0 version to allow backward incompatible changes. So v0.1.0 could be a good start.

    This will allow users to pin specific version instead of commit hash and setup auto-updating (e.g. Dependabot).

    Thanks!

  • Include Nanoseconds

    Include Nanoseconds

    It would be nice to have nanosecond precision in a human readable duration format.

    Given the following code, there are still 784 nanoseconds that could be displayed in an output format. Since output units can be limited to a specific one, I see little reason not to include such a feature, there are already Milliseconds and Microseconds, why not nanoseconds, also?

  • ParseShort is not working as expected

    ParseShort is not working as expected

    Since this prints: 9 years 46 weeks

    durafmt.Parse(t).LimitFirstN(2).String()
    

    I expected the ParseShort() function to print this way: 9y 46w

    durafmt.ParseShort(t).LimitFirstN(2).String()
    

    Am I missing something? If so, can we use custom formatting on these? (LONG, SHORT, etc.)

  • i18n duration formatting

    i18n duration formatting

    Is there any interest for internationalised (non-English) duration formatting? I've created https://github.com/fat0troll/durufmt for Russian language, based on your library (thank you!), and I'm curious is there a need for fully-internationalised time duration formatting library?

    Maybe someone will create it's own implementation or figure out, how to implement i18n in durafmt directly.

    And again, thanks for your library, it's awesome (but I needed one for Russian language, so I created one based on your work)!

:clock1: Date and Time - Golang Formatting Library
:clock1: Date and Time - Golang Formatting Library

Kair Date and Time - Golang Formatting Library Setup To get Kair > Go CLI go get github.com/GuilhermeCaruso/kair > Go DEP dep ensure -add github.com/G

Sep 26, 2022
fasttime - fast time formatting for go

fasttime - fast time formatting for go

Dec 13, 2022
Convert string to duration in golang

Go String To Duration (go-str2duration) This package allows to get a time.Duration from a string. The string can be a string retorned for time.Duratio

Dec 7, 2022
Time struct in Go that uses 4 bytes of memory vs the 24 bytes of time.Time

A tiny time object in Go. Tinytime uses 4 bytes of memory vs the 24 bytes of a standard time.Time{}

Oct 3, 2022
Gostradamus: Better DateTimes for Go ๐Ÿ•ฐ๏ธ
Gostradamus: Better DateTimes for Go ๐Ÿ•ฐ๏ธ

Gostradamus is a Go library that offers a lightweight and human-friendly way to create, transform, format, and parse datetimes. It uses the underlying Go time library and the main gostradamus' type DateTime can be easily converted to and from time.Time.

Dec 30, 2022
Carbon for Golang, an extension for Time

Carbon A simple extension for Time based on PHP's Carbon library. Features: Time is embedded into Carbon (provides access to all of Time's functionali

Dec 20, 2022
Now is a time toolkit for golang

Now Now is a time toolkit for golang Install go get -u github.com/jinzhu/now Usage Calculating time based on current time import "github.com/jinzhu/n

Dec 23, 2022
Golang package to manipulate time intervals.

timespan timespan is a Go library for interacting with intervals of time, defined as a start time and a duration. Documentation API Installation Insta

Sep 26, 2022
timeutil - useful extensions (Timedelta, Strftime, ...) to the golang's time package

timeutil - useful extensions to the golang's time package timeutil provides useful extensions (Timedelta, Strftime, ...) to the golang's time package.

Dec 22, 2022
Go time library inspired by Moment.js

Goment Current Version: 1.4.0 Changelog Goment is a port of the popular Javascript datetime library Moment.js. It follows the Moment.js API closely, w

Dec 24, 2022
๐ŸŒ A time zone helper
๐ŸŒ A time zone helper

?? A time zone helper tz helps you schedule things across time zones. It is an interactive TUI program that displays time across a few time zones of y

Dec 29, 2022
Clock is a small library for mocking time in Go.

clock Clock is a small library for mocking time in Go. It provides an interface around the standard library's time package so that the application can

Dec 30, 2022
A natural language date/time parser with pluggable rules

when when is a natural language date/time parser with pluggable rules and merge strategies Examples tonight at 11:10 pm at Friday afternoon the deadli

Dec 26, 2022
time format golang

a simple plugin to change date and time format

Sep 29, 2021
Structural time package for jalali calendar

Jalali Structural time package for jalali calendar. This package support parse from string, json and time. Structures There are three data structures

Mar 21, 2022
Timediff is a Go package for printing human readable, relative time differences ๐Ÿ•ฐ๏ธ

timediff is a Go package for printing human readable, relative time differences. Output is based on ranges defined in the Day.js JavaScript library, and can be customized if needed.

Dec 25, 2022
Show time by timezone

Show time by timezone

Jan 22, 2022
Go-timeparser - Flexible Time Parser for Golang

go-timeparser Flexible Time Parser for Golang Installation Download timeparser w

Dec 29, 2022
Parse a RFC 3339 duration string into time.Duration

duration Parse a RFC3339 duration string into time.Duration There are probably a few unsupported edge cases still to be fixed, please help me find the

Nov 25, 2021
Copy of stdlib's time.Duration, but ParseDuration accepts other bigger units such as days, weeks, months and years

duration Copy of stdlib's time.Duration, but ParseDuration accepts other units as well: d: days (7 * 24 * time.Hour) w: weeks (7 * Day) mo: months (30

Jun 21, 2022