Help us shape the future of Go! Take the 2026 Go Developer Survey

human

package
v0.6.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 24, 2026 License: MIT Imports: 11 Imported by: 0

README

human

import "github.com/gechr/x/human"

Package human formats bytes, durations, counts, numbers, and ordinals for human-readable output.

Index

Constants

SI byte size constants (powers of 1000).

const (
    KB  = 1000
    MB  = 1000 * KB
    GB  = 1000 * MB
    TB  = 1000 * GB
    PB  = 1000 * TB
    EB  = 1000 * PB
)

IEC byte size constants (powers of 1024).

const (
    KiB = 1024
    MiB = 1024 * KiB
    GiB = 1024 * MiB
    TiB = 1024 * GiB
    PiB = 1024 * TiB
    EiB = 1024 * PiB
)

Unit label constants.

const (
    UnitB   = "B"
    UnitKB  = "KB"
    UnitMB  = "MB"
    UnitGB  = "GB"
    UnitTB  = "TB"
    UnitPB  = "PB"
    UnitEB  = "EB"
    UnitKiB = "KiB"
    UnitMiB = "MiB"
    UnitGiB = "GiB"
    UnitTiB = "TiB"
    UnitPiB = "PiB"
    UnitEiB = "EiB"
)

Time arithmetic constants.

const (
    SecondsPerMinute = 60

    MinutesPerHour = 60

    HoursPerDay = 24

    DaysPerWeek  = 7
    DaysPerMonth = 30
    DaysPerYear  = 365

    WeeksPerMonth = 4
    WeeksPerYear  = 52

    MonthsPerYear = 12
)

func ContractHome

func ContractHome(path string) string

ContractHome replaces the user's home directory prefix with ~.

Example

ContractHome leaves paths outside the home directory untouched.

home, _ := os.UserHomeDir()
fmt.Println(human.ContractHome(filepath.Join(home, "projects", "x")))
fmt.Println(human.ContractHome("/etc/hosts"))

Output:

~/projects/x
/etc/hosts

func FormatDuration

func FormatDuration(d time.Duration, options ...DurationFormatOptions) string

FormatDuration formats d as up to two adjacent units with no separator (e.g. "5.2s", "2h15m", "1w2d"). Years are 365 days, weeks are 7 days. With no options it uses magnitude-based resolution: the largest exact sub-second unit, one decimal place below ten seconds, and whole seconds thereafter. When multiple options values are supplied, the last applies.

FormatDuration(90 * time.Second)             // "1m30s"
FormatDuration(2*time.Hour + 15*time.Minute) // "2h15m"
FormatDuration(8 * 24 * time.Hour)           // "1w1d"
FormatDuration(400 * 24 * time.Hour)         // "1y5w"
FormatDuration(50 * time.Millisecond)        // "50ms"
FormatDuration(5200 * time.Millisecond)      // "5.2s"
Example
fmt.Println(human.FormatDuration(90 * time.Second))
fmt.Println(human.FormatDuration(2*time.Hour + 15*time.Minute))
fmt.Println(human.FormatDuration(400 * 24 * time.Hour))
fmt.Println(human.FormatDuration(50 * time.Millisecond))
fmt.Println(human.FormatDuration(5200 * time.Millisecond))

Output:

1m30s
2h15m
1y5w
50ms
5.2s

func FormatIECBytes

func FormatIECBytes(b float64) string

FormatIECBytes formats a byte count using IEC binary units (KiB, MiB, GiB, TiB, PiB, EiB).

Example
fmt.Println(human.FormatIECBytes(512))
fmt.Println(human.FormatIECBytes(1536))
fmt.Println(human.FormatIECBytes(5 * human.GiB))

Output:

512 B
1.50 KiB
5.00 GiB

func FormatNumber

func FormatNumber(n int64, sep string) string

FormatNumber groups n's digits in threes from the right, joined with sep. Not locale-aware: pick a separator suited to your output.

FormatNumber(1234567, ",") // "1,234,567"
FormatNumber(1234567, ".") // "1.234.567"
FormatNumber(1234567, " ") // "1 234 567"
FormatNumber(-42, ",")     // "-42"
Example
fmt.Println(human.FormatNumber(1234567, ","))
fmt.Println(human.FormatNumber(1234567, "."))
fmt.Println(human.FormatNumber(1234567, " "))
fmt.Println(human.FormatNumber(-42, ","))

Output:

1,234,567
1.234.567
1 234 567
-42

func FormatNumberCompact

func FormatNumberCompact(n int64) string

FormatNumberCompact renders n in a compact, abbreviated form using K, M, B, and T suffixes (powers of 1000), with up to one decimal place and a trailing .0 trimmed. Values whose magnitude is below 1000 are returned verbatim. Values that round up to the next unit are promoted (e.g. 999999 → 1M), and magnitudes beyond a trillion stay in T.

FormatNumberCompact(950)      // "950"
FormatNumberCompact(1234)     // "1.2K"
FormatNumberCompact(1000000)  // "1M"
FormatNumberCompact(9999999)  // "10M"
FormatNumberCompact(-1500000) // "-1.5M"
Example
fmt.Println(human.FormatNumberCompact(950))
fmt.Println(human.FormatNumberCompact(1500))
fmt.Println(human.FormatNumberCompact(999999))
fmt.Println(human.FormatNumberCompact(3400000000))

Output:

950
1.5K
1M
3.4B

func FormatOrdinal

func FormatOrdinal(n int) string

FormatOrdinal returns n with its English ordinal suffix.

FormatOrdinal(1)   // "1st"
FormatOrdinal(22)  // "22nd"
FormatOrdinal(113) // "113th"
Example
fmt.Println(human.FormatOrdinal(1))
fmt.Println(human.FormatOrdinal(22))
fmt.Println(human.FormatOrdinal(113))

Output:

1st
22nd
113th

func FormatSIBytes

func FormatSIBytes(b float64) string

FormatSIBytes formats a byte count using SI decimal units (KB, MB, GB, TB, PB, EB).

Example
fmt.Println(human.FormatSIBytes(512))
fmt.Println(human.FormatSIBytes(1500))
fmt.Println(human.FormatSIBytes(5 * human.GB))

Output:

512 B
1.50 KB
5.00 GB

func FormatTimeAgo

func FormatTimeAgo(t time.Time) string

FormatTimeAgo formats a time as a human-readable relative string (plain text).

Example

FormatTimeAgo formats a time relative to the current time; see human.FormatTimeAgoFrom for the full range of outputs.

fmt.Println(human.FormatTimeAgo(time.Now().Add(-90 * time.Minute)))

Output:

1 hour ago

func FormatTimeAgoCompact

func FormatTimeAgoCompact(t time.Time) string

FormatTimeAgoCompact formats a time as a compact relative string (e.g. 15m ago).

Example

FormatTimeAgoCompact formats a time relative to the current time; see human.FormatTimeAgoCompactFrom for the full range of outputs.

fmt.Println(human.FormatTimeAgoCompact(time.Now().Add(-90 * time.Minute)))

Output:

1h ago

func FormatTimeAgoCompactFrom

func FormatTimeAgoCompactFrom(t, now time.Time) string

FormatTimeAgoCompactFrom formats a time as a compact relative string relative to now.

Example
now := time.Date(2024, time.June, 1, 12, 0, 0, 0, time.UTC)
fmt.Println(human.FormatTimeAgoCompactFrom(now.Add(-30*time.Second), now))
fmt.Println(human.FormatTimeAgoCompactFrom(now.Add(-90*time.Minute), now))
fmt.Println(human.FormatTimeAgoCompactFrom(now.Add(-3*24*time.Hour), now))
fmt.Println(human.FormatTimeAgoCompactFrom(now.Add(2*time.Hour), now))

Output:

now
1h ago
3d ago
in 2h

func FormatTimeAgoFrom

func FormatTimeAgoFrom(t, now time.Time) string

FormatTimeAgoFrom formats a time relative to the given reference time now.

Example
now := time.Date(2024, time.June, 1, 12, 0, 0, 0, time.UTC)
fmt.Println(human.FormatTimeAgoFrom(now.Add(-30*time.Second), now))
fmt.Println(human.FormatTimeAgoFrom(now.Add(-90*time.Minute), now))
fmt.Println(human.FormatTimeAgoFrom(now.Add(-3*24*time.Hour), now))
fmt.Println(human.FormatTimeAgoFrom(now.Add(2*time.Hour), now))

Output:

now
1 hour ago
3 days ago
in 2 hours

func ParseByteSize

func ParseByteSize(s string) float64

ParseByteSize parses a human-readable byte size string like 27.61 MiB or 1.5 GB into a byte count. Supports both IEC (KiB, MiB, GiB, TiB, PiB, EiB) and SI (KB, MB, GB, TB, PB, EB) units. Returns 0 for empty or unparseable input.

Example
fmt.Printf("%.0f\n", human.ParseByteSize("1.5 GB"))
fmt.Printf("%.0f\n", human.ParseByteSize("27.61 MiB"))

Output:

1500000000
28951183

func ParseDuration

func ParseDuration(s string) (time.Duration, error)

ParseDuration parses a human duration string into a time.Duration. It is the inverse of FormatDuration, accepting decimal values and the units y, w, d, h, m, s, ms, µs (or us), and ns, where a year is 365 days and a week is 7 days. Units may be combined but each may appear at most once and must run in descending order of size. A decimal value must be the final component. An optional leading - negates the result, and 0 parses to zero.

ParseDuration("2h15m")  // 2*time.Hour + 15*time.Minute
ParseDuration("1w2d")   // 9 * 24 * time.Hour
ParseDuration("5.2s")   // 5200 * time.Millisecond
ParseDuration("-1m30s") // -90 * time.Second
Example

ParseDuration is the inverse of human.FormatDuration, accepting the y, w, d, h, m, s, ms, µs, and ns units that function emits.

d, _ := human.ParseDuration("2h15m")
fmt.Println(d)
d, _ = human.ParseDuration("1w2d")
fmt.Println(d)
d, _ = human.ParseDuration("-1m30s")
fmt.Println(d)

Output:

2h15m0s
216h0m0s
-1m30s

func Plural

func Plural(n int, singular, plural string) string

Plural returns singular when n == 1, otherwise plural. Unlike Pluralize, it omits the count.

Plural(1, "file", "files") // "file"
Plural(3, "file", "files") // "files"
Example
fmt.Println(human.Plural(1, "file", "files"))
fmt.Println(human.Plural(3, "file", "files"))

Output:

file
files

func Pluralize

func Pluralize(n int, singular, plural string) string

Pluralize returns "1 singular" or "n plural".

Pluralize(1, "file", "files") // "1 file"
Pluralize(3, "file", "files") // "3 files"
Example
fmt.Println(human.Pluralize(1, "file", "files"))
fmt.Println(human.Pluralize(3, "file", "files"))

Output:

1 file
3 files

type DurationFormatOptions

DurationFormatOptions controls duration rounding and fractional display.

type DurationFormatOptions struct {
    // Precision is the number of decimal places used for durations below one
    // minute.
    Precision int
    // Round is the rounding granularity. Zero disables pre-format rounding.
    Round time.Duration
    // TrimTrailingZeros removes trailing zeroes from the fractional part.
    TrimTrailingZeros bool
}

Documentation

Overview

Package human formats bytes, durations, counts, numbers, and ordinals for human-readable output.

Index

Examples

Constants

View Source
const (
	KB = 1000
	MB = 1000 * KB
	GB = 1000 * MB
	TB = 1000 * GB
	PB = 1000 * TB
	EB = 1000 * PB
)

SI byte size constants (powers of 1000).

View Source
const (
	KiB = 1024
	MiB = 1024 * KiB
	GiB = 1024 * MiB
	TiB = 1024 * GiB
	PiB = 1024 * TiB
	EiB = 1024 * PiB
)

IEC byte size constants (powers of 1024).

View Source
const (
	UnitB   = "B"
	UnitKB  = "KB"
	UnitMB  = "MB"
	UnitGB  = "GB"
	UnitTB  = "TB"
	UnitPB  = "PB"
	UnitEB  = "EB"
	UnitKiB = "KiB"
	UnitMiB = "MiB"
	UnitGiB = "GiB"
	UnitTiB = "TiB"
	UnitPiB = "PiB"
	UnitEiB = "EiB"
)

Unit label constants.

View Source
const (
	SecondsPerMinute = 60

	MinutesPerHour = 60

	HoursPerDay = 24

	DaysPerWeek  = 7
	DaysPerMonth = 30
	DaysPerYear  = 365

	WeeksPerMonth = 4
	WeeksPerYear  = 52

	MonthsPerYear = 12
)

Time arithmetic constants.

Variables

This section is empty.

Functions

func ContractHome

func ContractHome(path string) string

ContractHome replaces the user's home directory prefix with ~.

Example

ContractHome leaves paths outside the home directory untouched.

package main

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/gechr/x/human"
)

func main() {
	home, _ := os.UserHomeDir()
	fmt.Println(human.ContractHome(filepath.Join(home, "projects", "x")))
	fmt.Println(human.ContractHome("/etc/hosts"))
}
Output:
~/projects/x
/etc/hosts

func FormatDuration

func FormatDuration(d time.Duration, options ...DurationFormatOptions) string

FormatDuration formats d as up to two adjacent units with no separator (e.g. "5.2s", "2h15m", "1w2d"). Years are 365 days, weeks are 7 days. With no options it uses magnitude-based resolution: the largest exact sub-second unit, one decimal place below ten seconds, and whole seconds thereafter. When multiple options values are supplied, the last applies.

FormatDuration(90 * time.Second)             // "1m30s"
FormatDuration(2*time.Hour + 15*time.Minute) // "2h15m"
FormatDuration(8 * 24 * time.Hour)           // "1w1d"
FormatDuration(400 * 24 * time.Hour)         // "1y5w"
FormatDuration(50 * time.Millisecond)        // "50ms"
FormatDuration(5200 * time.Millisecond)      // "5.2s"
Example
package main

import (
	"fmt"
	"time"

	"github.com/gechr/x/human"
)

func main() {
	fmt.Println(human.FormatDuration(90 * time.Second))
	fmt.Println(human.FormatDuration(2*time.Hour + 15*time.Minute))
	fmt.Println(human.FormatDuration(400 * 24 * time.Hour))
	fmt.Println(human.FormatDuration(50 * time.Millisecond))
	fmt.Println(human.FormatDuration(5200 * time.Millisecond))
}
Output:
1m30s
2h15m
1y5w
50ms
5.2s

func FormatIECBytes

func FormatIECBytes(b float64) string

FormatIECBytes formats a byte count using IEC binary units (KiB, MiB, GiB, TiB, PiB, EiB).

Example
package main

import (
	"fmt"

	"github.com/gechr/x/human"
)

func main() {
	fmt.Println(human.FormatIECBytes(512))
	fmt.Println(human.FormatIECBytes(1536))
	fmt.Println(human.FormatIECBytes(5 * human.GiB))
}
Output:
512 B
1.50 KiB
5.00 GiB

func FormatNumber

func FormatNumber(n int64, sep string) string

FormatNumber groups `n`'s digits in threes from the right, joined with `sep`. Not locale-aware: pick a separator suited to your output.

FormatNumber(1234567, ",") // "1,234,567"
FormatNumber(1234567, ".") // "1.234.567"
FormatNumber(1234567, " ") // "1 234 567"
FormatNumber(-42, ",")     // "-42"
Example
package main

import (
	"fmt"

	"github.com/gechr/x/human"
)

func main() {
	fmt.Println(human.FormatNumber(1234567, ","))
	fmt.Println(human.FormatNumber(1234567, "."))
	fmt.Println(human.FormatNumber(1234567, " "))
	fmt.Println(human.FormatNumber(-42, ","))
}
Output:
1,234,567
1.234.567
1 234 567
-42

func FormatNumberCompact

func FormatNumberCompact(n int64) string

FormatNumberCompact renders `n` in a compact, abbreviated form using K, M, B, and T suffixes (powers of 1000), with up to one decimal place and a trailing `.0` trimmed. Values whose magnitude is below 1000 are returned verbatim. Values that round up to the next unit are promoted (e.g. 999999 → `1M`), and magnitudes beyond a trillion stay in `T`.

FormatNumberCompact(950)      // "950"
FormatNumberCompact(1234)     // "1.2K"
FormatNumberCompact(1000000)  // "1M"
FormatNumberCompact(9999999)  // "10M"
FormatNumberCompact(-1500000) // "-1.5M"
Example
package main

import (
	"fmt"

	"github.com/gechr/x/human"
)

func main() {
	fmt.Println(human.FormatNumberCompact(950))
	fmt.Println(human.FormatNumberCompact(1500))
	fmt.Println(human.FormatNumberCompact(999999))
	fmt.Println(human.FormatNumberCompact(3400000000))
}
Output:
950
1.5K
1M
3.4B

func FormatOrdinal

func FormatOrdinal(n int) string

FormatOrdinal returns `n` with its English ordinal suffix.

FormatOrdinal(1)   // "1st"
FormatOrdinal(22)  // "22nd"
FormatOrdinal(113) // "113th"
Example
package main

import (
	"fmt"

	"github.com/gechr/x/human"
)

func main() {
	fmt.Println(human.FormatOrdinal(1))
	fmt.Println(human.FormatOrdinal(22))
	fmt.Println(human.FormatOrdinal(113))
}
Output:
1st
22nd
113th

func FormatSIBytes

func FormatSIBytes(b float64) string

FormatSIBytes formats a byte count using SI decimal units (KB, MB, GB, TB, PB, EB).

Example
package main

import (
	"fmt"

	"github.com/gechr/x/human"
)

func main() {
	fmt.Println(human.FormatSIBytes(512))
	fmt.Println(human.FormatSIBytes(1500))
	fmt.Println(human.FormatSIBytes(5 * human.GB))
}
Output:
512 B
1.50 KB
5.00 GB

func FormatTimeAgo

func FormatTimeAgo(t time.Time) string

FormatTimeAgo formats a time as a human-readable relative string (plain text).

Example

FormatTimeAgo formats a time relative to the current time; see human.FormatTimeAgoFrom for the full range of outputs.

package main

import (
	"fmt"
	"time"

	"github.com/gechr/x/human"
)

func main() {
	fmt.Println(human.FormatTimeAgo(time.Now().Add(-90 * time.Minute)))
}
Output:
1 hour ago

func FormatTimeAgoCompact

func FormatTimeAgoCompact(t time.Time) string

FormatTimeAgoCompact formats a time as a compact relative string (e.g. `15m ago`).

Example

FormatTimeAgoCompact formats a time relative to the current time; see human.FormatTimeAgoCompactFrom for the full range of outputs.

package main

import (
	"fmt"
	"time"

	"github.com/gechr/x/human"
)

func main() {
	fmt.Println(human.FormatTimeAgoCompact(time.Now().Add(-90 * time.Minute)))
}
Output:
1h ago

func FormatTimeAgoCompactFrom

func FormatTimeAgoCompactFrom(t, now time.Time) string

FormatTimeAgoCompactFrom formats a time as a compact relative string relative to `now`.

Example
package main

import (
	"fmt"
	"time"

	"github.com/gechr/x/human"
)

func main() {
	now := time.Date(2024, time.June, 1, 12, 0, 0, 0, time.UTC)
	fmt.Println(human.FormatTimeAgoCompactFrom(now.Add(-30*time.Second), now))
	fmt.Println(human.FormatTimeAgoCompactFrom(now.Add(-90*time.Minute), now))
	fmt.Println(human.FormatTimeAgoCompactFrom(now.Add(-3*24*time.Hour), now))
	fmt.Println(human.FormatTimeAgoCompactFrom(now.Add(2*time.Hour), now))
}
Output:
now
1h ago
3d ago
in 2h

func FormatTimeAgoFrom

func FormatTimeAgoFrom(t, now time.Time) string

FormatTimeAgoFrom formats a time relative to the given reference time `now`.

Example
package main

import (
	"fmt"
	"time"

	"github.com/gechr/x/human"
)

func main() {
	now := time.Date(2024, time.June, 1, 12, 0, 0, 0, time.UTC)
	fmt.Println(human.FormatTimeAgoFrom(now.Add(-30*time.Second), now))
	fmt.Println(human.FormatTimeAgoFrom(now.Add(-90*time.Minute), now))
	fmt.Println(human.FormatTimeAgoFrom(now.Add(-3*24*time.Hour), now))
	fmt.Println(human.FormatTimeAgoFrom(now.Add(2*time.Hour), now))
}
Output:
now
1 hour ago
3 days ago
in 2 hours

func ParseByteSize

func ParseByteSize(s string) float64

ParseByteSize parses a human-readable byte size string like `27.61 MiB` or `1.5 GB` into a byte count. Supports both IEC (KiB, MiB, GiB, TiB, PiB, EiB) and SI (KB, MB, GB, TB, PB, EB) units. Returns 0 for empty or unparseable input.

Example
package main

import (
	"fmt"

	"github.com/gechr/x/human"
)

func main() {
	fmt.Printf("%.0f\n", human.ParseByteSize("1.5 GB"))
	fmt.Printf("%.0f\n", human.ParseByteSize("27.61 MiB"))
}
Output:
1500000000
28951183

func ParseDuration

func ParseDuration(s string) (time.Duration, error)

ParseDuration parses a human duration string into a time.Duration. It is the inverse of FormatDuration, accepting decimal values and the units y, w, d, h, m, s, ms, µs (or us), and ns, where a year is 365 days and a week is 7 days. Units may be combined but each may appear at most once and must run in descending order of size. A decimal value must be the final component. An optional leading - negates the result, and `0` parses to zero.

ParseDuration("2h15m")  // 2*time.Hour + 15*time.Minute
ParseDuration("1w2d")   // 9 * 24 * time.Hour
ParseDuration("5.2s")   // 5200 * time.Millisecond
ParseDuration("-1m30s") // -90 * time.Second
Example

ParseDuration is the inverse of human.FormatDuration, accepting the y, w, d, h, m, s, ms, µs, and ns units that function emits.

package main

import (
	"fmt"

	"github.com/gechr/x/human"
)

func main() {
	d, _ := human.ParseDuration("2h15m")
	fmt.Println(d)
	d, _ = human.ParseDuration("1w2d")
	fmt.Println(d)
	d, _ = human.ParseDuration("-1m30s")
	fmt.Println(d)
}
Output:
2h15m0s
216h0m0s
-1m30s

func Plural

func Plural(n int, singular, plural string) string

Plural returns `singular` when `n == 1`, otherwise `plural`. Unlike Pluralize, it omits the count.

Plural(1, "file", "files") // "file"
Plural(3, "file", "files") // "files"
Example
package main

import (
	"fmt"

	"github.com/gechr/x/human"
)

func main() {
	fmt.Println(human.Plural(1, "file", "files"))
	fmt.Println(human.Plural(3, "file", "files"))
}
Output:
file
files

func Pluralize

func Pluralize(n int, singular, plural string) string

Pluralize returns "1 singular" or "n plural".

Pluralize(1, "file", "files") // "1 file"
Pluralize(3, "file", "files") // "3 files"
Example
package main

import (
	"fmt"

	"github.com/gechr/x/human"
)

func main() {
	fmt.Println(human.Pluralize(1, "file", "files"))
	fmt.Println(human.Pluralize(3, "file", "files"))
}
Output:
1 file
3 files

Types

type DurationFormatOptions added in v0.3.8

type DurationFormatOptions struct {
	// Precision is the number of decimal places used for durations below one
	// minute.
	Precision int
	// Round is the rounding granularity. Zero disables pre-format rounding.
	Round time.Duration
	// TrimTrailingZeros removes trailing zeroes from the fractional part.
	TrimTrailingZeros bool
}

DurationFormatOptions controls duration rounding and fractional display.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL