123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- package humanize
- import (
- "bytes"
- "git.nspix.com/golang/kos/util/bs"
- "time"
- )
- const (
- Nanosecond Duration = 1
- Microsecond = 1000 * Nanosecond
- Millisecond = 1000 * Microsecond
- Second = 1000 * Millisecond
- Minute = 60 * Second
- Hour = 60 * Minute
- )
- type Duration int64
- // fmtFrac formats the fraction of v/10**prec (e.g., ".12345") into the
- // tail of buf, omitting trailing zeros. It omits the decimal
- // point too when the fraction is 0. It returns the index where the
- // output bytes begin and the value v/10**prec.
- func fmtFrac(buf []byte, v uint64, prec int) (nw int, nv uint64) {
- // Omit trailing zeros up to and including decimal point.
- w := len(buf)
- print := false
- for i := 0; i < prec; i++ {
- digit := v % 10
- print = print || digit != 0
- if print {
- w--
- buf[w] = byte(digit) + '0'
- }
- v /= 10
- }
- if print {
- w--
- buf[w] = '.'
- }
- return w, v
- }
- // fmtInt formats v into the tail of buf.
- // It returns the index where the output begins.
- func fmtInt(buf []byte, v uint64) int {
- w := len(buf)
- if v == 0 {
- w--
- buf[w] = '0'
- } else {
- for v > 0 {
- w--
- buf[w] = byte(v%10) + '0'
- v /= 10
- }
- }
- return w
- }
- func (d Duration) String() string {
- // Largest time is 2540400h10m10.000000000s
- var buf [32]byte
- w := len(buf)
- u := uint64(d)
- neg := d < 0
- if neg {
- u = -u
- }
- if u < uint64(time.Second) {
- // Special case: if duration is smaller than a second,
- // use smaller units, like 1.2ms
- var prec int
- w--
- buf[w] = 's'
- w--
- switch {
- case u == 0:
- return "0s"
- case u < uint64(time.Microsecond):
- // print nanoseconds
- prec = 0
- buf[w] = 'n'
- case u < uint64(time.Millisecond):
- // print microseconds
- prec = 3
- // U+00B5 'µ' micro sign == 0xC2 0xB5
- w-- // Need room for two bytes.
- copy(buf[w:], "µ")
- default:
- // print milliseconds
- prec = 6
- buf[w] = 'm'
- }
- w, u = fmtFrac(buf[:w], u, prec)
- w = fmtInt(buf[:w], u)
- } else {
- w--
- buf[w] = 's'
- w, u = fmtFrac(buf[:w], u, 9)
- // u is now integer seconds
- w = fmtInt(buf[:w], u%60)
- u /= 60
- // u is now integer minutes
- if u > 0 {
- w--
- buf[w] = 'm'
- w = fmtInt(buf[:w], u%60)
- u /= 60
- // u is now integer hours
- // Stop at hours because days can be different lengths.
- if u > 0 {
- w--
- buf[w] = 'h'
- w = fmtInt(buf[:w], u)
- }
- }
- }
- if neg {
- w--
- buf[w] = '-'
- }
- return string(buf[w:])
- }
- func (d *Duration) UnmarshalJSON(b []byte) (err error) {
- var n time.Duration
- b = bytes.TrimFunc(b, func(r rune) bool {
- if r == '"' {
- return true
- }
- return false
- })
- if n, err = time.ParseDuration(bs.BytesToString(b)); err == nil {
- *d = Duration(n)
- }
- return err
- }
- func (d Duration) MarshalJSON() ([]byte, error) {
- return bs.StringToBytes(`"` + d.String() + `"`), nil
- }
- func (d Duration) Duration() time.Duration {
- return time.Duration(d)
- }
|