Go
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions and Methods
-
Section 4: Concurrency
-
Section 5: Packages and Tooling
-
Section 6: More Standard Library
-
Section 7: Building Services
-
Section 8: Advanced Go
-
Section 9: Go in the Cloud-Native Ecosystem
-
Section 10: Data Structures and Algorithms in Go
-
Section 11: Testing and Deployment
-
Section 12: Practical Projects
-
Section 13: More Standard Library Practice
-
Section 14: More Practice Projects
-
Section 15: Design Patterns in Go
-
Section 16: Interview Practice
-
Section 17: Package fmt In Depth
-
Section 18: Package strings and strconv
-
Section 19: Package os and io
-
Section 20: Package time
-
Section 21: Package sort and container
-
Section 22: Package encoding
-
Section 23: Package net/http In Depth
-
Section 24: Package context
-
Section 25: Package regexp and bytes
-
Section 26: Package errors In Depth
-
Section 27: Package crypto and hash
-
Section 28: Package flag and log
-
Section 29: Package sync In Depth
-
Section 30: More Practice Exercises
-
Section 31: Go Modules and Workspaces In Depth
-
Section 32: Generics Deep Dive (Go 1.18+)
-
Section 33: Testing Package In Depth
-
Section 34: More Interview and Whiteboard Practice
-
Section 35: Package math and unicode
-
Section 36: Package path and filepath
-
Section 37: Package database/sql
-
Section 38: Package text/template and html/template
-
Section 39: Package archive and compress
-
Section 40: Lower-Level net Package
-
Section 41: Package runtime and reflect
-
Section 42: Package embed and io/fs
-
Section 43: Go Assembly and CGO Basics
-
Section 44: Building CLIs and TUIs
-
Section 45: Go Performance Tuning
-
Section 46: More Real-World Projects
-
Section 47: Go in Production
-
Section 48: Go Design Patterns
-
Section 49: Go Interfaces Deep Dive
-
Section 50: Final Practice and Review
123: Formatting and Parsing Time in Go
I'll be honest: the first time I tried to format a date in Go, I spent twenty minutes staring at the documentation in complete confusion. Coming from Python or C#, I kept looking for the %Y-%m-%d style format strings. I tried to guess the symbols, I tried to find a hidden strftime function, and I felt like I was losing my mind. It turns out, Go does things in a way that feels completely backwards until you realize the logic behind it.
The muscle memory trap
When you're new to Go, your instinct is to treat time formatting as a set of symbolic codes. You might try something like this, thinking you're being clever with string manipulation or searching for a format library:
// This is the "naive" approach: trying to manually slice strings
// or searching for a %Y-%m-%d equivalent that doesn't exist.
timestamp := "2023-10-27 14:30:05"
// I've seen people try to use fmt.Sscanf or manual splitting here
// just to avoid learning the "Go way." It's brittle and slow.
The problem with trying to force C-style formatting into Go is that you'll either end up writing a lot of boilerplate code to slice strings, or you'll spend hours fighting a library that isn't designed for that. The "wrong" way isn't just about the code; it's about fighting the language's design. Go doesn't use symbols because symbols like %M (minute) and %m (month) are too easy to swap by accident, leading to those classic bugs where your logs show the month as the minute.
The magic of the reference date
In Go, you don't use symbols. You use a specific point in time as your layout. If you want to tell Go how to format a date, you show it an example of what that date should look like, using this exact magic date: January 2nd, 3:04:05 PM, 2006, MST (Mountain Standard Time).
I remember the "aha!" moment when I realized why this specific date was chosen. Look at the numbers: 1 (month), 2 (day), 3 (hour), 4 (minute), 5 (second), 6 (year). It's a sequence. Once you memorize that sequence, you stop guessing. To format a date as 2023-10-27, you don't use %Y-%m-%d; you use 2006-01-02.
now := time.Now()
// Instead of symbols, we use the "Layout" string
fmt.Println(now.Format("2006-01-02 15:04:05"))
// Output: 2023-10-27 14:30:05 (depending on current time)
This is significantly more intuitive once it clicks because the layout string is the example. If you want the month name written out, you just write "January" in your layout. If you want a leading zero on the day, you write "02".
Parsing back from strings
Parsing is just the reverse of formatting. You provide the same reference layout to time.Parse, and Go figures out how to map the input string back into a time.Time object. This is where most bugs creep in, usually because of a mismatch between the layout and the actual data.
input := "2023-10-27"
layout := "2006-01-02"
t, err := time.Parse(layout, input)
if err != nil {
// This is where you'll catch the "parsing time ... as ...: cannot parse" errors
log.Fatal(err)
}
One thing to watch out for: time.Parse assumes UTC unless you specify a timezone in the layout or use time.ParseInLocation. I've seen countless production bugs where a developer parsed a local timestamp without specifying the location, and the system suddenly shifted all their appointments by 5 or 8 hours. If you're dealing with user-provided local times, always use ParseInLocation.
When to stop doing it manually
Before you spend time crafting a custom layout, check if what you need is already a standard. Go provides constants like time.RFC3339 (the gold standard for APIs) and time.RFC1123. If you're building a professional API, please, for the love of everything, just use time.RFC3339. It handles the offset and the ISO 8601 standard automatically, saving you from the headache of managing timezone offsets manually.
📋 Practical Task
Exercise: Legacy Log Timestamp Converter
You've been handed a legacy log file where the timestamps are in a very strange, non-standard format: "Jan 02, 2006 03:04PM" (e.g., "Oct 27, 2023 02:30PM"). Your task is to write a function that converts these legacy strings into standard RFC3339 formatted strings.
Requirements:
- Create a function
ConvertLegacyTime(input string) (string, error). - Use
time.Parsewith the correct reference layout to handle the legacy format. - Return the time formatted using the
time.RFC3339constant. - Handle the error case where the input string does not match the legacy format.
Test Case:
Input: "Oct 27, 2023 02:30PM"
Expected Output: A string resembling "2023-10-27T14:30:00Z" (the exact offset may vary based on your local environment, but the format must be RFC3339).
There are no comments for now.