Golang基础笔记十一之日期与时间处理
本文首发于公众号:Hunter后端
原文链接:Golang基础笔记十一之日期与时间处理
本篇笔记介绍 Golang 里日期与时间的处理,以下是本篇笔记目录:
- 当前日期与时间的获取
- 字符串与时间格式的互相转换
- 时间戳与时间格式的互相转换
- 日期与时间的加减
- 星期数的获取
- 定时器与计时器
1、当前日期与时间的获取
在 Golang 里,日期和时间处理都通过 time 包来实现。
如果我们想获取当前时间,我们可以使用 time.Now() 来操作:
now := time.Now()
fmt.Println(now) // 2025-06-29 12:29:16.112605 +0800 CST m=+0.000154626
如果我们想获取单独的年月日时分秒字段,可以使用下面的操作:
now := time.Now()
year, month, day := now.Date()
hour, minute, second := now.Clock()
fmt.Println(year, month, day) // 2025 June 29
fmt.Println(hour, minute, second) // 15 29 50
可以看到输出的月份是 June
,但实际上月份是一个自定义的类型 Month
,本质上也是一个 int 型数据,其源代码如下:
type Month int
const (
January Month = 1 + iota
February
March
April
May
June
July
August
September
October
November
December
)
所以,对于这里的年月日时分秒的单个变量,我们想将其组合输出为一般的 %Y-%m-%d %H:%M:%S
格式,可以如下操作:
fmt.Printf("%d-%02d-%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second)
我们也可以分别单独获取对应的年月日时分秒数据:
now := time.Now()
fmt.Println(now.Year())
fmt.Println(now.Month())
fmt.Println(now.Day())
fmt.Println(now.Hour())
fmt.Println(now.Minute())
fmt.Println(now.Second())
2、字符串与时间格式的互相转换
1. 时间格式转字符串
在其他计算机语言中,如果想将时间字段转化为字符串,格式化的操作比如 Python,一般是类似于 %Y-%m-%d %H:%M:%S
这种,但是 Golang 里是一个特殊的格式化字段,为 2006-01-02 15:04:05
。
Go 里对时间字段格式化的函数为 Format()
,下面是将时间格式转为字符串的操作为:
now := time.Now()
fmt.Println(now.Format("2006-01-02 15:04:05")) // 2025-06-29 22:45:11
当然,格式化操作也可以单独针对日期,或者时间,连接的符号也可以自定义:
now := time.Now()
fmt.Println(now.Format("2006/01/02")) // 2025/06/29
fmt.Println(now.Format("15:04:05")) // 23:22:06
2. 字符串转时间格式
字符串转时间格式使用 time.Parse()
函数,以下是一个测试:
timeStr := "2025/06/29"
t, err := time.Parse("2006/01/02", timeStr)
if err != nil {
fmt.Println("str to time error: ", err)
} else {
fmt.Println("str to time is: ", t)
}
// str to time is: 2025-06-29 00:00:00 +0000 UTC
在这里 time.Parse() 返回两个字段,一个是转换后的时间字段,一个是转换过程中的错误。
上面是转换日期,转换时间也是一样的操作:
timeStr = "20:24:24"
t, err := time.Parse("15:04:05", timeStr)
if err != nil {
fmt.Println("str to time error: ", err)
} else {
fmt.Println("str to time is: ", t)
}
// str to time is: 0000-01-01 20:24:24 +0000 UTC
而如果提供了错误的时间字符串,返回的 err 字段则不会为空,比如下面这个示例:
timeStr := "2025/13/29"
t, err := time.Parse("2006/01/02", timeStr)
if err != nil {
fmt.Println("str to time error: ", err)
} else {
fmt.Println("str to time is: ", t)
}
// str to time error: parsing time "2025/13/29": month out of range
3、时间戳与时间格式的互相转换
另一个在时间函数中常用到的用于转换的数据是时间戳,下面介绍一下时间戳与时间的互相转换。
1. 时间格式转换为时间戳
下面是时间格式转换为秒级的时间戳:
now := time.Now()
fmt.Println(now.Unix()) // 1751211429
还有转换为毫秒,纳秒级的操作:
now := time.Now()
fmt.Println(now.UnixMilli()) // 1751211522339
fmt.Println(now.UnixNano()) // 1751211522339955000
2. 时间戳转换为时间格式
时间戳转换为时间格式的函数为 time.Unix()
:
timestamp := 1751211429
targetTime := time.Unix(int64(timestamp), 0)
fmt.Println(targetTime) // 2025-06-29 23:37:09 +0800 CST
这里需要注意,输入的时间戳需要是 int64 类型,输入的第二个参数为纳秒值,如果不需要那么精细的话,传值为 0 即可。
4、日期与时间的加减
介绍日期与时间的加减,这里分为两部分来介绍,一部分是时分秒,一部分是年月日,他们分别用到的函数是 Add()
和 AddDate()
。
1. Add()-时分秒的加减
time.Duration
Add()
函数的参数类型是 time.Duration
,Duration
也是自定义的一个时间单位,一纳秒就是一个 Duration
,它的类型是 int64
,范围是:
const (
minDuration Duration = -1 << 63
maxDuration Duration = 1<<63 - 1
)
而时分秒也都根据其转换关系定义好了各自的字段:
const (
Nanosecond Duration = 1
Microsecond = 1000 * Nanosecond
Millisecond = 1000 * Microsecond
Second = 1000 * Millisecond
Minute = 60 * Second
Hour = 60 * Minute
)
所以我们在使用 Add()
函数的时候可以直接使用对应的单位。
时分秒的加减
now := time.Now()
threeHoursLater := now.Add(3 * time.Hour)
thirtyMinutesAgo := now.Add(-30 * time.Minute)
twoDaysLater := now.Add(48 * time.Hour)
fmt.Println("now is: ", now.Format("2006-01-02 15:04:05"))
fmt.Println("three hours later is: ", threeHoursLater.Format("2006-01-02 15:04:05"))
fmt.Println("thirty minutes ago is: ", thirtyMinutesAgo.Format("2006-01-02 15:04:05"))
fmt.Println("two days later is: ", twoDaysLater.Format("2006-01-02 15:04:05"))
输出结果如下:
now is: 2025-06-30 22:58:38
three hours later is: 2025-07-01 01:58:38
thirty minutes ago is: 2025-06-30 22:28:38
two days later is: 2025-07-02 22:58:38
2. AddDate()-年月日的加减
AddDate()
函数接收三个参数,分别是 years、months、days,表示需要在当前时间需要增加的年数、月数和天数。
如果是想要回溯过去的日期,在对应的参数前加上负号 -
即可。
如果是不需要指定的参数设为 0 即可。
比如想要获取今天前一个月的日期,以及今天往后三天的日期,可以如下操作:
now := time.Now()
lastMonth := now.AddDate(0, -1, 0)
latestThreeDays := now.AddDate(0, 0, 3)
fmt.Println("last month is: ", lastMonth.Format("2006-01-02 15:04:05"))
fmt.Println("latest three days is: ", latestThreeDays.Format("2006-01-02 15:04:05"))
3. Add() 和 AddDate() 使用示例
这里分别使用 Add()
和 AddDate()
两个函数打印出之后七天的日期,其操作如下:
使用 Add()
函数:
now := time.Now()
for i := range 7 {
targetDate := now.Add(time.Duration(24*(i+1)) * time.Hour)
fmt.Println(targetDate.Format("2006-01-02"))
}
使用 AddDate()
函数:
now := time.Now()
for i := range 7 {
targetDate := now.AddDate(0, 0, i+1)
fmt.Println(targetDate.Format("2006-01-02"))
}
4. 两个时间点的差值
1) Sub()
如果我们想获取两个时间点之间差值,比如用于测试某个函数执行的时间,可以使用 Sub()
函数,返回的结果也是 time.Duration
:
t1 := time.Now()
time.Sleep(3 * time.Second)
t2 := time.Now()
subResult := t2.Sub(t1)
fmt.Println(subResult) // 3.00144925s
我们可以将 subResult
直接转换成我们想要的单位,比如毫秒和分钟:
fmt.Println("use millseconds: ", subResult.Milliseconds()) // use millseconds: 3001
fmt.Println("use minutes: ", subResult.Minutes()) // use minutes: 0.05002786111666667
2) time.Since()
如果我们想获取现在距离某个时间点的差值,也可以直接使用 time.Since() 函数,其使用示例如下:
t1 := time.Now()
time.Sleep(2 * time.Second)
result := time.Since(t1)
fmt.Println(result) // 2.001462166s
5、星期数的获取
我们也可以根据日期来获取对应的星期数,比如今天是星期几:
now := time.Now()
fmt.Println(now.Weekday()) // Monday
输出的信息是 Monday
。
星期数的底层数据也是 int 型,但是 Golang 将其包了一层,自定义了一个 Weekday
的类型:
type Weekday int
const (
Sunday Weekday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
)
从周日开始到周六,分别是从 0 到 6,我们可以打印一下:
now := time.Now()
fmt.Printf("%s, %d\n", now.Weekday(), now.Weekday()) // Monday, 1
6、定时器与计时器
下面介绍一下 Golang 里 time 模块的定时器和计时器如何使用。
1. 定时器
定时器有两个写法,一个是 time.NewTimer()
,一个是 time.After()
,接收的参数类型都是 time.Duration
。
下面直接用代码示例来介绍如何使用。
1) time.NewTimer
有一个需求,我们需要调用某个函数,但是函数的执行时长是不定的,而整体执行的时长是有限的,我们希望能在指定的时间内返回数据,如果这个函数执行超时就不希望它再执行了,能够立即获取其超时状态。
针对这个需求,我们就可以使用定时器来完成。
首先,我们有一个需要执行的函数,这个函数可能是调用某个接口,可能是从 Redis 或者 MySQL 中读数据,但是其执行时长是不定的,我们用 RandomTimeWork()
函数来替代,并且在其中设置一个随机休息的时间用来模拟不定的执行时长:
func RandomTimeWork() int {
sleepSeconds := rand.Intn(10)
time.Sleep(time.Duration(sleepSeconds) * time.Second)
return sleepSeconds
}
然后我们需要一个中间函数使用通道来传递其返回值:
func CallFunc(ch chan int) {
result := RandomTimeWork()
ch <- result
}
接下来就是主函数的操作,我们需要先设置一个定时器,这里我们设置为 5 秒的超时:
timeout := time.NewTimer(5 * time.Second)
然后设置一个通道用于传输数据,并且使用 goroutine 来调用:
ch := make(chan int)
go CallFunc(ch)
最后就是使用 select 操作来进行等待,看是通道先返回数据,还是定时器先计时完毕:
select {
case result := <-ch:
fmt.Println("call func success, sleep seconds: ", result)
case <-timeout.C:
fmt.Println("call func timeout")
}
其整体代码如下:
package main
import (
"fmt"
"math/rand"
"time"
)
func RandomTimeWork() int {
sleepSeconds := rand.Intn(10)
time.Sleep(time.Duration(sleepSeconds) * time.Second)
return sleepSeconds
}
func CallFunc(ch chan int) {
result := RandomTimeWork()
ch <- result
}
func main() {
timeout := time.NewTimer(5 * time.Second)
ch := make(chan int)
go CallFunc(ch)
select {
case result := <-ch:
fmt.Println("call func success, sleep seconds: ", result)
case <-timeout.C:
fmt.Println("call func timeout")
}
}
在上面的操作中,如果待执行的函数先执行完毕,而定时器却没有结束,我们可以手动执行停止定时器操作。
实际上,如果不手动停止,默认等待定时器触发结束或者程序完毕也可以,但是在高并发场景下,如果有很多未完成的定时器会造成内存占用增加,且增加程序的 GC 负担,因此,我们可以选择手动提前停止定时器。
停止操作也很简单,在获取到函数执行的结果后,我们可以如下操作:
select {
case result := <-ch:
fmt.Println("call func success, sleep seconds: ", result)
timeout.Stop()
case <-timeout.C:
fmt.Println("call func timeout")
}
2) time.After
除了 time.NewTimer()
,我们可以使用更简单的 time.After()
函数来执行一个定时器,相对上面的完整示例,我们只改动 main
函数里代码如下:
func main() {
ch := make(chan int)
go CallFunc(ch)
select {
case result := <-ch:
fmt.Println("call func success, sleep seconds: ", result)
case <-time.After(5 * time.Second):
fmt.Println("call func timeout")
}
}
注意:使用 time.After()
有个问题就是不可以提前手动结束定时器。
2. 计时器
计时器常用于定时任务,比如每隔多长时间执行某个动作,用到的函数是 time.NewTicker
,传入的参数是 time.Duration
。
比如我们想将某个函数设置为每隔三秒钟执行一次,我们可以如下操作:
func TargetFunc() {
fmt.Println("call target func at: ", time.Now().Format("2006-01-02 15:04:05"))
}
func CallFuncEntrance(ticker *time.Ticker) {
// for t := range ticker.C {
for range ticker.C {
TargetFunc()
}
}
func main() {
ticker := time.NewTicker(3 * time.Second)
go CallFuncEntrance(ticker)
time.Sleep(10 * time.Second)
ticker.Stop()
}
上面的示例中,开启了一个 goroutine 并将计时器作为参数传入,每隔三秒钟触发一次目标函数 TargetFunc()
。
并且在最后执行了计时器的停止操作 ticker.Stop()
。
在这里如果我们想重置计时器的间隔时间,可以使用 Reset() 操作:
func main() {
ticker := time.NewTicker(3 * time.Second)
go CallFuncEntrance(ticker)
time.Sleep(10 * time.Second)
ticker.Reset(1 * time.Second)
time.Sleep(4 * time.Second)
ticker.Stop()
}
执行 main 函数可以看到目标函数执行的时间间隔会从 3s 变成 1s。
定时任务的其他实现方式
除了这个操作用来执行定时任务外,我们还可以使用 for{}
和 time.Sleep()
操作来实现定时任务,其示例如下:
func TargetFunc() {
fmt.Println("call target func at: ", time.Now().Format("2006-01-02 15:04:05"))
}
func CallFuncEntrance() {
for {
TargetFunc()
time.Sleep(3 * time.Second)
}
}
func main() {
go CallFuncEntrance()
time.Sleep(10 * time.Second)
}
Golang基础笔记十一之日期与时间处理的更多相关文章
- MYSQL学习笔记三:日期和时间函数
MYSQL学习笔记三:日期和时间函数 1. 获取当前日期的函数和获取当前时间的函数 /*获取当前日期的函数和获取当前时间的函数.将日期以'YYYY-MM-DD'或者'YYYYMMDD'格式返回 */ ...
- Java基础篇(04):日期与时间API用法详解
本文源码:GitHub·点这里 || GitEE·点这里 一.时间和日期 在系统开发中,日期与时间作为重要的业务因素,起到十分关键的作用,例如同一个时间节点下的数据生成,基于时间范围的各种数据统计和分 ...
- python笔记7:日期和时间
Python 提供了一个 time 和 calendar 模块可以用于格式化日期和时间. 时间间隔是以秒为单位的浮点小数. 每个时间戳都以自从1970年1月1日午夜(历元)经过了多长时间来表示. 时间 ...
- 《Javascript权威指南》13号学习笔记:使用日期和时间
一.创Date示例 1.Date类的方法和属性是非常不静,故,申请书Date属性和方法之前.必须创建Date类的实例. var date = new Date(); //以当前日期和时间创建实例. ...
- 吴裕雄--天生自然python学习笔记:Python3 日期和时间
Python 程序能用很多方式处理日期和时间,转换日期格式是一个常见的功能. Python 提供了一个 time 和 calendar 模块可以用于格式化日期和时间. 时间间隔是以秒为单位的浮点小数. ...
- 基础笔记4(包装类,时间date. calendar
1.包装类 基本类型和对象. 编译器会对基本类型和包装类进行自动拆箱,装箱处理 Interger i=5; int i=new Interger(4); 一个缓存问题:以便提高效率 integer ...
- Golang基础笔记
<基础> Go语言中的3个关键字用于标准的错误处理流程: defer,panic,recover. 定义一个名为f 的匿名函数: Go 不支持继承和重载. Go的goroutine概念:使 ...
- javascript中关于日期和时间的基础知识
× 目录 [1]标准时间 [2]字符串 [3]闰年[4]月日[5]星期[6]时分秒 前面的话 在介绍Date对象之前,首先要先了解关于日期和时间的一些知识.比如,闰年.UTC等等.深入了解这些,有助于 ...
- R语言学习 第十一篇:日期和时间
R语言的基础包中提供了三种基本类型用于处理日期和时间,Date用于处理日期,它不包括时间和时区信息:POSIXct/POSIXlt用于处理日期和时间,其中包括了日期.时间和时区信息.R内部在存储日期和 ...
- Java基础之一组有用的类——生成日期和时间(TryDateFormats)
控制台程序. java.util包中含有相当多的类涉及日期和时间,包括Date类.Calendar类和GregorianCalendar类. Date类对象其实定义了精确到毫秒的时刻,从1970年1月 ...
随机推荐
- MySQL 中的 Log Buffer 是什么?它有什么作用?
MySQL 中的 Log Buffer 是什么?它有什么作用? Log Buffer 是 MySQL InnoDB 存储引擎的一部分,用于存储写入日志数据的内存区域.它主要用于记录事务的变更日志,这些 ...
- .net6 Api添加跨域
参照:(7条消息) .net6使用最小api(8)- 开启跨域模式,通过扩展服务实现_hailang2ll的博客-CSDN博客 步骤: 一.在appsetting.json里添加配置文件 //配置文件 ...
- pystinger实现不出网情况下,上线CS的方式
某hw过程中遇到如下情况: 获取到webshell,目标服务器不出网 目标机:内网地址,端口映射到公网ipvps: pystinger地址: https://github.com/FunnyWolf/ ...
- Allure2+Maven+Testng部署及使用详细教程
AllureReport部署 前言:最近做自动化测试要用到AllureReport生成测试报告,网上逛了一下,发现有很多帖子,但是大家描述的都模棱两可,没有详细的步骤,因此编写此贴对部署方式进行记录; ...
- Tableau 我常用函数整理
日期函数 dateadd datedadd (date_part, interval, date) 表示在日期 date 的基础上, 以date_part 为单位, 与之间隔 interval的日期 ...
- 网络编程:epoll
原理 select 的几个缺点: 1)每次调用select,都需要把fd集合从用户空间拷贝到内核空间,这个开销在fd很多时会很大 2)每次调用select都需要在内核遍历传递进来的所有fd,这个开销在 ...
- React-Native开发鸿蒙NEXT-video
React-Native开发鸿蒙NEXT-video 前几周的开发,基本把一个"只读型"社区开发的差不多了.帖子列表,详情,搜索都迁移实现了,但还差了一点------视频类型帖子的 ...
- c++复习板子
数论 GCD 点击查看 B4025 最大公约数 gcd: 点击查看代码 #include<bits/stdc++.h> #define int long long using namesp ...
- BS直聘职位数据采集与分析(爬虫)
一.项目介绍 在当今竞争激烈的就业市场中,及时掌握职位信息和市场动态变得尤为重要.本文将详细介绍如何使用Python开发一个爬虫项目,自动采集BOSS直聘网站的职位数据,并对数据进行处理和分析. 1. ...
- 把多个文件打包压缩成tar.gz文件并解压的Java实现
压缩文件 在Java中,可以 使用GZIPOutputStream创建gzip(gz)压缩文件,它在commons-compress下面,可以通过如下的maven坐标引入: <depende ...