Golang我的专题程序员

Golang packge time

2019-02-21  本文已影响3人  _AlphaBaby_

time 包的官方文档

中文
英文
本文章不是对time包文档的重复,旨在加深对time实现的理解上,以上是文档可以进行查看。

time 包中一些官方定义的结构的认识

go针对时间常量的定义:

const (
    Nanosecond  Duration = 1                  //纳秒
    Microsecond          = 1000 * Nanosecond  //微秒
    Millisecond          = 1000 * Microsecond // 毫秒
    Second               = 1000 * Millisecond // 秒
    Minute               = 60 * Second        // 分
    Hour                 = 60 * Minute        // 时
)
type Weekday int  // 定义星期

const (
    Sunday Weekday = iota
    Monday
    Tuesday
    Wednesday
    Thursday
    Friday
    Saturday
)
type Month int  // 定义月份

const (
    January Month = 1 + iota
    February
    March
    April
    May
    June
    July
    August
    September
    October
    November
    December
)

主要的结构体

type Time struct {
    // sec gives the number of seconds elapsed since
    // January 1, year 1 00:00:00 UTC.
    sec int64  //  sec表示从公元1年1月1日00:00:00UTC到要表示的整数秒数, 
    // nsec specifies a non-negative nanosecond
    // offset within the second named by Seconds.
    // It must be in the range [0, 999999999].
    nsec int32  // nsec表示余下的纳秒数, 
    // loc specifies the Location that should be used to
    // determine the minute, hour, month, day, and year
    // that correspond to this Time.
    // The nil location means UTC.
    // All UTC times are represented with loc==nil, never loc==&utcLoc.
    loc *Location  //  loc表示时区. sec和nsec处理没有歧义的时间值, loc处理偏移量.
}
type Duration int64  // 针对时间长度的定义,单位为纳秒,两个时间点之间经过的纳秒数
// Location代表一个地点,以及该地点所在的时区信息。北京时间可以使用 Asia/Shanghai
type Location struct {
    name string
    zone []zone
    tx   []zoneTrans
    cacheStart int64
    cacheEnd   int64
    cacheZone  *zone
}

针对以上的结构体和类型,go提供了很多方法。

1. time.Time

time.Time 代表一个纳秒精度的时间点。
time.Time 主要的方法有:获取时间点,获取时间相关信息,时间比较,计算和序列化操作。

1.1 获取时间
var t time.Time
t = time.Now() // 返回一个本地时间, 返回的类型是一个 time.Time 的一个结构体
fmt.Println("time.Now():", t)

// 根据时间戳返回本地时间 中国的本地时间也就是东八区的区时
t = time.Unix(12342342410, 111111)
fmt.Println("time.Unix: ", t)

// 返回指定时间 把这个确定的时间转为一个时间time.Time结构体类型
t = time.Date(2019, time.Month(2), 20, 1, 30, 30, 1111111, time.Local)
fmt.Println("time.Date: ", t)

// 按照第一参数的格式,读取后面的时间,格式该怎么用参考后面时间序列化
dt, err := time.Parse("2006-01-02 15:04:05", "2018-04-23 12:24:51")
if err != nil {
    fmt.Println("读取错误")
}
fmt.Println(dt.Unix(), dt)
1.2 时间格式化

计算机中表示时间使用时间戳的形式来表示,但是这是我们人不能看懂的,所以就需要序列化(也就是用一个我们人能看懂的格式来表示这个时间)。
func (t Time) Format(layout string) string // 按照指定格式序列化time.Time
Format函数需要传递一个字符串,这个字符串就是我们需要给出的一个格式,Format函数会根据我们给定的格式把time.Time类型序列化。

t = time.Now()
timeStr := t.Format("年月日:2006-01-02 时分秒:15:04:05 英文的星期:Mon 英文月份:Jan 数字一个月中的号数:2 时区:-0700 MST")
fmt.Println(timeStr)
timeStr = t.Format("15:04:05 2006/01/02  ")
fmt.Println(timeStr)

比如年份:短年份06,长年份2006,
月份:01,Jan,January
日:02,2,_2
时:15,3,03
分:04, 4
秒:05, 5
时区:-0700 MST

因为都不相等所以通过遍历layout就可以switch case解析出每个区块的意义和在字符串中的位置,这样输入对应格式的时间字符串就可以顺利解析出来。
这样layout也可以自定义,而且顺序任意,只要符合下列每个区块定义的规则即可,代码中的注释就是规则写法,如果要设置要给复杂的格式参考如下:

const (
    _                        = iota
    stdLongMonth             = iota + stdNeedDate  // "January"
    stdMonth                                       // "Jan"
    stdNumMonth                                    // "1"
    stdZeroMonth                                   // "01"
    stdLongWeekDay                                 // "Monday"
    stdWeekDay                                     // "Mon"
    stdDay                                         // "2"
    stdUnderDay                                    // "_2"
    stdZeroDay                                     // "02"
    stdHour                  = iota + stdNeedClock // "15"
    stdHour12                                      // "3"
    stdZeroHour12                                  // "03"
    stdMinute                                      // "4"
    stdZeroMinute                                  // "04"
    stdSecond                                      // "5"
    stdZeroSecond                                  // "05"
    stdLongYear              = iota + stdNeedDate  // "2006"
    stdYear                                        // "06"
    stdPM                    = iota + stdNeedClock // "PM"
    stdpm                                          // "pm"
    stdTZ                    = iota                // "MST"
    stdISO8601TZ                                   // "Z0700"  // prints Z for UTC
    stdISO8601SecondsTZ                            // "Z070000"
    stdISO8601ShortTZ                              // "Z07"
    stdISO8601ColonTZ                              // "Z07:00" // prints Z for UTC
    stdISO8601ColonSecondsTZ                       // "Z07:00:00"
    stdNumTZ                                       // "-0700"  // always numeric
    stdNumSecondsTz                                // "-070000"
    stdNumShortTZ                                  // "-07"    // always numeric
    stdNumColonTZ                                  // "-07:00" // always numeric
    stdNumColonSecondsTZ                           // "-07:00:00"
    stdFracSecond0                                 // ".0", ".00", ... , trailing zeros included
    stdFracSecond9                                 // ".9", ".99", ..., trailing zeros omitted

    stdNeedDate  = 1 << 8             // need month, day, year
    stdNeedClock = 2 << 8             // need hour, minute, second
    stdArgShift  = 16                 // extra argument in high bits, above low stdArgShift
    stdMask      = 1<<stdArgShift - 1 // mask out argument
)

除了可以自己自定义格式外,go还给了很多标准化的格式

const (
    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 with numeric zone
    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 with numeric zone
    RFC3339     = "2006-01-02T15:04:05Z07:00"
    RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
    Kitchen     = "3:04PM"
    // Handy time stamps.
    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"
)
// 获取指定时间在UTC 时区(零时区)的时间表示
t = time.Now()
t_by_utc := t.UTC()
fmt.Println("'t.UTC': ", t_by_utc)

// 获取本地时间表示
t_by_local := t.Local()
fmt.Println("'t.Local': ", t_by_local)

// 时间在指定时区的表示
t_in := t.In(time.UTC)
fmt.Println("'t.In': ", t_in)
1.3 时间序列化
b,err := t.MarshalJSON() // 序列化
if err != nil {
    log.Println(" MarshalJSON error ")
}
fmt.Println(string(b))

t.AddDate(1,1,1)
t.UnmarshalJSON(b)  // 反序列化
fmt.Println(t)
1.4 时间比较与计算
t := time.Date(0, 0, 0, 12, 15, 30, 918273645, time.UTC)
round := []time.Duration{
    time.Nanosecond,
    time.Microsecond,
    time.Millisecond,
    time.Second,
    2 * time.Second,
    time.Minute,
    10 * time.Minute,
    time.Hour,
}
for _, d := range round {
    fmt.Printf("t.Round(%6s) = %s\n", d, t.Round(d).Format("15:04:05.999999999"))
}

输出: 对时间进行保留

t.Round(   1ns) = 12:15:30.918273645
t.Round(   1us) = 12:15:30.918274
t.Round(   1ms) = 12:15:30.918
t.Round(    1s) = 12:15:31
t.Round(    2s) = 12:15:30
t.Round(  1m0s) = 12:16:00
t.Round( 10m0s) = 12:20:00
t.Round(1h0m0s) = 12:00:00

time.Duration

time.Duration 表示的是时间段,时间段的定义在文章开头部分
常用的时间段。没有定义一天或超过一天的单元,以避免夏时制的时区切换的混乱。

// time.Duration 时间段
fmt.Println("time.Duration 时间段")
d := time.Duration(10000000000000)

fmt.Printf("'String: %v', 'Nanoseconds: %v', 'Seconds: %v', 'Minutes: %v', 'Hours: %v'\n",
    d.String(), d.Nanoseconds(), d.Seconds(), d.Minutes(), d.Hours())
d,err  = time.ParseDuration("-1h45m30s")
if err != nil {
    log.Println("ParseDuration 解析错误")
}
fmt.Printf("'String: %v', 'Nanoseconds: %v', 'Seconds: %v', 'Minutes: %v', 'Hours: %v'\n",
    d.String(), d.Nanoseconds(), d.Seconds(), d.Minutes(), d.Hours())

time.Location

time.Location的结构在文章开头给出了。

IANA

var local *time.Location
local, ok := time.LoadLocation("Asia/Shanghai")
fmt.Printf("%v, %T, %v\n", local, local, ok)

local, ok = time.LoadLocation("Asia/Chongqing")
fmt.Printf("%v, %T, %v\n", local, local, ok)

var cstZone = time.FixedZone("CST", 8*3600)       // 东八
fmt.Println("SH : ", time.Now().In(cstZone).Format("2006-01-02 15:04:05"))

更多的时区相关的东西可以参考这里

time.Sleep() 常用

查看 runtime/time.go文件中的timeSleep可知,Sleep的是通过 Timer 实现的,把当前 goroutine 作为 arg 参数(getg())

time.Timer time.Ticker

参考我的另一篇笔记:Golang time.Timer and time.Ticker

参考
Go 标准库介绍二: time
深入理解GO时间处理(time.Time)
golang包time用法详解
Time包

上一篇 下一篇

猜你喜欢

热点阅读