
go 的 time.format() 不支持自动添加日期序数后缀(如 “1st”“2nd”),需手动拼接后缀逻辑,再结合标准布局字符串完成格式化。
在 Go 中,time.Format() 严格遵循预定义的参考时间(Mon Jan 2 15:04:05 MST 2006)进行布局解析,它不支持动态文本替换(例如 "2nd" 中的 "nd" 并非占位符,而是字面量)。因此,直接使用 "Monday 2nd January" 会导致 2 被固定渲染为字面字符 "2",而后缀 "nd" 始终原样输出,无法随日期变化——这正是示例中 4nd 和 1nd 错误结果的根源。
要实现符合英语习惯的“verbose date”(如 Wednesday 4th March 或 Sunday 1st March),必须将日期序数后缀(st/nd/rd/th)动态计算并注入格式字符串中。以下是一个简洁、健壮的实现:
func formatVerboseDate(t time.Time) string {
day := t.Day()
var suffix string
switch {
case day%100 >= 11 && day%100 <= 13:
suffix = "th" // 11th, 12th, 13th are special cases
case day%10 == 1:
suffix = "st"
case day%10 == 2:
suffix = "nd"
case day%10 == 3:
suffix = "rd"
default:
suffix = "th"
}
// 使用 Format 拼接:先用 "2" 占位日,再替换为带后缀的完整日字符串
base := t.Format("Monday 2 January 2006")
return strings.Replace(base, " 2 ", fmt.Sprintf(" %d%s ", day, suffix), 1)
}✅ 注意:上述实现使用 strings.Replace(..., 1) 精确替换第一个 " 2 "(含空格),避免误替其他数字;同时正确处理了英语中的特殊规则:11–13 日统一用 "th"(即 11th, 12th, 13th),而非 11st。
更推荐的无依赖写法(不引入 strings 包)是直接构造字符串:
func formatVerboseDate(t time.Time) string {
day := t.Day()
var suffix string
switch {
case day%100 >= 11 && day%100 <= 13:
suffix = "th"
case day%10 == 1:
suffix = "st"
case day%10 == 2:
suffix = "nd"
case day%10 == 3:
suffix = "rd"
default:
suffix = "th"
}
return fmt.Sprintf("%s %d%s %s %d",
t.Weekday().String(),
day,
suffix,
t.Month().String(),
t.Year(),
)
}该函数输出完全可控,例如:
- time.Date(2025, 3, 1, 0, 0, 0, 0, time.UTC) → "Sunday 1st March 2025"
- time.Date(2025, 3, 11, 0, 0, 0, 0, time.UTC) → "Tuesday 11th March 2025"
- time.Date(2025, 3, 22, 0, 0, 0, 0, time.UTC) → "Friday 22nd March 2025"
? 总结:Go 标准库不提供序数日期格式化能力,但通过组合 t.Day()、条件判断与 fmt.Sprintf(),可轻松、高效、可读地实现符合本地化习惯的 verbose date 输出。关键在于理解 time.Format() 的静态布局本质,并主动承担动态部分的逻辑。










