本文首发于公众号:Hunter后端

原文链接:Golang基础笔记十一之日期与时间处理

本篇笔记介绍 Golang 里日期与时间的处理,以下是本篇笔记目录:

  1. 当前日期与时间的获取
  2. 字符串与时间格式的互相转换
  3. 时间戳与时间格式的互相转换
  4. 日期与时间的加减
  5. 星期数的获取
  6. 定时器与计时器

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.DurationDuration 也是自定义的一个时间单位,一纳秒就是一个 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基础笔记十一之日期与时间处理的更多相关文章

  1. MYSQL学习笔记三:日期和时间函数

    MYSQL学习笔记三:日期和时间函数 1. 获取当前日期的函数和获取当前时间的函数 /*获取当前日期的函数和获取当前时间的函数.将日期以'YYYY-MM-DD'或者'YYYYMMDD'格式返回 */ ...

  2. Java基础篇(04):日期与时间API用法详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.时间和日期 在系统开发中,日期与时间作为重要的业务因素,起到十分关键的作用,例如同一个时间节点下的数据生成,基于时间范围的各种数据统计和分 ...

  3. python笔记7:日期和时间

    Python 提供了一个 time 和 calendar 模块可以用于格式化日期和时间. 时间间隔是以秒为单位的浮点小数. 每个时间戳都以自从1970年1月1日午夜(历元)经过了多长时间来表示. 时间 ...

  4. 《Javascript权威指南》13号学习笔记:使用日期和时间

    一.创Date示例 1.Date类的方法和属性是非常不静,故,申请书Date属性和方法之前.必须创建Date类的实例. var date = new Date();  //以当前日期和时间创建实例. ...

  5. 吴裕雄--天生自然python学习笔记:Python3 日期和时间

    Python 程序能用很多方式处理日期和时间,转换日期格式是一个常见的功能. Python 提供了一个 time 和 calendar 模块可以用于格式化日期和时间. 时间间隔是以秒为单位的浮点小数. ...

  6. 基础笔记4(包装类,时间date. calendar

    1.包装类 基本类型和对象. 编译器会对基本类型和包装类进行自动拆箱,装箱处理 Interger  i=5; int i=new Interger(4); 一个缓存问题:以便提高效率 integer ...

  7. Golang基础笔记

    <基础> Go语言中的3个关键字用于标准的错误处理流程: defer,panic,recover. 定义一个名为f 的匿名函数: Go 不支持继承和重载. Go的goroutine概念:使 ...

  8. javascript中关于日期和时间的基础知识

    × 目录 [1]标准时间 [2]字符串 [3]闰年[4]月日[5]星期[6]时分秒 前面的话 在介绍Date对象之前,首先要先了解关于日期和时间的一些知识.比如,闰年.UTC等等.深入了解这些,有助于 ...

  9. R语言学习 第十一篇:日期和时间

    R语言的基础包中提供了三种基本类型用于处理日期和时间,Date用于处理日期,它不包括时间和时区信息:POSIXct/POSIXlt用于处理日期和时间,其中包括了日期.时间和时区信息.R内部在存储日期和 ...

  10. Java基础之一组有用的类——生成日期和时间(TryDateFormats)

    控制台程序. java.util包中含有相当多的类涉及日期和时间,包括Date类.Calendar类和GregorianCalendar类. Date类对象其实定义了精确到毫秒的时刻,从1970年1月 ...

随机推荐

  1. QUBO建模

    技术背景 QUBO(Quadratic Unconstrained Binary Optimization)模型是一种常用于求解组合优化问题的一种技术,它所能够求解的问题是这样定义的:给定一个布尔类型 ...

  2. ThinkPHP 中闭包在数组查询条件中的深度应用

    一.闭包与数组条件的协同原理 在 ThinkPHP 的查询体系中,数组条件是构建查询逻辑的核心载体.当数组条件的值为闭包(Closure)时,框架会自动将其解析为动态子查询生成器,实现运行时按需构建 ...

  3. 通过adb访问SQLite数据库

    根据<第一行代码>第二版进入到数据库的文件夹,但是如果照书本直接cd data/data/包名/databases 的话是会报错的,错误信息如下 cd: /data/data/包名 /da ...

  4. Java字节流--输出流OutputStream和输入流InputStream

    OutputStream和InputStream都是抽象类 OutputStream定义和InputStream定义 OutputStream InputStream public abstract ...

  5. 关闭windows10 Alt+Tab开打edge选项卡

    发现最近更新的windows10会使用快捷键Alt+Tab打开Edge的选项卡,很不适应,可喜的是微软提供了关闭的方法. 设置⚙->系统->多任务处理->Alt+Tab 设置为仅打开 ...

  6. C++基础——引用和指针篇

    一.指针(Pointer) 定义: 指针是一个变量,用于存储另一个变量的地址. 基本用法: #include <iostream> using namespace std; int mai ...

  7. 探秘Transformer系列之(32)--- Lookahead Decoding

    探秘Transformer系列之(32)--- Lookahead Decoding 目录 探秘Transformer系列之(32)--- Lookahead Decoding 0x00 概述 0x0 ...

  8. django实例(1)

    Urls.py from django.contrib import adminfrom django.conf.urls import urlfrom cmdb import viewsurlpat ...

  9. NCC Mocha v0.2.0 发布, 新增对 Metrics 的支持

    目录 项目简介 项目进度 v0.2.0 发布内容 快速体验 数据的发送 数据的查询 Trace 配置 Jaeger 数据源 Trace 数据的查询 Metrics 配置 Prometheus 数据源 ...

  10. FFmpeg开发笔记(六十二)Windows给FFmpeg集成H.266编码器vvenc

    ​<FFmpeg开发实战:从零基础到短视频上线>该书的第八章介绍了如何在Windows环境给FFmpeg集成H.264和H.265的编码器,如今H.266的编码器vvenc也日渐成熟,从7 ...