简介

在各个语言之中都有时间类型的处理,因为这个地球是圆的(我仿佛在讲废话),有多个时区,每个时区的时间不一样,在程序中有必要存在一种方式,或者说一种类型存储时间,还可以通过一系列的方法转换成不同国家的时间。

上问提到了时间、时区,还有一个概念为两个时间之间的差值,比如小熊每次可以坚持1个小时(锻炼),1个小时这种时间形容词就是时间间隔。

这就是三种时间处理的类型。

类型

TimeLocationDurationtime

Time时间类型

Time
type Time struct {
    sec int64 //秒
    nsec int32 //纳秒
    loc *Location //时区
}
Timegotime.Time*time.TimeIsZeroTime
Duration290
type Duration int64

时区

我们在使用time.Time类型一般都是Local时间,也就是本地时间,现在就是中国时间。

// 本地时间(如果是在中国,获取的是东八区时间)
 curLocalTime := time.Now()
 // UTC时间
 curUTCTime := time.Now().UTC()
timeLocationLocalUTC
LocalUTCtimeLocalLocalorm

默认就是Local中国时间!

问题:时区这个怎么设置?传字符串进去吗?

curLocalTime := time.Now() //这是local
curUtcTime := curLocalTime.In(time.UTC) //这是UTC
Time

小心有坑

timeStr := "2022-01-13 22:32:17"
    utcTimeObj, err := time.Parse("2006-01-02 15:04:05", timeStr)
    if err == nil {
        fmt.Println(utcTimeObj, utcTimeObj.Unix())
    }
UTC2022-01-13 22:32:17 +0000 UTCUTC
time.ParseInLocationtime.Local
localTimeObj, err := time.ParseInLocation("2006-01-02 15:04:05", timeStr, time.Local)
    if err == nil {
        fmt.Println(localTimeObj)
    }

它返回的是time 类型是吗?没错!这两个返回的都是time类型。

问:这个会用在哪个场景?

好问题,问到点子上了!

时间解析的使用场景

json

我们约定好用时间戳传递,总是有一些比较轴的同事一定要用字符串传输,你有没有这样的同事?如果非要使用字符串传输,在传递json的时候就需要反复的做解析相当的不友善。

但也不是不能做~~

UnmarshalJSONMarshalJSON
json
MarshalJSON
type Person struct {
    Id       int64  `json:"id"`
    Name     string `json:"name"`
    Birthday Time   `json:"_"`
}
Birthdayjson
json
jsonjsonjson-
Peoplejson.UnmarshalJSON
birthdays.Brithdays.tmps.Birthdaylocaltimetmptmppeople
tmp
*p = People(s.tmp)
Peopletmp
s.tmp*p

我定义的是新类型,并不是创建,实际上是一个强制类型转换。哈哈哈,我就是蔫坏。

关于时间处理的各种函数我也列在下面了,大家收藏看就行了。还是刚刚提到的各种完整代码。喜欢这篇文章的话点个在看,么么哒。

时间操作

获取当前时间

import time

func getCurTime() {
 // 本地时间(如果是在中国,获取的是东八区时间)
 curLocalTime := time.Now()
 // UTC时间
 curUTCTime := time.Now().UTC()
 fmt.Println(curLocalTime, curUTCTime)
}

时区设置

LocationtimeLocalUTC
LocalUTCtimeLocalLocalorm
func setTimeZone() {
 curLocalTime := time.Now()
 curUtcTime := curLocalTime.In(time.UTC)
 fmt.Println(curUtcTime)
}
time.LocalUTC

时间格式化(时间类型转字符串)

func time2TimeStr() {
 localTimeStr := time.Now().Format("2006-01-02 15:04:05")
 // UTC时间
 utcTimeStr := time.Now().UTC().Format("2006-01-02 15:04:05")
 fmt.Println(localTimeStr, utcTimeStr)
}

时间类型转时间戳

func getCurTimeStamp() {
 // 时间戳,精确到秒
 timestamp := time.Now().Unix()
 // 时间戳,精确到纳秒
 timestampNano := time.Now().UnixNano()
 fmt.Println(timestamp, timestampNano)
}

相关函数或方法:

time.Time

时间戳转时间类型

func timestamp2Time() {
 timestamp := time.Now().Unix()
 localTimeObj := time.Unix(timestamp, 0)
 fmt.Println(localTimeObj)
}

时间字符串转时间类型

func timeStr2Time() {
 timeStr := "2020-01-13 22:32:17"
 // 返回的是UTC时间 2020-01-13 22:32:17 +0000 UTC
 utcTimeObj, err := time.Parse("2006-01-02 15:04:05", timeStr)
 if err == nil {
  fmt.Println(utcTimeObj, utcTimeObj.Unix())
 }

 // 返回的是当地时间 2020-01-13 22:32:17 +0800 CST
 localTimeObj, err := time.ParseInLocation("2006-01-02 15:04:05", timeStr, time.Local)
 if err == nil {
  fmt.Println(localTimeObj)
 }
}

time.Parse 解析出来的时区却是 time.UTC(可以通过 Time.Location() 函数知道是哪个时区)。在中国,它们相差 8 小时。 所以,一般的,我们应该总是使用 time.ParseInLocation 来解析时间,并给第三个参数传递 time.Local。

时间计算

获取时间类型具体内容

t := time.Now()
fmt.Println("time.Now():", t) // 2020-10-24 22:10:53.328973 +0800 CST m=+0.006015101
year, month, day := t.Date()
fmt.Println("日期:", year, month, day) // 2020 October 24
fmt.Println("一年中的第几天:", t.YearDay()) // 298
fmt.Println("星期几:", t.Weekday()) // Saturday
fmt.Println("年:", t.Year()) // 2020
fmt.Println("月:", t.Month()) // October
fmt.Println("日:", t.Day()) // 24
fmt.Println("时:", t.Hour()) // 22
fmt.Println("分:", t.Minute()) // 10
fmt.Println("秒:", t.Second()) // 53
fmt.Println("纳秒:", t.Nanosecond()) // 328973000
fmt.Println("秒时间戳:", t.Unix()) // 1603548653
fmt.Println("纳秒时间戳:", t.UnixNano()) // 1603548653328973000
fmt.Println("毫秒时间戳:", t.UnixNano() / 1e6) // 1603548653328

时间加减

转换为Time类型比较容易做加减。

  • 时间点可以使用 Before、After 和 Equal 方法进行比较。
  • Sub 方法让两个时间点相减,生成一个 Duration 类型值(代表时间段)。
  • Add 方法给一个时间点加上一个时间段,生成一个新的 Time 类型时间点。
func addTime() {
 curTime := time.Now()
 // 加1秒
 addSecondTime := curTime.Add(time.Second * 1)
 // 加1分钟
 addMinuteTime := curTime.Add(time.Minute * 1)
 addMinuteTime2 := curTime.Add(time.Second * time.Duration(60*1))
 fmt.Println(addSecondTime, addMinuteTime, addMinuteTime2)
}
time.Hour
t := time.Now()
addOneHour := t.Add(time.Hour)
addTwoHour := t.Add(2 * time.Hour)
fmt.Println("增加1小时:", addOneHour)
fmt.Println("增加2小时:", addTwoHour)

subTwoHour := t.Add(-2 * time.Hour)
fmt.Println("减去2小时:", subTwoHour)

addDate := t.AddDate(1, 0, 0)
fmt.Println("增加1年:", addDate) // 2021-10-24 22:10:53.328973 +0800 CST

subDate := t.AddDate(-1, 0, 0)
fmt.Println("减去1年:", subDate) // 2019-10-24 22:10:53.328973 +0800 CST

before := t.Before(t.Add(time.Hour))
fmt.Println("before:", before)

after := t.After(t.Add(time.Hour))
fmt.Println("after:", after)

时间间隔(耗时)

t := time.Now()
time.Sleep(2e9) // 休眠2秒
delta := time.Now().Sub(t)
fmt.Println("时间差:", delta) // 2.0534341s

时间取整(向上取整向下取整)

t, _ := time.ParseInLocation("2006-01-02 15:04:05", "2016-06-13 15:34:39", time.Local)
// 整点(向下取整)
fmt.Println(t.Truncate(1 * time.Hour))
// 整点(最接近)
fmt.Println(t.Round(1 * time.Hour))

// 整分(向下取整)
fmt.Println(t.Truncate(1 * time.Minute))
// 整分(最接近)
fmt.Println(t.Round(1 * time.Minute))

t2, _ := time.ParseInLocation("2006-01-02 15:04:05", t.Format("2006-01-02 15:00:00"), time.Local)
fmt.Println(t2)

拓展

json时间转换

前后端建议使用时间戳传输,不要使用时间字符串可以大大省心,如果非要使用字符串传输,在传递json的时候就需要反复的做解析相当的不友善,但也不是不能做。 方式一、省心方式,重定义时间类型

type Time time.Time

const (
    timeFormart = "2006-01-02 15:04:05"
)

func (t *Time) UnmarshalJSON(data []byte) (err error) {
    now, err := time.ParseInLocation(`"`+timeFormart+`"`, string(data), time.Local)
    *t = Time(now)
    return
}

func (t Time) MarshalJSON() ([]byte, error) {
    b := make([]byte, 0, len(timeFormart)+2)
    b = append(b, '"')
    b = time.Time(t).AppendFormat(b, timeFormart)
    b = append(b, '"')
    return b, nil
}

func (t Time) String() string {
    return time.Time(t).Format(timeFormart)
}
type Person struct {
    Id       int64  `json:"id"`
    Name     string `json:"name"`
    Birthday Time   `json:"birthday"`
}
time.TimeTimejson

方式二、重写结构体方法

type Person struct {
    Id       int64  `json:"id"`
    Name     string `json:"name"`
    Birthday Time   `json:"_"`
}
func (p *People) UnmarshalJSON(b []byte) error {
 // 定义临时类型 用来接受非`json:"_"`的字段
 type tmp People
 // 用中间变量接收json串,tmp以外的字段用来接受`json:"_"`属性字段
 var s = &struct {
  tmp
  // string 先接收字符串类型,一会再转换
  Birthday string `json:"birthday"`
 }{}
 // 解析
 err := json.Unmarshal(b, &s)
 if err != nil {
  return err
 }
    localTimeObj, err := time.ParseInLocation("2006-01-02 15:04:05", s.Birthday, time.Local)
 if err == nil {
  return err
 }
 s.tmp.Birthday = localTimeObj
 // tmp类型转换回People,并赋值
 *p = People(s.tmp)
 return nil
}

作业

  1. 尝试写出时间戳转字符串的代码
  2. 尝试求上个月最后一天

喜欢点个赞吧,求求了!