[TOC]
0x00 引言说明
描述: 我们进行Go语言编程之中当遇到不熟悉的内置函数时, 可以采用go doc builtin [builtinFunName]
查看go语言内置函数。
[TOC]
描述: 我们进行Go语言编程之中当遇到不熟悉的内置函数时, 可以采用go doc builtin [builtinFunName]
查看go语言内置函数。
[TOC]
描述: 我们进行Go语言编程之中当遇到不熟悉的内置函数时, 可以采用go doc builtin [builtinFunName]
查看go语言内置函数。1
2
3
4
5
6
7package builtin // import "builtin"
func println(args ...Type)
The println built-in function formats its arguments in an
implementation-specific way and writes the result to standard error. Spaces
are always added between arguments and a newline is appended. Println is
useful for bootstrapping and debugging; it is not guaranteed to stay in the language.
或者参考【Golang标准库文档】:https://studygolang.com/pkgdoc
描述: 本文介绍了fmtb包的一些常用函数。
fmt 包 : fmt包实现了类似C语言printf
和scanf
的格式化I/O。主要分为向外输出内容和获取输入内容两大部分。
标准库fmt提供了以下几种输出相关函数。
描述: Print
系列函数会将内容输出到系统的标准输出,区别在于Print
函数直接输出内容,Printf
函数支持格式化输出字符串,Println
函数会在输出内容的结尾添加一个换行符。
1 | func Print(a ...interface{}) (n int, err error) |
举个简单的例子:1
2
3
4
5
6func main() {
fmt.Print("在终端打印该信息。")
name := "WeiyiGeek-Go语言学习"
fmt.Printf("我是:%s\n", name)
fmt.Println("在终端打印单独一行显示")
}
执行上面的代码输出:1
2在终端打印该信息。我是:WeiyiGeek-Go语言学习
在终端打印单独一行显示
Fprint
系列函数会将内容输出到一个io.Writer
接口类型的变量w
中,我们通常用这个函数往文件中写入内容。1
2
3func Fprint(w io.Writer, a ...interface{}) (n int, err error)
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)
func Fprintln(w io.Writer, a ...interface{}) (n int, err error)
举个例子:1
2
3
4
5
6
7
8
9
10// 向标准输出写入内容
fmt.Fprintln(os.Stdout, "向标准输出写入内容")
fileObj, err := os.OpenFile("./xx.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
fmt.Println("打开文件出错,err:", err)
return
}
name := "WeiyiGeek"
// 向打开的文件句柄中写入内容
fmt.Fprintf(fileObj, "往文件中写如信息:%s", name)
注意,只要满足io.Writer
接口的类型都支持写入。
Sprint
系列函数会把传入的数据生成并返回一个字符串。
1 | func Sprint(a ...interface{}) string |
简单的示例代码如下:
1 | s1 := fmt.Sprint("WeiyiGeek") |
Errorf
函数根据format参数生成格式化字符串并返回一个包含该字符串的错误。
1 | func Errorf(format string, a ...interface{}) error |
通常使用这种方式来自定义错误类型,例如:1
err := fmt.Errorf("这是一个错误")
Go1.13版本为fmt.Errorf
函数新加了一个%w
占位符用来生成一个可以包裹Error的Wrapping Error。
1 | e := errors.New("原始错误e") |
Go语言fmt
包下有fmt.Scan
、fmt.Scanf
、fmt.Scanln
三个函数,可以在程序运行过程中从标准输入获取用户的输入。
函数定签名如下:
1 | func Scan(a ...interface{}) (n int, err error) |
具体代码示例如下:
1 | func main() { |
将上面的代码编译后在终端执行,在终端依次输入小王子
、28
和false
使用空格分隔。
1 | $ ./scan_demo |
fmt.Scan
从标准输入中扫描用户输入的数据,将以空白符分隔的数据分别存入指定的参数。
函数签名如下:
1 | func Scanf(format string, a ...interface{}) (n int, err error) |
代码示例如下:
1 | func main() { |
将上面的代码编译后在终端执行,在终端按照指定的格式依次输入小王子
、28
和false
。
1 | $ ./scan_demo |
fmt.Scanf
不同于fmt.Scan
简单的以空格作为输入数据的分隔符,fmt.Scanf
为输入数据指定了具体的输入内容格式,只有按照格式输入数据才会被扫描并存入对应变量。
例如,我们还是按照上个示例中以空格分隔的方式输入,fmt.Scanf
就不能正确扫描到输入的数据。
1 | $ ./scan_demo |
函数签名如下:
1 | func Scanln(a ...interface{}) (n int, err error) |
具体代码示例如下:
1 | func main() { |
将上面的代码编译后在终端执行,在终端依次输入小王子
、28
和false
使用空格分隔。
1 | $ ./scan_demo |
fmt.Scanln
遇到回车就结束扫描了,这个比较常用。
有时候我们想完整获取输入的内容,而输入的内容可能包含空格,这种情况下可以使用bufio
包来实现。示例代码如下:
1 | func bufioDemo() { |
描述: 这几个函数功能分别类似于fmt.Scan
、fmt.Scanf
、fmt.Scanln
三个函数,只不过它们不是从标准输入中读取数据而是从io.Reader
中读取数据。
1 | func Fscan(r io.Reader, a ...interface{}) (n int, err error) |
描述: 这几个函数功能分别类似于fmt.Scan
、fmt.Scanf
、fmt.Scanln
三个函数,只不过它们不是从标准输入中读取数据而是从指定字符串中读取数据。
1 | func Sscan(str string, a ...interface{}) (n int, err error) |
示例演示:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18package main
import "fmt"
func main() {
var name string
var age int
var boolean_value bool
n, err := fmt.Sscan("WeiyiGeek 18 true",
&name, &age, &boolean_value)
if err != nil {
panic(err)
}
fmt.Printf("%d:%s, %d, %t", n, name, age, boolean_value)
}
执行结果:1
3:WeiyiGeek, 18, true
描述: *printf
系列函数都支持format格式化参数,在这里我们按照占位符将被替换的变量类型划分,方便查询和记忆。
占位符 | 说明 |
---|---|
%v | 值的默认格式表示 |
%+v | 类似%v,但输出结构体时会添加字段名 |
%#v | 值的Go语法表示 |
%T | 打印值的类型 |
%% | 百分号 |
示例代码如下:1
2
3
4
5
6
7fmt.Printf("%v\n", 100)
fmt.Printf("%v\n", false)
o := struct{ name string }{"小王子"}
fmt.Printf("%v\n", o)
fmt.Printf("%#v\n", o)
fmt.Printf("%T\n", o)
fmt.Printf("100%%\n")
输出结果如下:1
2
3
4
5
6100
false
{小王子}
struct { name string }{name:"小王子"}
struct { name string }
100%
占位符 | 说明 |
---|---|
%t | true或false |
占位符 | 说明 |
---|---|
%b | 表示为二进制 |
%c | 该值对应的unicode码值 |
%d | 表示为十进制 |
%o | 表示为八进制 |
%x | 表示为十六进制,使用a-f |
%X | 表示为十六进制,使用A-F |
%U | 表示为Unicode格式:U+1234,等价于”U+%04X” |
%q | 该值对应的单引号括起来的go语法字符字面值,必要时会采用安全的转义表示 |
示例代码如下:
1 | n := 65 |
输出结果如下:
1 | 1000001 |
占位符 | 说明 |
---|---|
%b | 无小数部分、二进制指数的科学计数法,如-123456p-78 |
%e | 科学计数法,如-1234.456e+78 |
%E | 科学计数法,如-1234.456E+78 |
%f | 有小数部分但无指数部分,如123.456 |
%F | 等价于%f |
%g | 根据实际情况采用%e或%f格式(以获得更简洁、准确的输出) |
%G | 根据实际情况采用%E或%F格式(以获得更简洁、准确的输出) |
示例代码如下:
1 | f := 12.34 |
输出结果如下:
1 | 6946802425218990p-49 |
占位符 | 说明 |
---|---|
%s | 直接输出字符串或者[]byte |
%q | 该值对应的双引号括起来的go语法字符串字面值,必要时会采用安全的转义表示 |
%x | 每个字节用两字符十六进制数表示(使用a-f |
%X | 每个字节用两字符十六进制数表示(使用A-F) |
示例代码如下:
1 | s := "小王子" |
输出结果如下:
1 | 小王子 |
占位符 | 说明 |
---|---|
%p | 表示为十六进制,并加上前导的0x |
示例代码如下:1
2
3a := 10
fmt.Printf("%p\n", &a) // 变量a的地址
fmt.Printf("%#p\n", &a)
输出结果如下:1
20xc000094000
c000094000
宽度通过一个紧跟在百分号后面的十进制数指定,如果未指定宽度,则表示值时除必需之外不作填充。精度通过(可选的)宽度后跟点号后跟的十进制数指定。如果未指定精度,会使用默认精度;如果点号后没有跟数字,表示精度为0。
举例如下:
占位符 | 说明 |
---|---|
%f | 默认宽度,默认精度 |
%9f | 宽度9,默认精度 |
%.2f | 默认宽度,精度2 |
%9.2f | 宽度9,精度2 |
%9.f | 宽度9,精度0 |
示例代码如下:1
2
3
4
5
6n := 12.34
fmt.Printf("%f\n", n)
fmt.Printf("%9f\n", n)
fmt.Printf("%.2f\n", n)
fmt.Printf("%9.2f\n", n)
fmt.Printf("%9.f\n", n)
输出结果如下:
1 | 12.340000 |
占位符 | 说明 |
---|---|
’+’ | 总是输出数值的正负号;对%q(%+q)会生成全部是ASCII字符的输出(通过转义); |
’ ‘ | 对数值,正数前加空格而负数前加负号;对字符串采用%x或%X时(% x或% X) 会给各打印的字节之间加空格 |
’-’ | 在输出右边填充空白而不是默认的左边(即从默认的右对齐切换为左对齐); |
’#’ | 八进制数前加0(%#o),十六进制数前加0x(%#x)或0X(%#X) ,指针去掉前面的0x(%#p)对%q(%#q),对%U(%#U) 会输出空格和单引号括起来的go字面值; |
‘0’ | 使用0而不是空格填充,对于数值类型会把填充的0放在正负号后面; |
举个例子:1
2
3
4
5
6
7
8s := "小王子"
fmt.Printf("%s\n", s)
fmt.Printf("%5s\n", s)
fmt.Printf("%-5s\n", s)
fmt.Printf("%5.7s\n", s)
fmt.Printf("%-5.7s\n", s)
fmt.Printf("%5.2s\n", s)
fmt.Printf("%05s\n", s)
输出结果如下:1
2
3
4
5
6
7小王子
小王子
小王子
小王子
小王子
小王
00小王子
描述: 如果你只是简单的想要获取命令行参数,可以像下面的代码示例一样使用os.Args
来获取命令行参数。
Tips : os.Args
是一个存储命令行参数的字符串切片,它的第一个元素是执行文件的名称。
1 | package main |
将上面的代码执行go build -o "args_demo"
编译之后,执行:1
2
3
4
5
6$ ./args_demo a b c d
args[0]=./args_demo
args[1]=a
args[2]=b
args[3]=c
args[4]=d
我们可以使用os.Open()
与os.Openfile()
方法读取或者写入、创建文件。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// 返回一个只读的文化句柄
file, err := os.Open("./onlyread.txt")
if err != nil {
fmt.Println("open file failed!, err:", err)
return
}
defer file.Close()
// 返回一个可写入文件句柄
file, err := os.OpenFile("./write.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
if err != nil {
fmt.Println("open write file failed!, err:", err)
return
}
defer file.Close()
// 文件重命名
os.Rename("./write.txt","./write.txt.bak")
描述: Go语言内置的flag包实现了命令行参数的解析,flag包使得开发命令行工具更为简单。
文档参考: https://studygolang.com/pkgdoc
描述: 同样要想使用我们需要先导入其包。1
import flag
参数类型: flag 包支持的命令行参数类型有 bool、int、int64、uint、uint64、float float64、string、duration
flag参数 | 有效值 |
---|---|
字符串flag | 合法字符串 |
整数flag | 1234、0664、0x1234等类型,也可以是负数。 |
浮点数flag | 合法浮点数 |
bool类型flag | 1, 0, t, f, T, F, true, false, TRUE, FALSE, True, False。 |
时间段flag | 任何合法的时间段字符串。如”300ms”、”-1.5h”、”2h45m”。 合法的单位有”ns”、”us” 、“µs”、”ms”、”s”、”m”、”h”。 |
描述: 有以下两种常用的定义命令行flag参数的方法。
基本格式如下:flag.Type(flag名, 默认值, 帮助信息)*Type
例如: 我们要定义姓名、年龄、婚否三个命令行参数,我们可以按如下方式定义:
1 | name := flag.String("name", "张三", "姓名") // 返回的是指针变量 |
需要注意的是,此时name
、age
、married
、delay
均为对应类型的指针,在输出时需要加取地址符(*
)。
基本格式如下: flag.TypeVar(Type指针, flag名, 默认值, 帮助信息)
例如: 我们要定义姓名、年龄、婚否三个命令行参数,我们可以按如下方式定义:
1 | var name string |
描述: 通过以上两种方法定义好命令行flag参数后,需要通过调用flag.Parse()
来对命令行参数进行解析,并将其赋值给对应的变量。
支持的命令行参数格式有以下几种:
-flag xxx
(使用空格,一个-
符号)--flag xxx
(使用空格,两个-
符号)-flag=xxx
(使用等号,一个-
符号)--flag=xxx
(使用等号,两个-
符号)其中,布尔类型的参数必须使用等号的方式指定。
Flag 解析在第一个非flag参数(单个'-'不是flag参数
)之前停止,或者在终止符–
之后停止。
描述:下述该Flag
的方法可以帮助我们查看其它参数
和参数数量
。1
2
3flag.Args() // 返回命令行参数后的其他参数,以[]string类型
flag.NArg() // 返回命令行参数后的其他参数个数
flag.NFlag() // 返回使用的命令行参数个数
完整示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24func main() {
// 定义命令行参数方式
var (
name string
age int
married bool
delay time.Duration
)
// 如没有参数参入则采用默认设置的参数
flag.StringVar(&name, "name", "张三", "姓名")
flag.IntVar(&age, "age", 18, "年龄")
flag.BoolVar(&married, "married", false, "婚否")
flag.DurationVar(&delay, "delay", 0, "延迟的时间间隔")
// 解析命令行参数
flag.Parse()
fmt.Println(name, age, married, delay)
//返回命令行参数后的其他参数
fmt.Println(flag.Args())
//返回命令行参数后的其他参数个数
fmt.Println(flag.NArg())
//返回使用的命令行参数个数
fmt.Println(flag.NFlag())
}
命令行参数使用提示:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16➜ package go build -o flag
$ ./flag -help
# Usage of ./flag:
# -age int
# 年龄 (default 18)
# -d duration
# 时间间隔
# -married
# 婚否
# -name string
# 姓名 (default "张三")
➜ package ./flag -name "WeiyiGeek" -age 18 -d=1h30m -married=false other1 other2
# WeiyiGeek 18 false 1h30m0s // 传入参数
# [other1 other2] // 未设置的参数(--flag)
# 2 // 未设置的参数(--flag)的个数
# 4 // 传入参数的个数
描述: 无论是软件开发的调试阶段还是软件上线之后的运行阶段,日志一直都是非常重要的一个环节,我们也应该养成在程序中记录日志的好习惯。
描述: Go语言内置的log包实现了简单的日志服务, 本文介绍了标准库log的基本使用。
描述: log包定义了Logger类型,该类型提供了一些格式化输出的方法。本包也提供了一个预定义的“标准”logger,可以通过调用函数Print系列(Print|Printf|Println)
、Fatal系列(Fatal|Fatalf|Fatalln)
、和Panic系列(Panic|Panicf|Panicln)
来使用,比自行创建一个logger对象更容易使用。
例如,我们可以像下面的代码一样直接通过log包来调用上面提到的方法,默认它们会将日志信息打印到终端界面:
1 | package main |
编译并执行上面的代码会得到如下输出:1
2
32017/06/19 14:04:17 这是一条很普通的日志。
2017/06/19 14:04:17 这是一条很普通的日志。
2017/06/19 14:04:17 这是一条会触发fatal的日志。
Tips : logger 会打印每条日志信息的日期、时间,默认输出到系统的标准错误。
Tips : Fatal 系列函数会在写入日志信息后调用 os.Exit(1)
。
Tips : Panic 系列函数会在写入日志信息后调用 panic
。
标准配置
描述: 默认情况下的logger只会提供日志的时间信息,但是很多情况下我们希望得到更多信息,比如记录该日志的文件名和行号等。log标准库中为我们提供了定制这些设置的方法。
Tips : log 标准库中的Flags
函数会返回标准logger的输出配置,而SetFlags函数用来设置标准logger的输出配置。1
2func Flags() int
func SetFlags(flag int)
flag 选项
描述: log标准库提供了如下的flag选项,它们是一系列定义好的常量。
1 | const ( |
下面我们在记录日志之前先设置一下标准logger的输出选项如下:1
2
3
4func main() {
log.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate)
log.Println("这是一条很普通的日志。")
}
编译执行后得到的输出结果如下:1
2017/06/19 14:05:17.494943 .../log_demo/main.go:11: 这是一条很普通的日志。
配置日志前缀
描述: log标准库中还提供了关于日志信息前缀的两个方法:1
2func Prefix() string
func SetPrefix(prefix string)
其中Prefix函数用来查看标准logger的输出前缀,SetPrefix函数用来设置输出前缀。1
2
3
4
5
6func main() {
log.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate)
log.Println("这是一条很普通的日志。")
log.SetPrefix("[小王子]")
log.Println("这是一条很普通的日志。")
}
上面的代码输出如下:1
[小王子]2017/06/19 14:05:57.940542 .../log_demo/main.go:13: 这是一条很普通的日志。
Tips : 这样我们就能够在代码中为我们的日志信息添加指定的前缀,方便之后对日志信息进行检索和处理。
配置日志输出位置
描述: SetOutput 函数
用来设置标准logger的输出目的地,默认是标准错误输出。1
func SetOutput(w io.Writer)
例如,下面的代码会把日志输出到同目录下的xx.log文件中。1
2
3
4
5
6
7
8
9
10
11
12func main() {
logFile, err := os.OpenFile("./xx.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
fmt.Println("open log file failed, err:", err)
return
}
log.SetOutput(logFile)
log.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate)
log.Println("这是一条很普通的日志。")
log.SetPrefix("[小王子]")
log.Println("这是一条很普通的日志。")
}
如果你要使用标准的logger,我们通常会把上面的配置操作写到init函数中。1
2
3
4
5
6
7
8
9func init() {
logFile, err := os.OpenFile("./xx.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
fmt.Println("open log file failed, err:", err)
return
}
log.SetOutput(logFile)
log.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate)
}
描述: log标准库中还提供了一个创建新logger对象的构造函数–New,支持我们创建自己的logger示例。
New 函数的签名如下:1
func New(out io.Writer, prefix string, flag int) *Logger
New 创建一个Logger对象。其中参数out设置日志信息写入的目的地。参数prefix会添加到生成的每一条日志前面。参数flag定义日志的属性(时间、文件等)。
举个例子:1
2
3
4func main() {
logger := log.New(os.Stdout, "<New>", log.Lshortfile|log.Ldate|log.Ltime)
logger.Println("这是自定义的logger记录的日志。")
}
将上面的代码编译执行之后,得到结果如下:1
<New>2017/06/19 14:06:51 main.go:34: 这是自定义的logger记录的日志。
描述: Go内置的log库功能有限,例如无法满足记录不同级别日志的情况,我们在实际的项目中根据自己的需要选择使用第三方的日志库,如logrus、zap等。
案例演示:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49package main
import (
"fmt"
"log"
"os"
"time"
)
func delay() {
time.Sleep(time.Duration(1) * time.Second)
}
func main() {
v := "信息警告提示"
// 常规信息
log.Printf("[-] 此处是这一条的日志信息 :%s 。\n", v)
delay()
log.Println("[-] 这是一条换行的日志信息。")
// Flag 选项
log.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ltime | log.Ldate)
log.Println("[-] 这是换行的日志信息(Flag 选项)。")
// 配置日志前缀
log.SetPrefix("[WeiyiGeek] ")
log.Println("这是换行的日志信息(配置日志前缀)。")
// 创建 logger 使用示例
logger := log.New(os.Stdout, "[New-WeiGeek] ", log.Lshortfile|log.Ldate|log.Ltime)
logger.Println("这是自定义的logger记录的日志。")
// 配置日志输出
logFile, err := os.OpenFile("./Logger.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
fmt.Println("open log file failed, err:", err)
return
}
log.SetOutput(logFile) // 每次执行不会覆盖其内容,而会向其追加内容。
log.Println("[-] 这是要配置日志输出到文件之中(1)") // 会输出到 /Logger.log
log.Println("[-] 这是要配置日志输出到文件之中(2)") // 会输出到 /Logger.log
// 执行 Panicln 则会exit
delay()
log.Fatalln("[-] 这是一条会触发fatal的日志。") // 会输出到 /Logger.log
delay()
log.Panicln("[-] 这是一条会触发panic的日志。")
}
执行结果:1
2
3
4$ cat Logger.log
[WeiyiGeek] 2021/08/03 11:35:29.482279 /home/weiyigeek/app/project/go/src/weiyigeek.top/studygo/package/02logger.go:41: [-] 这是要配置日志输出到文件之中(1)
[WeiyiGeek] 2021/08/03 11:35:29.482338 /home/weiyigeek/app/project/go/src/weiyigeek.top/studygo/package/02logger.go:42: [-] 这是要配置日志输出到文件之中(2)
[WeiyiGeek] 2021/08/03 11:35:30.482714 /home/weiyigeek/app/project/go/src/weiyigeek.top/studygo/package/02logger.go:46: [-] 这是一条会触发fatal的日志。
描述: 本文主要介绍了Go语言内置的time包的基本用法,time包提供了时间的显示和测量用的函数。
Time 报预定义的版式,其定义的时间为2006年1月2号 15点04分05秒
是Go语言诞生的日子。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22const (
ANSIC = "Mon Jan _2 15:04:05 2006"
UnixDate = "Mon Jan _2 15:04:05 MST 2006"
RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
RFC822 = "02 Jan 06 15:04 MST"
RFC822Z = "02 Jan 06 15:04 -0700" // 使用数字表示时区的RFC822
RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // 使用数字表示时区的RFC1123
RFC3339 = "2006-01-02T15:04:05Z07:00"
RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
Kitchen = "3:04PM"
// 方便的时间戳
Stamp = "Jan _2 15:04:05"
StampMilli = "Jan _2 15:04:05.000"
StampMicro = "Jan _2 15:04:05.000000"
StampNano = "Jan _2 15:04:05.000000000"
)
// 可以获取输出其定义常量
fmt.Println(time.ANSIC) # Mon Jan _2 15:04:05 2006
Tips: 日历的计算采用的是公历。
描述: 我们可以通过time.Now()
函数获取当前的时间对象,然后获取时间对象的年月日时分秒
等信息。
示例代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25func demo1() {
// 获取当前时间
now := time.Now()
// 输出当前时间
fmt.Printf("Current Localtion Time is :%v, \nUTC Time is: %v\n", now.Local(), now.UTC())
// 分别获取当前时间的年月日/时分秒
year := now.Year() //年
month := now.Month() //月
day := now.Day() //日
hour := now.Hour() //小时
minute := now.Minute() //分钟
second := now.Second() //秒
y, m, d := now.Date() //年月日
week := now.Weekday() //周
fmt.Printf("Current Localtion Time Format: %d-%02d-%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second)
fmt.Printf("Year : %d ,Month : %v ,Day : %d ,WeekDay : %v\n", y, m, d, week)
}
// === 执行结果 ===
Current Localtion Time is :2021-09-27 12:45:41.295602237 +0800 CST,
UTC Time is: 2021-09-27 04:45:41.295602237 +0000 UTC
Current Localtion Time Format: 2021-09-27 12:45:41
Year : 2021 ,Month : September ,Day : 27 ,WeekDay : Monday
描述: 时间戳是自1970年1月1日(00:00:00)至当前时间的总毫秒数与时区无关,它也被称为Unix时间戳(UnixTimestamp),我们可以使用time.Unix()函数
将时间戳转为时间格式。
1 | // # Unix创建一个本地时间,对应sec和nsec表示的Unix时间(从January 1, 1970 UTC至该时间的秒数和纳秒数)。 |
代码演示:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23//获取当前时间
now := time.Now()
timestamp1 := now.Unix() //时间戳
timestamp2 := now.UnixNano() //纳秒时间戳
fmt.Printf("current timestamp : %v\n", timestamp1)
fmt.Printf("current timestamp nanosecond: %v\n", timestamp2)
//将时间戳转为时间格式(秒数,纳秒数)
timeObj := time.Unix(timestamp1, 0)
fmt.Println("时间戳转换后的时间 :", timeObj)
year := timeObj.Year() //年
month := timeObj.Month() //月
day := timeObj.Day() //日
hour := timeObj.Hour() //小时
minute := timeObj.Minute() //分钟
second := timeObj.Second() //秒
fmt.Printf("格式化后 :%d-%02d-%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second)
// ==== 执行结果 ====
current timestamp : 1632718244
current timestamp nanosecond: 1632718244062677557
时间戳转换后的时间 : 2021-09-27 12:50:44 +0800 CST
格式化后 :2021-09-27 12:50:44
描述: time.Duration是time包定义的一个类型,它代表两个时间点之间经过的时间,以纳秒为单位。
time.Duration表示一段时间间隔,可表示的最长时间段大约290年。
time包中定义的时间间隔类型的常量如下:1
2
3
4
5
6
7
8const (
Nanosecond Duration = 1
Microsecond = 1000 * Nanosecond
Millisecond = 1000 * Microsecond
Second = 1000 * Millisecond
Minute = 60 * Second
Hour = 60 * Minute
)
例如:time.Duration表示1纳秒,time.Second表示1秒。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16func demo3() {
fmt.Println(time.Nanosecond)
fmt.Println(time.Microsecond)
fmt.Println(time.Millisecond)
fmt.Println(time.Second)
fmt.Println(time.Minute)
fmt.Println(time.Hour)
}
// 执行结果:
1ns
1µs
1ms
1s
1m0s
1h0m0s
描述: 默认输出的时间为 UTC 世界协调时间,我们可以设置CST 中部标准时间 (Central Standard Time)
, 而中国属于东八区,我们需要在上述时间+8小时,我们可以利用如下方法。
GMT、UTC、DST、CST时区代表的意义
GMT:Greenwich Mean Time (格林威治标准时间); 英国伦敦格林威治定为0°经线开始的地方,地球每15°经度 被分为一个时区,共分为24个时区,相邻时区相差一小时;例: 中国北京位于东八区,GMT时间比北京时间慢8小时。
UTC: Coordinated Universal Time (世界协调时间);经严谨计算得到的时间,精确到秒,误差在0.9s以内, 是比GMT更为精确的世界时间
DST: Daylight Saving Time (夏季节约时间) 即夏令时;是为了利用夏天充足的光照而将时间调早一个小时,北美、欧洲的许多国家实行夏令时;
CST: Central Standard Time (中部标准时间) 四个不同时区的缩写:
1 | Central Standard Time (USA) UT-6:00 美国标准时间 |
代码演示:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27func demo4() {
// UTC & CST & 本地时间 并返回与t关联的时区信息。
now := time.Now()
fmt.Printf("UTC 世界协调时间 : %v,时区信息: %v\n", now.UTC(), now.UTC().Location())
var cst = time.FixedZone("CST", 0)
cstnow := time.Now().In(cst)
fmt.Printf("CST 中部标准时间 : %v,时区信息: %v\n", cstnow, cstnow.Location())
fmt.Printf("将UTC时间转化为当地时间 : %v,时区信息: %v\n\n", now.Local(), now.Location())
// 中国北京时间东八区
// 方式1.FixedZone
var utcZone = time.FixedZone("UTC", 8*3600)
fmt.Printf("北京时间 : %v\n", now.In(utcZone))
// 方式2.LoadLocation 设置地区
var cstZone, _ = time.LoadLocation("Asia/Shanghai") //上海
fmt.Printf("北京时间 : %v\n", now.In(cstZone))
// 输出当前格林威治时间和该时区相对于UTC的时间偏移量(单位秒)
name, offset := now.In(utcZone).Zone()
fmt.Println("当前时间时区名称:", name, " 对于UTC的时间偏移量:", offset)
// 当前操作系统本地时区
fmt.Println("当前操作系统本地时区",time.Local)
}
执行结果:1
2
3
4
5
6
7
8UTC 世界协调时间 : 2021-09-27 04:58:11.866995694 +0000 UTC,时区信息: UTC
CST 中部标准时间 : 2021-09-27 04:58:11.867088566 +0000 CST,时区信息: CST
将UTC时间转化为当地时间 : 2021-09-27 12:58:11.866995694 +0800 CST,时区信息: Local
北京时间 : 2021-09-27 12:58:11.866995694 +0800 UTC
北京时间 : 2021-09-27 12:58:11.866995694 +0800 CST
当前时间时区名称: UTC 对于UTC的时间偏移量: 28800
当前操作系统本地时区: Local
Add
描述: 我们在日常的编码过程中可能会遇到要求时间+时间间隔的需求,Go语言的时间对象有提供Add方法如下:
语法:1
func (t Time) Add(d Duration) Time
Sub
描述: 求两个时间之间的差值,返回一个时间段t-u。
如果结果超出了Duration可以表示的最大值/最小值,将返回最大值/最小值。要获取时间点t-d(d为Duration),可以使用t.Add(-d)。
1 | func (t Time) Sub(u Time) Duration |
Equal
描述: 判断两个时间是否相同,会考虑时区的影响,因此不同时区标准的时间也可以正确比较。本方法和用t==u不同,这种方法还会比较地点和时区信息。1
func (t Time) Equal(u Time) bool
Before
如果t代表的时间点在u之前,返回真;否则返回假。1
func (t Time) Before(u Time) bool
After
如果t代表的时间点在u之后,返回真;否则返回假。1
func (t Time) After(u Time) bool
代码示例1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16func demo5() {
now := time.Now()
// 1.求一个小时之后的时间
later := now.Add(time.Hour) // 当前时间加1小时后的时间
tomorrow := now.Add(time.Hour * 24) // 当前时间加1天后的时间
fmt.Println("later :", later, "\ntomorrow: ", tomorrow)
fmt.Println("later :", later)
// 2.当前时间与later的差值
fmt.Println("Sub :", now.Sub(later))
// 3.当前时间与later是否相等
fmt.Println("Equal :", now.Equal(later))
// 3.当前时间是否在later之前
fmt.Println("Before :", now.Before(later))
// 3.当前时间是否在later之后
fmt.Println("After :", now.After(later))
}
执行结果:1
2
3
4
5
6later : 2021-09-27 14:04:53.94642009 +0800 CST m=+3600.000091915
tomorrow: 2021-09-28 13:04:53.94642009 +0800 CST m=+86400.000091915
Sub : -1h0m0s
Equal : false
Before : true
After : false
描述: 使用time.Tick(时间间隔)
来设置定时器以及使用time.Sleep(Duration)
函数来延迟执行,定时器的本质上是一个通道(channel)。
Duration 时间间隔可选参数:1
2
3
4
5
6time.Nanosecond
time.Microsecond
time.Millisecond
time.Second
time.Minute
time.Hour
示例演示:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15func demo6() {
ticker := time.Tick(time.Second) //定义一个1秒间隔的定时器
for i := range ticker {
fmt.Println(i) //每秒都会执行的任务
time.Sleep(time.Second * 5) //休眠5S执行,注意不能直接传递5,除了前面这种方式你还可以利用显示强转整数5 time.Duration(5);
}
}
执行结果:
➜ Time go run timeDemo.go
2021-09-27 03:35:58.640028069 +0000 UTC m=+1.000158842
2021-09-27 03:35:59.64011495 +0000 UTC m=+2.000245738 # 特殊点(第二执行未经过5S)
2021-09-27 03:36:04.640065081 +0000 UTC m=+7.000195859
2021-09-27 03:36:09.640302389 +0000 UTC m=+12.000433177
2021-09-27 03:36:14.640070051 +0000 UTC m=+17.000200829
描述: 时间类型有一个自带的方法Format
进行格式化,需要注意的是Go语言中格式化时间模板不是常见的Y-m-d H:M:S
而是使用Go的诞生时间2006年1月2号15点04分(记忆口诀为2006 1 2 3 4)
, 也许这就是技术人员的浪漫吧。
补充:如果想格式化为12小时方式,需指定PM
。
Foramt|格式化
描述: 格式化时间是把Go语言中的时间对象,转换成为字符串类型的时间。
代码演示:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30func demo7() {
// 当前UTC时间
now := time.Now()
// 设置时区为Asia/Shanghai
loc, err := time.LoadLocation("Asia/Shanghai")
if err != nil {
fmt.Println(err)
return
}
fmt.Println("北京时间 :", now.In(loc), "\n地点时区 :", loc)
// 1.时间格式化
fmt.Println("格式1 :", now.Format("2006/01/02"))
fmt.Println("格式2 :", now.Format("2006/01/02 15:04"))
fmt.Println("格式3 :", now.Format("15:04 2006/01/02"))
// 24小时制
fmt.Println("格式4 :", now.Format("2006-01-02 15:04:05.000 Mon Jan"))
// 12小时制
fmt.Println("格式5 :", now.Format("2006-01-02 03:04:05.000 PM"))
fmt.Println("格式6 :", now.Format("2006-01-02 03:04:05.000 PM Mon Jan"))
fmt.Println("Kitchen 格式 :", now.Format(time.Kitchen))
// 时区展示
fmt.Println("RFC1123 格式 :", now.Format(time.RFC1123))
fmt.Println("RFC1123 格式 :", now.Format(time.RFC1123Z))
fmt.Println("RFC3339 格式 :", now.Format(time.RFC3339))
fmt.Println("RFC3339Nano 格式 :", now.Format(time.RFC3339Nano))
}
执行结果:1
2
3
4
5
6
7
8
9
10
11
12
13北京时间 : 2021-09-27 14:15:42.716506733 +0800 CST
地点时区 : Asia/Shanghai
格式1 : 2021/09/27
格式2 : 2021/09/27 14:15
格式3 : 14:15 2021/09/27
格式4 : 2021-09-27 14:15:42.716 Mon Sep
格式5 : 2021-09-27 02:15:42.716 PM
格式6 : 2021-09-27 02:15:42.716 PM Mon Sep
Kitchen 格式 : 2:15PM
RFC1123 格式 : Mon, 27 Sep 2021 14:15:42 CST
RFC1123 格式 : Mon, 27 Sep 2021 14:15:42 +0800
RFC3339 格式 : 2021-09-27T14:15:42+08:00
RFC3339Nano 格式 : 2021-09-27T14:15:42.716506733+08:00
Parse|解析字符串格式
描述: 将时间字符串解析为时间对象。
通过time.Parse将时间字符串转化为时间类型对象默认是UTC时间, 而通过time.ParseInLocation我们可以指定时区得到CST时间。
代码演示:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26func demo8() {
// 1.时间与时区设置
now := time.Now()
loc, _ := time.LoadLocation("Asia/Shanghai")
// 2.按照指定时区和指定格式解析字符串时间
timeObj1, _ := time.Parse("2006-01-02 15:04:05", "2021-09-27 14:15:20")
timeObj2, _ := time.ParseInLocation("2006/01/02 15:04:05", "2021/09/27 14:15:20", time.Local) // 操作系统本地时区
timeObj3, _ := time.ParseInLocation("2006/01/02 15:04:05", "2021/09/27 14:15:20", loc) // 指定时区
fmt.Printf("Now: %v\ntimeObj1: %v\ntimeObj2: %v\ntimeObj3: %v\n", now.Local(), timeObj1, timeObj2, timeObj3)
// 将当地时区转化为UTC时间
utcLocal := timeObj3.UTC()
fmt.Println("将当地时区转化为UTC时间:", utcLocal)
// 将UTC时间转化为当地时间(+8)
localTime := utcLocal.Local()
fmt.Println("将UTC时间转化为当地时间:", localTime)
// 3.相互转换后的时间进行对比.
fmt.Println("相互转换后的时间进行对比:", utcLocal.Equal(localTime))
// 4.输入的时间字符串与当前时间的相差时间.
d := timeObj3.Sub(now)
// 可以看到timeObj 时间 与 当前时间 相差 33 分钟 55 秒
fmt.Println("看到timeObj 时间 与 当前时间 相差:", d.String())
}
执行结果:1
2
3
4
5
6
7
8Now: 2021-09-27 14:49:15.392828987 +0800 CST
timeObj1: 2021-09-27 14:15:20 +0000 UTC
timeObj2: 2021-09-27 14:15:20 +0800 CST
timeObj3: 2021-09-27 14:15:20 +0800 CST
将当地时区转化为UTC时间: 2021-09-27 06:15:20 +0000 UTC
将UTC时间转化为当地时间: 2021-09-27 14:15:20 +0800 CST
相互转换后的时间进行对比: true
看到timeObj3 时间 与 当前时间 相差: -33m55.392828987s
(0) 按照str格式化时间(Go诞生之日口诀:6-1-2-3-4-5)
1 | //格式化时间格式 |
(1) UTC时间互换标准时间
1 | //UTC时间转标准时间 |
(2) 标准时间转UTC时间
1 | //标准时间转UTC时间 |
(3) str格式化时间转时间戳
1 | the_time, err := time.Parse("2006-01-02 15:04:05", "2020-04-29 22:11:08") |
(4) 时间戳转str格式化时间
1 | str_time := time.Unix(1588224111, 0).Format("2006-01-02 15:04:05") |
你好看友,欢迎关注博主微信公众号哟! ❤
这将是我持续更新文章的动力源泉,谢谢支持!(๑′ᴗ‵๑)
温馨提示: 未解锁的用户不能粘贴复制文章内容哟!
方式1.请访问本博主的B站【WeiyiGeek】首页关注UP主,
将自动随机获取解锁验证码。
Method 2.Please visit 【My Twitter】. There is an article verification code in the homepage.
方式3.扫一扫下方二维码,关注本站官方公众号
回复:验证码
将获取解锁(有效期7天)本站所有技术文章哟!
@WeiyiGeek - 为了能到远方,脚下的每一步都不能少
欢迎各位志同道合的朋友一起学习交流,如文章有误请在下方留下您宝贵的经验知识,个人邮箱地址【master#weiyigeek.top】
或者个人公众号【WeiyiGeek】
联系我。
更多文章来源于【WeiyiGeek Blog - 为了能到远方,脚下的每一步都不能少】, 个人首页地址( https://weiyigeek.top )
专栏书写不易,如果您觉得这个专栏还不错的,请给这篇专栏 【点个赞、投个币、收个藏、关个注、转个发、赞个助】,这将对我的肯定,我将持续整理发布更多优质原创文章!。
最后更新时间:
文章原始路径:_posts/编程世界/Go/Package/1.Go语言之标准库学习记录(1).md
转载注明出处,原文地址:https://blog.weiyigeek.top/2020/4-23-602.html
本站文章内容遵循 知识共享 署名 - 非商业性 - 相同方式共享 4.0 国际协议