human

package
v0.2.17 Latest Latest
Warning

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

Go to latest
Published: Jul 11, 2026 License: MIT Imports: 9 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) string

FormatDuration formats d as up to two adjacent units with no separator (e.g. "2h15m", "1w2d", "1y5w"). Years are 365 days, weeks are 7 days. Durations >= 1s are rounded to the nearest second.

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"
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))

Output:

1m30s
2h15m
1y5w
50ms

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 the units that function emits: 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, so "1y2w", "2h15m", and "90s" are valid while a repeated ("5w5w") or out-of-order ("1w1y") unit is an error. 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("-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

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) string

FormatDuration formats `d` as up to two adjacent units with no separator (e.g. "2h15m", "1w2d", "1y5w"). Years are 365 days, weeks are 7 days. Durations >= 1s are rounded to the nearest second.

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"
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))
}
Output:
1m30s
2h15m
1y5w
50ms

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 the units that function emits: 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, so "1y2w", "2h15m", and "90s" are valid while a repeated ("5w5w") or out-of-order ("1w1y") unit is an error. 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("-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

This section is empty.

Jump to

Keyboard shortcuts

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