Golang中time.Format方法的使用问题解析

Golang中time.Format方法的使用问题解析 我正在绞尽脑汁,试图理解 time.Format 中一个非常简单的单字符更改。

我查看了这个网站以查看一些格式化示例。如果我使用他们的格式化示例,它可以正常工作;但如果我更改一个地方,它就不行了,我不明白其中的区别。

完整代码:

package main

import (
    "log"
    "time"
)

func main() {

    t := time.Now()
    log.Println(t)

    log.Println("Correct:", t.Format("2006-01-02 15:04:05"))
    log.Println("Weird:", t.Format("2007-01-02 15:04:05"))
}

输出: 2021/07/23 23:44:24 2021-07-23 23:44:24.569482 +0100 BST m=+0.000072078 2021/07/23 23:44:24 Correct: 2021-07-23 23:44:24 2021/07/23 23:44:24 Weird: 23007-07-23 23:44:24

为什么年份差异如此之大?如果我更改年、月、日、小时等,也会发生类似的情况。

非常感谢。


更多关于Golang中time.Format方法的使用问题解析的实战教程也可以访问 https://www.itying.com/category-94-b0.html

9 回复

同意。这可能是我在标准库中最不喜欢的函数!

更多关于Golang中time.Format方法的使用问题解析的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你可以尝试使用 carbon,这是一个简单、语义化且对开发者友好的 Go 语言日期时间处理包。

好的,非常感谢。我已经点击链接,现在明白它的来源了。这不是首先会想到的事情——需要知道那些“魔法数字”才能知道如何格式化日期。

J.

是的——这是 Go 语言中少数几件让我感到困扰的事情之一。使用 MM 与 mm 似乎比完全随机的数字更容易理解,而且这个问题经常出现。此外,在调试方面,对我来说,先使用 MM 来获取月份,然后意识到“哦,对了;应该是 mm”,再修改它,比必须去查找一串魔术数字要容易得多。

啊哈!非常感谢您的及时回复。但我仍然有些困惑。

以年份为例,2006和2007之间有什么区别?它们都是四位数,所以我期望得到的结果是四位数的年份。为什么我得到了五位数?我不明白为什么使用2006作为格式得到的是2021,而使用2007却得到23007。难道2006是那个神奇的数字(而不仅仅是代表4位数字)?

再次感谢。

因为2007不是魔法数字之一。2是表示日期的魔法数字,所以你在“2”的位置得到了“23”,然后,我猜格式化程序不知道如何处理“007”,所以就原样保留了。

编辑: 列出具体数字的Go文档链接:https://pkg.go.dev/time#Parse

日期组件都是魔数。与大多数编程语言使用诸如“yy”、“yyyy”、“MM”、“MMM”等表示方式不同,Go 决定使用魔数来表示日期格式。要在 Go 中获得两位数的年份格式,请使用“06”;要获得四位数的年份,请使用“2006”。要获得12小时制的小时,请使用“03”或“3”。要使其成为24小时制,请使用“15”,等等。

我怀疑这原本是为了比记住“mm 是月份而 MM 是分钟,还是反过来?”更容易。然而,似乎每个人(包括我自己!)都会感到困惑,所以我认为他们并没有完全做对。

感谢您的提示。我可能会尝试一下。在必要时我会使用第三方包。

我打算在这里写一些可能具有争议性的内容,您自己也提到了:如果我需要使用第三方包来获得“对开发者友好”的日期和时间函数,那么根据定义,内置函数就是“对开发者不友好”的。我认真考虑了 skillian 关于 MM 和 mm 混淆的论述——我自己这些年来也犯过好几次这样的错误,事后才意识到我用了月份而不是分钟,或者反之,然后改正了。这很容易出错,也同样容易纠正。如果不了解所使用的那些“魔法数字”,我绝不会想到 2007 和 2006 有如此大的不同。

我算不上你们所说的那种严肃的开发者,我只是随便玩玩。我发现 Go 语言非常容易上手,没有遇到任何严重问题,只有学习新事物时常见的那些典型困难。这是我第一次遇到一些我会描述为“奇怪”和“他们为什么要那样做?”的事情。

非常感谢, J.

在Go语言的time.Format方法中,格式化字符串使用固定的参考时间2006-01-02 15:04:05来定义格式。这个时间点不是任意的,而是Go语言设计者选择的特定时间,用于表示格式化的各个部分:

  • 2006 代表年份
  • 01 代表月份
  • 02 代表日期
  • 15 代表小时(24小时制)
  • 04 代表分钟
  • 05 代表秒

当您将年份部分从2006改为2007时,解析器会将2007识别为不同的格式代码,导致年份解析错误。实际上,2007中的每个数字都被单独解析:

  • 2 被解析为年份的最后一位
  • 0 被解析为年份的十位
  • 0 被解析为年份的百位
  • 7 被解析为年份的千位

这导致了年份显示为23007的奇怪结果。下面是一个更清晰的示例:

package main

import (
    "fmt"
    "time"
)

func main() {
    t := time.Now()
    
    // 正确的格式化
    fmt.Println("正确格式:", t.Format("2006-01-02 15:04:05"))
    
    // 修改年份部分会导致解析错误
    fmt.Println("错误格式1:", t.Format("2007-01-02 15:04:05"))
    fmt.Println("错误格式2:", t.Format("2005-01-02 15:04:05"))
    
    // 其他部分的修改也会导致问题
    fmt.Println("错误月份:", t.Format("2006-13-02 15:04:05"))
    fmt.Println("错误分钟:", t.Format("2006-01-02 15:14:05"))
}

输出示例:

正确格式: 2024-07-23 10:30:45
错误格式1: 42007-07-23 10:30:45
错误格式2: 52005-07-23 10:30:45
错误月份: 2024-13-02 10:30:45
错误分钟: 2024-01-02 10:14:45

关键点:必须严格使用2006-01-02 15:04:05这个参考时间的各个部分作为格式字符串的占位符。任何修改都会改变解析规则,导致意外的输出结果。

回到顶部