Go源码解析之format.go(1)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Go源码解析之format.go(1)

File: format.go

format.go 文件是 Go 语言标准库 time 包中用于时间格式化的核心文件。该文件定义了两个重要结构体:TimeFormatter,以及一系列支持时间格式化的函数和变量。

Time 结构体用于表示时区无关的时间,其包含一个 int64 类型字段,表示从 Unix 纪元起至今的纳秒数。Time 结构体支持一系列方法,如 FormatAddSub 等,可用于格式化时间、增加或减少时间等操作。

Formatter 结构体用于定义时间格式化的规则,其包含一个字符串字段 layout,表示时间格式化的模板。Formatter 结构体支持一系列方法,如 FormatParse 等,可用于将时间格式化为指定格式的字符串,或将指定格式的字符串解析成时间。

除了上述结构体之外,format.go 文件还定义了一些常量和变量,如 ANSICRFC822RFC1123 等常用的时间格式化模板,以及 nanosecondmicrosecondmillisecond 等常用时间单位的常量。

总之,format.go 文件是 Go 语言中时间格式化的核心组成部分,它实现了一系列重要的结构体、函数和变量,为 Go 语言中时间处理提供了强大的支持和便利。


Var:

std0x

在 Go 语言的 time 包中,std0x 这个变量是一个用来存储标准格式字符串(如 "2006-01-02T15:04:05Z07:00")中前缀 0x(用于表示十六进制)的位置索引。它的作用是用于处理十六进制的时间格式化。

标准的时间格式化是通过根据给定的时间模板字符串来格式化时间,如 "2006-01-02 15:04:05" 就是一个时间模板字符串。但是对于一些特殊的时间格式,如十六进制,需要单独处理。

在 Go 语言的 time 包中,如果时间字符串中包含 0x,就会将其作为十六进制时间格式化。例如,"0x1f" 表示的是时间戳为 31 秒的时间。

std0x 变量就是用来帮助处理这种特殊的时间格式。它存储标准格式字符串中前缀 0x 的位置索引,用于找到时间字符串中的 0x 并将其解析为十六进制的时间格式。

longDayNames

在 Go 语言的 time 包中,longDayNames 变量是一个切片,用于存储星期的全称(即 Sunday、Monday 等的完整拼写)。这个变量的作用是在日期格式化时使用,这些名称可以用字符串中的“Weekday”转换器来表示。日期中的“Monday”之类的名字以及其对应的“星期一”的全称就需要通过这个变量来转换。同时,在 time 包中的其他子模块中,也可能会使用这个变量来进行星期转换。

在 format.go 文件中,longDayNames 变量的定义如下:

var longDayNames = []string{
    "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday",
}

在进行日期格式化时,如果遇到了 %A 字符串,就会根据当前日期的星期数,从 longDayNames 的对应位置获取对应的星期全称,然后插入到格式化字符串中输出。例如,格式化字符串为 %A, %B %d, 对于日期 2022-08-15,输出结果为 Monday, August 15。在这个输出结果中,%A 转换器返回的是 Monday,而不是 1time.Weekday() 方法的返回值)或其他任何数字,这是因为 longDayNames 提供了对应的星期全称。

shortDayNames

在Go语言的time包中,shortDayNames变量存储了一周中每天的缩写名称列表,例如“Mon”表示星期一,“Tue”表示星期二等等。这个变量的作用是帮助格式化日期时间字符串时快速获取星期几的缩写名称。

在Go中,有一些日期时间格式符用于获取星期几,例如“%a”用于获取星期几的缩写名称,“%A”用于获取星期几的全称。当我们使用这些格式符进行日期时间格式化时,依赖于shortDayNames变量来获取每天的缩写名称。

shortDayNames变量由time package中的init函数初始化,并在全局范围内使用。在运行时,可以提高性能,避免每次调用format函数时重新初始化一遍shortDayNames变量。

总之,shortDayNames变量是time包中用于获取星期几缩写名称的重要变量,它使得格式化日期字符串更加高效和简便。

shortMonthNames

shortMonthNames 是 time 包中的一个变量,它是一个长度为 12 的字符串切片,表示每个月份的缩写名称。

shortMonthNames 的作用是为时间格式化提供了一些预定义的月份缩写名称,例如在使用 time.Time.Format 方法将时间格式化为字符串时,可以使用 "Jan" 表示一月,而不需要手动定义。简化了用户的工作,提高了程序的可读性和可维护性。

除此之外,shortMonthNames 还被用于其他一些时间处理函数和方法中,例如 ParseInLocation 方法,根据 shortMonthNames 可以进行月份的解析和比较。

longMonthNames

在go/src/time中的format.go文件中,longMonthNames保存了一个包含12个字符串的切片,分别表示一年中12个月份的全称名称,以英文表示。这个变量的作用是在格式化时间字符串时,用于确定时间字符串中月份的完整名称,以便与其他部分相组合,形成规范的时间字符串表示。

例如,我们可以使用Go语言的time 包中的Format函数将一个time.Time类型的时间变量转换为字符串,如下所示:

t := time.Now()
str := t.Format("2006年01月02日 15:04:05 Mon Jan")

在这个例子中,我们传入了一个格式化字符串“2006年01月02日 15:04:05 Mon Jan”,其中“Mon”的位置就是月份名称的完整表示,而“Jan”的位置则是月份名称的缩写表示。这时候,format.go文件中的longMonthNames变量就会派上用场,它通过被定义的顺序,与time包实际使用位置相对应,正确地找到并设置了每个月份的完整名称,从而生成了正确的时间字符串。

因此,longMonthNames变量在go/src/time/format.go文件中是非常重要的,它保证了在各种不同的情况下,time包可以正确地处理并输出规范的时间字符串。

errAtoi

在Go语言的time包中,format.go文件中的errAtoi变量是一个错误对象,该对象用于在转换字符串为数字时发生错误时返回给调用者一个错误信息。它是一个全局变量,只会在第一次访问时初始化,并在后续的调用中重用,以提高代码执行效率。

当进行字符串到整数的转换时,通过在字符串中进行迭代,并将每个字符逐个转换为数字,并将其乘以10,将多个数字组合成一个整数。如果在此过程中出现了非数字字符或无法转换的字符,errAtoi将被设置为一个错误对象,并返回给调用者一个错误信息。

对于开发人员来说,如果使用errAtoi变量,可以在发生错误时对其进行判断,并进行相应的异常处理,以提高代码的健壮性和可靠性。

errBad

errBad是time包中的一个变量,其作用是表示时间格式化字符串中存在不支持的占位符时返回的错误信息。

在format.go中,定义了多个时间格式化字符串中可以使用的占位符,如2006表示年份,01表示月份等。如果使用了不支持的占位符,比如使用了Q表示季节,就会返回errBad错误信息。

这个错误信息可以帮助开发者发现并纠正在使用时间格式化字符串时存在的错误,提高时间处理的准确性和可靠性。

errLeadingInt

在 Go 语言的 time 包中,format.go 文件是用于时间格式化的辅助函数集合。errLeadingInt 是此文件中的一个变量。

errLeadingInt 是一个错误类型,用于表示在格式化时间字符串时,出现了不合法的整型数字前缀。例如,格式化字符串中出现了超过了合法值范围的小时数或月份,如 "13:05" 或 "2021-13-01",都会被认为是不合法的整型数字前缀。对于这种情况,time 包会返回一个 errLeadingInt 错误,以提示用户时间格式化字符串中的错误。

在 time 包中,可以通过使用 Format 方法对时间进行格式化,例如:

t := time.Now()
fmt.Println(t.Format("2006-01-02 15:04:05"))

在这个例子中,使用了 "2006-01-02 15:04:05" 这个字符串作为时间格式化字符串,代表的含义为 "年-月-日 时:分:秒"。如果此时使用错误的格式化字符串,例如 "2006-13-02 15:04:05",那么在 Format 方法中将会返回一个 errLeadingInt 错误。

总之,errLeadingInt 变量的作用是用于表示在 time 包中格式化时间字符串时,出现了不合法的整型数字前缀的错误类型。

unitMap

在 Go 语言中,time 包中的 format.go 文件中定义了一个名为 unitMap 的变量,它是一个 map 类型,用来将时间格式字符串中的字符映射到对应的时间单位。

时间格式字符串中包含了很多类似于 %Y、%m、%d、%H、%M、%S 这样的字符,它们代表了年、月、日、小时、分钟和秒等时间单位。unitMap 变量就是用来将这些字符映射到 Go 语言中对应的时间单位的。

在代码中,我们可以看到 unitMap 变量的定义和初始化过程:

var unitMap = map[byte]int{
    'Y': int(_year),
    'M': int(_month),
    'D': int(_day),
    'h': int(_hour),
    'm': int(_minute),
    's': int(_second),
    'f': int(_fractions),
    'z': int(_zone),
}

在这个 map 中,每个键值对都是由一个表示时间单位的枚举值和一个整数值组成的。

具体来说,比如对于字符 'Y',它的值是 int(_year),_year 是一个枚举值,表示时间单位 year,它在代码中的定义是这样的:

type _Month int
const (
    ...
    _year _Month = iota + 1
    ...
)

因此,当解析时间格式字符串时,如果遇到字符 'Y',就可以通过 unitMap 将其映射到 Go 语言中对应的时间单位 year 上。

这样,我们就可以使用类似于这样的代码将时间格式字符串解析成时间对象:

t, err := time.Parse("2006-01-02 15:04:05", "2021-03-15 14:30:00")

在这个例子中,我们将时间格式字符串 "2006-01-02 15:04:05" 解析成了一个时间对象,这个字符串中包含了很多类似于 %Y、%m、%d、%H、%M、%S 这样的字符,它们对应的时间单位都可以通过 unitMap 来映射到 Go 语言中的具体时间单位。


Structs:

ParseError

ParseError是time包中定义的一个结构体,用于表示时间解析过程中的错误信息。该结构体包含三个字段:Layout、Value和Msg。具体介绍如下:

  1. Layout:表示时间格式化字符串。该字段是一个字符串类型,用于存储时间格式化字符串。在时间解析过程中如果发现Layout与时间字符串不匹配,就会抛出ParseError。
  2. Value:表示无法解析的时间字符串。该字段是一个字符串类型,用于存储无法解析的时间字符串。
  3. Msg:表示错误信息。该字段是一个字符串类型,用于存储错误信息。在抛出ParseError时会使用Msg参数指定的错误信息。Msg参数可以使用fmt.Sprintf()函数格式化输出错误信息。

在time包中,当使用Parse()或者ParseInLocation()方法解析时间字符串时,如果发生解析错误(如时间字符串格式不正确),就会返回一个ParseError类型的错误。可以通过对该错误类型进行断言,获取到具体的错误信息,并进行相应的处理。

总的来说,ParseError结构体的作用是方便开发者捕捉时间解析过程中的错误,以及提供错误信息,方便开发者进行相应的处理。

Functions:

startsWithLowerCase

在 Go 语言中,以小写字母开头的标识符是私有成员,只能在同一个包中被访问。startsWithLowerCase 这个函数是一个私有函数,作用是判断一个字符串是否以小写字母开头。

在 time 包中,startsWithLowerCase 函数主要用于将给定的格式化字符串解析为时间格式化对象。格式化字符串是一种定义日期和时间如何显示的模式,例如 “2006-01-02 15:04:05.999999999 MST”。这个函数会检查格式化字符串的每个字符,如果该字符是小写字母,则表示需要进行填充或者其他操作,否则表示该字符为固定文本。

通过判断字符串是否以小写字母开头,startsWithLowerCase 函数可以帮助解析器确定时间格式化字符串的各个部分,进而生成标准的时间格式化对象。这样可以确保时间的正确性和统一性,提高代码的可读性和维护性。

nextStdChunk

在Go语言中,time包是一个重要的包,其中的format.go文件中提供了格式化时间的功能。在这个文件中,nextStdChunk这个函数用于解析格式化时间字符串中的下一个标准块(standard chunk)。

标准块是指格式化时间字符串中由连续的相同字符组成的部分。例如,格式化时间字符串"2006/01/02 15:04:05"中的"2006"、"/"、"01"、"/"、"02"、" "、"15"、":"、"04"、":"、"05"就是标准块。

nextStdChunk函数的作用是找到格式化时间字符串中的下一个标准块,并返回该标准块。如果该标准块在字符串中的位置是奇数,则需要返回该标准块的前一个字符,因为在格式化时间字符串中,标准块总是从偶数位置开始的。

在函数内部,首先会检查当前解析位置是否已经到达字符串的结尾,如果是,则返回空字符串。然后,函数会从当前解析位置开始,向后查找连续的相同字符,直到找到一个不同的字符或者到达字符串的结尾为止。最后,函数会将找到的标准块返回,并更新解析位置,以便下一次解析可以从正确的位置开始。

总的来说,nextStdChunk函数的作用是分析格式化时间字符串,找到其中的标准块,并返回这些标准块的内容。这个函数是time包中解析时间格式化字符串的核心函数之一。

match

在 Go 语言的 time 包中,match 函数的作用是实现字符格式的匹配。在该函数内部,它会将给定的格式串与内部的时间格式模板进行匹配,得到不同时间部分的格式化字符串。如果格式字符串匹配成功,则输出与 t 时刻匹配的格式化字符串,否则返回空字符串。

具体来说,match 函数在匹配格式字符串的同时会收集不同时间部分的格式化字符串,对于每个时间段,它会创建一个 flags 类型的变量用于记录该时间段的匹配状态。同时,如果匹配成功,则匹配函数还会将相对应的时间值存储在相应的 time.Time 对象中。在整个匹配结束后,match 函数会扫描 flags 对象,确定所匹配的时间部分是否完整。如果所有时间部分都已成功匹配,则 match 函数返回 true,否则返回 false。

总之,match 函数提供了一种将时间格式字符串转换为 time.Time 对象的方法,使得用户能够部分或完整地解析和格式化时间信息。在实际应用中,它非常适用于解析和验证用户输入的时间数据。

lookup

在Go语言标准库的time包中,format.go文件中的lookup函数是用来查找日期格式化占位符的。它的具体作用是将给定的字符r作为日期格式化占位符查找其对应的解释器函数(例如%Y对应Year函数,%m对应Month函数等),并返回该函数的索引位置。

lookup函数的定义如下:

func lookup(r rune) int { for i, rr := range rmap { if rr == r { return i } } return -1 }

其中,rmap是一个字符数组,存储了所有支持的日期格式化占位符,例如:

var rmap = []rune{ ' ', '!', '"', '#', '$', '%', '&', ''', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', }

在lookup函数中,使用for循环遍历rmap数组,将r作为参数传入,查找与之对应的解释器函数,如果找到则返回该函数的索引位置,否则返回-1。

此外,lookup函数还可以用于判断一个字符是否为支持的日期格式化占位符,例如:

if lookup(r) == -1 { // r不是支持的日期格式化占位符 // 进行相应处理 }

总之,lookup函数在格式化时间时起到了非常重要的作用,它的作用是将输入的日期格式化占位符与其对应的解释器函数进行匹配,从而实现对日期格式化的处理。

appendInt

在go/src/time中的format.go文件中,appendInt函数的作用是将integer类型的数字按照指定进制转换成字符串,并在输出字符串后面追加到buf中。

该函数首先检查进制是否有效,如果无效则返回错误;然后,它用指定进制将数字转换为字符串,并将其附加到buf缓冲区的末尾。

如果指定的进制是10,则该函数会检查是否需要添加负号,并将整数转换为十进制字符串。如果指定的进制不是10,则该函数会将整数转换为无符号整数,并使用指定的进制将其转换为字符串。

最后,如果该函数成功将数字转换为字符串,则返回转换后的字符串的长度。如果出现错误,则返回-1。

atoi

在go/src/time中,format.go文件中的atoi函数作用是将字符串转换为整数。在时间格式中,我们会使用一些数字来表示年、月、日、时、分、秒等信息,因此我们需要将字符串转换为整数来获取这些信息。

函数签名为:

func atoi(s string) (n int, ok bool)

参数s为需要转换的字符串,返回值有两个,一个是转换后的整数n,另一个是转换是否成功的标志ok。

该函数的实现方法如下:

func atoi(s string) (n int, ok bool) {
    for _, c := range []byte(s) {
        if '0' <= c && c <= '9' {
            n = n * 10 + int(c-'0')
        } else {
            return 0, false
        }
    }
    return n, true
}

函数首先将字符串s转换为byte类型的切片,然后遍历切片中的每一个字符。如果该字符是数字字符,将其转换为数值并加到n变量上(实现了字符串到整数的转换),否则表示该字符串不能被正确转换,返回失败标志false和0。最后返回成功标志和转换后的整数。

注意,该函数不支持带符号的字符串转换,只能处理无符号整数的字符串转换。如果需要支持带符号字符串的转换,则可以使用strconv.Atoi函数。


目录
相关文章
|
4天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
4天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
4天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
28天前
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
55 12
|
23天前
|
PyTorch Shell API
Ascend Extension for PyTorch的源码解析
本文介绍了Ascend对PyTorch代码的适配过程,包括源码下载、编译步骤及常见问题,详细解析了torch-npu编译后的文件结构和三种实现昇腾NPU算子调用的方式:通过torch的register方式、定义算子方式和API重定向映射方式。这对于开发者理解和使用Ascend平台上的PyTorch具有重要指导意义。
|
5天前
|
安全 搜索推荐 数据挖掘
陪玩系统源码开发流程解析,成品陪玩系统源码的优点
我们自主开发的多客陪玩系统源码,整合了市面上主流陪玩APP功能,支持二次开发。该系统适用于线上游戏陪玩、语音视频聊天、心理咨询等场景,提供用户注册管理、陪玩者资料库、预约匹配、实时通讯、支付结算、安全隐私保护、客户服务及数据分析等功能,打造综合性社交平台。随着互联网技术发展,陪玩系统正成为游戏爱好者的新宠,改变游戏体验并带来新的商业模式。
|
1月前
|
存储 Go PHP
Go语言中的加解密利器:go-crypto库全解析
在软件开发中,数据安全和隐私保护至关重要。`go-crypto` 是一个专为 Golang 设计的加密解密工具库,支持 AES 和 RSA 等加密算法,帮助开发者轻松实现数据的加密和解密,保障数据传输和存储的安全性。本文将详细介绍 `go-crypto` 的安装、特性及应用实例。
80 0
|
JSON Prometheus Cloud Native
go解析Prometheus的数据
访问一个api, 返回如下数据: {"status":"success","data":{"resultType":"matrix","result":[{"metric":{},"values":[[1473820558.
2597 0
|
3天前
|
存储 监控 算法
员工上网行为监控中的Go语言算法:布隆过滤器的应用
在信息化高速发展的时代,企业上网行为监管至关重要。布隆过滤器作为一种高效、节省空间的概率性数据结构,适用于大规模URL查询与匹配,是实现精准上网行为管理的理想选择。本文探讨了布隆过滤器的原理及其优缺点,并展示了如何使用Go语言实现该算法,以提升企业网络管理效率和安全性。尽管存在误报等局限性,但合理配置下,布隆过滤器为企业提供了经济有效的解决方案。
31 8
员工上网行为监控中的Go语言算法:布隆过滤器的应用
|
23天前
|
存储 Go 索引
go语言中数组和切片
go语言中数组和切片
37 7

推荐镜像

更多