Go 的時間操作基本上都用 time
包,比 C 的 time 函數和 timeval 等 struct 好用多了。不過 time
包還是有不少用法和其他語言不同的,所以有必要寫個筆記記錄一下。
本文鏈接:https://segmentfault.com/a/1190000020944345,首次發佈於雲+社區
*time.Location 類型
和其他文章不同的是,本文我從時區講起。在 Go 中,表示時區的類型是 type Location struct{...}
,代碼中使用 *time.Location
對象。
對於不嚴格的場景而言,可以獲取服務器所處的時區。但是本文不建議這個方法。因爲一臺服務器服務的時區是事先可知的,或者說是需要對接的時區信息也是已知的(比如對接微信,那麼時間肯定是東八區,而不是 UTC 時間)。獲得東八區時區的代碼如下:
loc, _ := time.LoadLocation("Asia/Shanghai")
之後這個 loc
可以作爲常量使用。是否能夠拿到時區,取決於機器本地的 zoneinfo 文件。後文也將使用這個 loc
作爲全局變量。
也可以自定義一個時區名稱,比如我們人工添加一個巴西利亞時間:
brazil := time.FixedZone("Brazil/Brasilia", -3*60*60)
這裏我們同時要知道一個很重要的概念,就是在 *Location
的加持下,一個 Time
類型本身是同時記錄着 UTC 時間和本地時間的,這就使得一個 Go 時間類型不會因爲時區而出現歧義,比如你可以用一個東八區的 Time
和西八區的 Time
隨意進行運算也不會出錯。這一特性使得時間類型變得極爲實用。
time.Time 類型
Time 創建及與 string 類型互轉
最基本的創建時間類型的接口:
t := time.Now()
此外,很多資料會跟你說採用 Local()
函數獲得本地時間,但基於前述理由,我建議固定指定 location:
t := time.Now().In(loc)
其他的幾個創建時間的函數:
-
t := time.Date(y, m, d, h, min, s, nsec, loc)
:用從年到納秒,以及時區信息,創建一個時間。參數均爲整型 -
t := time.Unix(s, nsec)
:使用 Unix UTC 時間戳來創建時間
如果將 time
類型轉換成字符串,採用以下函數:
s := t.Format("2006-01-02 15:04:05.000") // 輸出如:"2019-07-03 22:10:23.437"
通過已知格式的字符串解析時間的函數爲:
t, err := time.ParseInLocation("2006-01-02 15:04:05", s, loc)
略微瞭解過 Go time 的人都知道,Go 時間格式化採用的並不是傳統的 YYYY-MM-DD hh:mm:ss
格式。這裏有一份對應表,便於組裝字符串時查閱——以時間 1609-08-12 19:02:35 PM +03:00 Aug Wed PDT
爲例,這個時間的含義是:1609年9月12日,北美太平洋地區時間下午7:02:35,應用以下格式的輸出舉例:
類型 | 格式符 | 輸出舉例 | 說明 |
---|---|---|---|
年 | 2006 |
1609 | |
| 06 |
09 | |
月 | 01 |
08 | |
| 1 |
8 | |
| Jan |
Aug | |
| January |
August | |
日 | 02 |
02 | |
| 2 |
2 | |
周幾 | Mon |
Wed | 注意,格式符裏沒有數字化的周幾信息,需要自己拼。參見後文 |
| Monday |
Wednesday | |
小時 | 03 |
07 | 12小時制,01~12,12點表示正午 |
| 3 |
7 | 12小時制,1~12,12點表示正午 |
| 15 |
19 | 24小時制,0~23,永遠都是兩位數字,不足2位補0,如早上7點:"07" |
分鐘 | 04 |
02 | |
| 4 |
2 | |
秒 | 05 |
35 | |
| 5 |
35 | |
上 / 下午 | PM |
PM | |
小數點後秒數 | .000 |
.123 | |
| .000000 |
.123456 | |
| .000000000 |
.123456789 | 實際上,可以是小於9位的任意位數的0,只要是以 . 打頭 |
時區偏移 | -0700 |
+0300 | |
| -07:00 |
+03:00 | |
| Z0700 |
+0300 | |
| Z07:00 |
+03:00 | |
時區名 | MST |
PDT | |
如果需要自定義的星期幾名,需要搭配 time
的 Weekday()
函數,返回 Weekday
類型(等同於 int 類型),以 0 代表星期天。如下:
wday := []string{"日", "一", "二", "三", "四", "五", "六"}
s := fmt.Sprintf(t.Format("2006-01-02 15:04:05 星期%s"), wday[t.Weekday()])
fmt.Println(s) // 1609-08-12 19:02:35 星期三
時間比較
time.Time
提供了一個 IsZero()
函數來判斷時間類型是否爲空的狀態。空時間所指代的時間是 UTC 時間公元元年 00:00:00,這是 t := time.Time{}
所生成的時間。
主要的比較函數如下:
func (t Time) IsZero() bool
-
func (t Time) After(u Time) bool
:判斷是否在另一個時間之後 -
func (t Time) Before(u Time) bool
:判斷是否在另一個時間之前 -
func (t Time) Equal(u Time) bool
:判斷兩個時間是否相等 -
func (t Time) Sub(u Time) Duration
:計算兩個時間之間的差。Duration
類型會在下一小節說明- 注意這個和
Add()
函數的使用場景是完全不同的,不得不吐槽一下兩者的命名……
- 注意這個和
時間運算
-
func (t Time) Add(d Duration)
:加上一個時間段,返回一個新的時間。d 也可以是負的時間 -
func (t Time) AddDate(年, 月, 日)
:加上一個日期,獲返回一個新的時間。各參數均爲整型,可以是負數- 比如
t.AddDate(0, 1, -1)
表示加上一個月之後再減一天
- 比如
-
func Since(u Time) Duration
:表示當前時間與一個過去的時間的差;如果被比較的時間是將來時間的話,那麼返回負的 Duration- 等價於
time.Now().Sub(t)
- 等價於
-
func Until(u Time) Duration
:這是
Since` 的反邏輯- 等價於
t.Sub(time.Now())
- 等價於
獲取時間的基本函數
以下函數可以獲取時間的基本信息,返回均爲整型,很好理解:
t.Year()
t.Month()
t.Day()
-
t.Weekday()
:返回以星期天爲 0 的星期幾數值 -
t.YearDay()
:返回處於每一年的第幾天 t.Hour()
t.Minute()
t.Second()
-
t.Nanosecond()
:時間的毫秒部分,int
類型 -
t.Unix()
:返回 Unix UTX 時間戳,int64
類型
Duration 類型
Duration
類型的作用是用來表示兩個時間點之間的時間段。Duration 實際上是 int64
類型,單位是納秒。但在實際編碼中,基本上不會直接賦值一個數字,而是用 time
提供的常量,如:
tenSecs := 10 * time.Second
twoHours := 2 * time.Hour
其他常量還有:
const (
Nanosecond Duration = 1
Microsecond = 1000 * Nanosecond
Millisecond = 1000 * Microsecond
Second = 1000 * Millisecond
Minute = 60 * Second
Hour = 60 * Minute
)
此外,Duration 類型還有下面的實用的方法:
-
func (d Duration) Round(m Duration) Duration
:表示按照m
給定的單位,返回四捨五入 -
func (d Duration) Truncate(m Duration) Duration
:表示按照m
給定的單位,返回舍尾數計算 -
func (d Duration) String() string
:給出幾小時幾分鐘幾秒的字符串格式,非常適合打日誌 -
Hours(), Minutes(), Seconds()
:返回float64
格式,也就是小數形式的小時 / 分鐘 / 秒數 -
Nanoseconds()
:返回int64
類型的納秒數
參考資料
本文章採用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議 進行許可。
原作者: amc,歡迎轉載,但請註明出處。
原文標題:Go 語言 time 包常用用法筆記
發佈日期:2017-07-03
原文鏈接:https://cloud.tencent.com/developer/article/1456484。