Go 标准库 time 包之 Location 类型 ( 上 )
时区 ( Location
) 想必大家不陌生,其实啊,它有另一个更通用的英文 time zone
,不过呢,编程语言中爱用 loc
或 tzinfo
作为变量名。
我们先来了解下时区方面的知识。
大家都知道,地球分为 24 时区,有东 12 区和西 12 区,每个区跨越 7.5 度。
每个时区的中央经线上的时间就是这个时区内统一采用的时间,称为区时。相邻两个时区的时间相差1小时
例如,我国东8区的时间总比泰国东7区的时间早1小时,而比日本东9区的时间晚1小时。因此,出国旅行的人,必须随时调整自己的手表,才能和当地时间相一致。凡向西走,每过一个时区,就要把表向前拨1小时(比如2点拨到1点);凡向东走,每过一个时区,就要把表向后拨1小时(比如1点拨到2点)
格林尼治标准时间 ( GMT )
0 区是本初子午线经过的时区,其实又称为 格林尼治标准时间 ( GMT ) ,指位于英国伦敦郊区的皇家格林尼治天文台当地的标准时间,因为本初子午线被定义为通过那里的经线。
原因在于地球每天的自转是有些不规则的,而且正在缓慢减速,因此格林尼治时间基于天文观测本身的缺陷,已经不再被作为标准时间使用。
现在的标准时间,是由原子钟报时的协调世界时 ( UTC ) 来决定
UTC
协调世界时,英语:Coordinated Universal Time,法语:Temps Universel Coordonné,简称 UTC ,是最主要的世界时间标准
如果时间是以协调世界时 ( UTC ) 表示,则在时间后面直接加上一个 Z
( 不加空格 )
Z
是协调世界时中 0
时区的标志。因此,09:30 UTC
就写作 09:30Z
或是 0930Z
。14:45:15 UTC
则为 14:45:15Z
或144515Z
。
UTC 时间也被叫做祖鲁时间,因为在北约音标字母中用
Zulu
表示Z
UTC 偏移量
UTC 偏移量是协调世界时 ( UTC ) 和特定时区的日期与时间差异,其单位为小时和分钟
UTC 偏移量通常以 ±[hh]:[mm]
、 ±[hh][mm]
或 ±[hh]
的格式显示
所以,如果被描述的时间比 UTC 早一小时 ( 例如柏林的冬季时间 ),UTC 的偏移量将是 +01:00
、+0100
或简单显示为 +01
北京时间
北京时间,又名中国标准时间,是中国大陆的标准时间,比协调世界时快八小时 ( 即 UTC+8
) ,与香港、澳门、台北、吉隆坡、新加坡等地的标准时间相同
Location
类型
了解了时区和 UTC 、UTC 偏移量相关的知识后,我们就可以很轻松的理解 Location
这个类型了
Location
时区,是将一个时刻 ( Time t ) 映射到当时正在使用的区域 ( 时区 ) 。通常,Location
表示在地理区域中使用的时间偏移的集合,例如中欧的 CEST
和 CET
经过前面的学习,大家应该都知道,Time
对象表示的是一个时刻,是某个时间点以来经过的 wall time,这个和所在地域是无关的。但为了表示所在地域的更好理解的时间,已经有了这个说法
我们先来看看 Location
类型的定义
type Location struct { // contains filtered or unexported fields }
看起来没有什么公开的属性,我们看看源码有那些私有属性
type Location struct { name string zone []zone tx []zoneTrans // Most lookups will be for the current time. // To avoid the binary search through tx, keep a // static one-element cache that gives the correct // zone for the time when the Location was created. // if cacheStart <= t < cacheEnd, // lookup can return cacheZone. // The units for cacheStart and cacheEnd are seconds // since January 1, 1970 UTC, to match the argument // to lookup. cacheStart int64 cacheEnd int64 cacheZone *zone }
私有属性真的很多,我们列一个表解释吧
属性 | 说明 |
---|---|
name | 时区的名称 |
zone | 时区 |
tx | 时区转换方式 |
cacheStart | 时区偏移量的缓存开始 |
cacheEnd | 时区偏移量的结束 |
cacheZone | 缓存的时区 |
和时区有关的变量
同时,time
包中又定义了几个和 Location
相关的变量
-
var utcLoc = Location{name: "UTC"}
这是一个仅限于
time
包内部使用的变量,用于表示通用协调时间 ( UTC ),也就是 0 时区,偏移量为 0 -
var UTC *Location = &utcLoc
变量 UTC 表示通用协调时间 ( UTC ),注意,这个变量的首字母是大写的,也就是说可以在
time
包外使用 -
var localLoc Location
变量
locaLoc
表示的是一个本地时间,如果时区对象是localLoc
,那么只会初始化一次翻看源码,我们可以发现以下代码
var localLoc Location var localOnce sync.Once func (l *Location) get() *Location { if l == nil { return &utcLoc } if l == &localLoc { localOnce.Do(initLocal) } return l }
如果你仔细翻看源码,就会发现,机会所有的
Location
类型的方法都会先调用get()
方法来初始化时区 -
var Local *Location = &localLoc
定义一个本地的时区,因为首字母大写,所以可以在
time
包外使用如果你看过源码,就会知道,其实这个
Local
在刚导入包的时候是未知的,我们写一段代码来看看package main import ( "fmt" "time" ) const UINT32_MAX uint32 = ^uint32(0) func main() { fmt.Printf("time.Local 的初始值为:%#v\n", time.Local) }
运行结果如下
time.Local 的初始值为:&time.Location{name:"", zone:[]time.zone(nil), tx:[]time.zoneTrans(nil), cacheStart:0, cacheEnd:0, cacheZone:(*time.zone)(nil
但,一旦我们生成了一个
Time
对象并输出其字符串表现形式的时候,就立刻初始化了package main import ( "fmt" "time" ) const UINT32_MAX uint32 = ^uint32(0) func main() { fmt.Printf("time.Local 的初始值为:%#v\n", time.Local) t := time.Now() fmt.Println("当前时间是:", t) fmt.Printf("time.Local 的值为:%#v\n", time.Local) }
运行结果为
time.Local 的初始值为:&time.Location{name:"", zone:[]time.zone(nil), tx:[]time.zoneTrans(nil), cacheStart:0, cacheEnd:0, cacheZone:(*time.zone)(nil)} 当前时间是: 2018-08-28 22:16:45.72168 +0800 CST m=+0.000963491 time.Local 的值为:&time.Location{name:"Local", zone:[]time.zone{time.zone{name:"CDT", offset:32400, isDST:true}, time.zone{name:"CST", offset:28800, isDST:false}}, tx:[]time.zoneTrans{time.zoneTrans{when:-933494400, index:0x0, isstd:false, isutc:false}, time.zoneTrans{when:-923130000, index:0x1, isstd:false, isutc:false}, time.zoneTrans{when:-908784000, index:0x0, isstd:false, isutc:false}, time.zoneTrans{when:-891594000, index:0x1, isstd:false, isutc:false}, time.zoneTrans{when:515520000, index:0x0, isstd:false, isutc:false}, time.zoneTrans{when:527007600, index:0x1, isstd:false, isutc:false}, time.zoneTrans{when:545155200, index:0x0, isstd:false, isutc:false}, time.zoneTrans{when:558457200, index:0x1, isstd:false, isutc:false}, time.zoneTrans{when:576604800, index:0x0, isstd:false, isutc:false}, time.zoneTrans{when:589906800, index:0x1, isstd:false, isutc:false}, time.zoneTrans{when:608659200, index:0x0, isstd:false, isutc:false}, time.zoneTrans{when:621961200, index:0x1, isstd:false, isutc:false}, time.zoneTrans{when:640108800, index:0x0, isstd:false, isutc:false}, time.zoneTrans{when:653410800, index:0x1, isstd:false, isutc:false}, time.zoneTrans{when:671558400, index:0x0, isstd:false, isutc:false}, time.zoneTrans{when:684860400, index:0x1, isstd:false, isutc:false}}, cacheStart:684860400, cacheEnd:9223372036854775807, cacheZone:(*time.zone)(0xc0000680e0)}
结束语
篇幅有限,剩下的方法我们下一章节再来讲述,下一章节,我们还会顺带讲讲 zone[]
那一坨代码到底是啥回事