strings and time
strings Package
Section titled “strings Package”The strings package provides functions for manipulating UTF-8 encoded strings. Strings in Go are immutable byte slices — all operations return new strings rather than modifying in place.
Searching
Section titled “Searching”strings.Contains("hello world", "world") // truestrings.HasPrefix("hello", "hel") // truestrings.HasSuffix("hello", "llo") // truestrings.Index("hello", "ll") // 2strings.LastIndex("hello", "l") // 3strings.Count("hello", "l") // 2Index returns -1 if the substring is not found. Count counts non-overlapping occurrences.
Splitting and Joining
Section titled “Splitting and Joining”parts := strings.Split("a,b,c", ",") // ["a", "b", "c"]parts := strings.SplitN("a,b,c", ",", 2) // ["a", "b,c"]result := strings.Join(parts, "-") // "a-b-c"fields := strings.Fields(" hello world ") // ["hello", "world"]SplitN limits the number of splits. Fields splits on whitespace and discards empty strings.
Trimming and Case
Section titled “Trimming and Case”strings.TrimSpace(" hello ") // "hello"strings.Trim("!!!hello!!!", "!") // "hello"strings.TrimPrefix("hello", "hel") // "lo"strings.TrimSuffix("hello", "llo") // "hel"strings.ToUpper("hello") // "HELLO"strings.ToLower("HELLO") // "hello"Replace and Repeat
Section titled “Replace and Repeat”strings.Replace("foo bar foo", "foo", "baz", 1) // "baz bar foo"strings.ReplaceAll("foo bar foo", "foo", "baz") // "baz bar baz"strings.Repeat("ab", 3) // "ababab"Replace takes a count argument — -1 replaces all occurrences (same as ReplaceAll).
strings.Builder
Section titled “strings.Builder”For efficient string concatenation in loops, use strings.Builder instead of repeated +=:
var b strings.Builderfor _, s := range items { b.WriteString(s) b.WriteByte(",')}result := b.String()Builder avoids allocating a new string on each concatenation. Grow(n) pre-allocates capacity:
var b strings.Builderb.Grow(1000)for _, s := range items { b.WriteString(s)}strconv Package
Section titled “strconv Package”The strconv package converts between strings and other types:
n, err := strconv.Atoi("42") // int 42s := strconv.Itoa(42) // "42"s := strconv.FormatBool(true) // "true"s := strconv.FormatInt(-42, 10) // "-42"s := strconv.FormatInt(255, 16) // "ff"s := strconv.FormatFloat(3.14, 'f', 2, 64) // "3.14"
f, err := strconv.ParseFloat("3.14", 64) // 3.14i, err := strconv.ParseInt("ff", 16, 64) // 255
s := strconv.Quote("hello \"world\"") // "hello \"world\""s, err := strconv.Unquote(`"hello"`) // "hello"Atoi is shorthand for ParseInt(s, 10, 0). Always check the returned error.
time Package
Section titled “time Package”Creating and Reading time.Time
Section titled “Creating and Reading time.Time”t := time.Now() // current local timet := time.Date(2026, 5, 30, 14, 30, 0, 0, time.UTC)
fmt.Println(t.Year()) // 2026fmt.Println(t.Month()) // Mayfmt.Println(t.Day()) // 30fmt.Println(t.Hour()) // 14fmt.Println(t.Minute()) // 30fmt.Println(t.Second()) // 0fmt.Println(t.Unix()) // seconds since epochfmt.Println(t.UnixNano()) // nanoseconds since epochfmt.Println(t.Weekday()) // Saturdayfmt.Println(t.IsZero()) // falseParsing
Section titled “Parsing”layout := "2006-01-02 15:04:05"t, err := time.Parse(layout, "2026-05-30 14:30:00")Go uses a reference date for layout strings. The reference date is Mon Jan 2 15:04:05 MST 2006 (which is 01/02 03:04:05 PM 06 -0700 in a more memorable form). Each component determines how the corresponding value is interpreted.
Common layouts:
time.RFC3339 // "2006-01-02T15:04:05Z07:00"time.RFC3339Nano // "2006-01-02T15:04:05.999999999Z07:00"time.RFC1123 // "Mon, 02 Jan 2006 15:04:05 MST"time.Kitchen // "3:04PM"time.RubyDate // "2006-01-02 15:04:05 -0700"time.UnixDate // "Mon Jan 2 15:04:05 MST 2006"Formatting
Section titled “Formatting”t := time.Now()fmt.Println(t.Format(time.RFC3339)) // "2026-05-30T14:30:00Z"fmt.Println(t.Format("2006-01-02")) // "2026-05-30"fmt.Println(t.Format("Jan _2, 2006")) // "May 30, 2026"fmt.Println(t.Format("15:04:05")) // "14:30:00"Duration
Section titled “Duration”time.Duration is an int64 representing nanoseconds. Constants help construct durations:
d := 2 * time.Hour + 30 * time.Minute // 2h30m0sd := time.Millisecond * 500 // 500msd := time.Duration(5) * time.Second // 5s
fmt.Println(d) // "2h30m0s"fmt.Println(d.Hours()) // 2.5fmt.Println(d.Minutes()) // 150fmt.Println(d.Seconds()) // 9000fmt.Println(d.Milliseconds()) // 9000000Time Arithmetic
Section titled “Time Arithmetic”t := time.Now()future := t.Add(24 * time.Hour) // 24 hours from nowpast := t.Add(-24 * time.Hour) // 24 hours ago
diff := future.Sub(t) // 24h0m0sfmt.Println(diff.Hours()) // 24
t1 := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)t2 := time.Date(2026, 12, 31, 0, 0, 0, 0, time.UTC)t1.Before(t2) // truet1.After(t2) // falset2.Equal(t1) // false
since := time.Since(t1) // duration since t1until := time.Until(t2) // duration until t2Timers and Tickers
Section titled “Timers and Tickers”time.Timer
Section titled “time.Timer”A Timer fires once after a specified duration:
timer := time.NewTimer(2 * time.Second)<-timer.C // blocks for 2 seconds, then receives the current timeStop a timer before it fires:
timer := time.NewTimer(5 * time.Second)stopped := timer.Stop()if stopped { fmt.Println("timer was stopped before firing")}If the timer has already fired or been stopped, Stop() returns false. Always drain the channel if Stop() returns false:
if !timer.Stop() { <-timer.C}time.Ticker
Section titled “time.Ticker”A Ticker fires repeatedly at a fixed interval:
ticker := time.NewTicker(1 * time.Second)defer ticker.Stop()
for i := 0; i < 5; i++ { <-ticker.C fmt.Println("tick", time.Now().Format("15:04:05"))}Always stop tickers with defer ticker.Stop() to prevent goroutine leaks.
time.After and time.AfterFunc
Section titled “time.After and time.AfterFunc”// After: fires once, returns a channel<-time.After(2 * time.Second) // blocks for 2 seconds
// AfterFunc: fires once, calls a functiontimer := time.AfterFunc(2*time.Second, func() { fmt.Println("2 seconds elapsed")})timer.Stop() // canceltime.After is convenient but note that it creates a timer that is not garbage-collected until it fires. Avoid time.After in tight loops — use time.NewTimer instead.
Time Zones
Section titled “Time Zones”loc, err := time.LoadLocation("America/New_York")if err != nil { log.Fatal(err)}
t := time.Date(2026, 5, 30, 14, 30, 0, 0, loc)fmt.Println(t) // 2026-05-30 14:30:00 -0400 EDT
utc := t.UTC() // convert to UTClocal := t.Local() // convert to localback := utc.In(loc) // convert to specific locationtime.UTC is a pre-defined location for UTC. time.Local is the system’s local time zone.
Comparisons: always compare times in the same zone. Equal compares the absolute instant regardless of location:
t1 := time.Date(2026, 5, 30, 14, 0, 0, 0, time.UTC)t2 := time.Date(2026, 5, 30, 10, 0, 0, 0, loc) // same instant, different zonet1.Equal(t2) // trueIntuition
Section titled “Intuition”Strings are just byte sequences with UTF-8 encoding: Think of a Go string as an immutable array of bytes that happens to be encoded in UTF-8. The strings package gives you tools to manipulate these bytes, searching, splitting, trimming, and converting case. Time handling is about parsing and formatting these byte representations of dates and times.
Why it matters: String manipulation is fundamental to data processing, parsing, and formatting. Understanding Go’s string handling (UTF-8 aware, immutable) prevents bugs like assuming strings are arrays of characters. Time handling is essential for logging, scheduling, and data processing.
The key insight: Go strings are immutable, every string operation creates a new string. For heavy string concatenation in loops, use strings.Builder to avoid quadratic allocation.
Common Pitfalls
Section titled “Common Pitfalls”Using += for string concatenation in loops. Each
+=allocates a new string. Usestrings.Builderfor repeated concatenation.Not checking strconv errors.
AtoiandParseIntreturn errors for invalid input. Ignoring the error yields a zero value, which can silently corrupt data.Using the wrong layout string for time.Parse. The layout must use the reference date
2006-01-02 15:04:05. Using other values (e.g.,2015-01-02) causes incorrect parsing.Comparing times with ==. Use
t1.Equal(t2)instead. Twotime.Timevalues in different locations representing the same instant are not==butEqualreturnstrue.Leaking timers and tickers.
time.NewTimerandtime.NewTickercreate resources that must be stopped. Failing to callStop()leaks a goroutine. Always usedefer.Using time.After in a loop. Each call creates a new timer that cannot be stopped. In a loop, this leaks timers. Use
time.NewTimerwithStop()instead.Ignoring time zone in parsing.
time.Parsewithout a time zone offset produces a time with no location (UTC +0). Usetime.ParseInLocationwhen the input has a known time zone but no offset:
loc, _ := time.LoadLocation("America/New_York")t, _ := time.ParseInLocation("2006-01-02 15:04", "2026-05-30 14:30", loc)Summary
Section titled “Summary”This topic covers the core concepts of strings and time in Go, including underlying theory, practical implementation, and key applications.
Key concepts include:
- string manipulation and efficient concatenation
- type conversions with strconv
- time parsing, formatting, and arithmetic
- timers, tickers, and time zones
- common pitfalls and best practices
Worked Examples
Section titled “Worked Examples”Cross-References
Section titled “Cross-References”- I/O: File and stream operations that work with string data.
- Net/HTTP: HTTP client and server that use string and time utilities.
- Basics: Fundamental Go concepts including string and time types.