Go語言標準庫time之日期和時間相關函式

尹正杰發表於2024-07-19

目錄
  • 一.時間型別
  • 二.Location和time zone
    • 1.時區介紹
    • 2.時區案例
  • 三.時間戳unix time
    • 1.Unix Time概述
    • 2.獲取時間戳
    • 3.將時間戳轉為時間物件
  • 四.時間間隔設定及比較
    • 1.時間間隔型別的常量
    • 2.Add
    • 3.sub
    • 4.Equal
    • 5.Before
    • 6.After
  • 五.定時器
    • 1.定時器概述
    • 2.定時器案例
  • 六.時間格式化
    • 1.時間格式化
    • 2.參考案例
  • 七.解析字串的時間
    • 1.解析時間的函式
    • 2.Parse從文字解析時間
    • 3.ParseInLocation從文字解析時間
  • 八.練習題
    • 1.獲取當前時間,格式化輸出為"2030/01/01 23:30:05"格式
    • 2.編寫程式統計一段程式碼的執行耗時時間,單位精確到微秒。

一.時間型別

package main

import (
	"time"
	"fmt"
)

func main() {
	// 獲取當前時間物件,後從時間物件中可以獲取到年、月、日、時、分、秒等資訊。
	now := time.Now()
	fmt.Printf("current time: [%v]\n", now)

	// 年
	year := now.Year()
	// 月
	month := now.Month()
	// 日
	day := now.Day()
	// 小時
	hour := now.Hour()
	// 分鐘
	minute := now.Minute()
	// 秒
	second := now.Second()
	fmt.Println(year, month, day, hour, minute, second)
}

二.Location和time zone

1.時區介紹

Go語言中使用location來對映具體的時區。時區(Time Zone)是根據世界各國家與地區不同的經度而劃分的時間定義,全球共分為24個時區。

中國差不多跨5個時區,但為了使用方便只用東八時區的標準時即北京時間為準。在日常編碼過程中使用時間物件的時候一定要注意其時區資訊。

2.時區案例

package main

import (
	"fmt"
	"time"
)

func main() {
	// 中國沒有夏令時,使用一個固定的8小時的UTC時差(東八區,UTC +08:00),對於很多其他國家需要考慮夏令時。
	timezone := int((8 * time.Hour).Seconds())

	// FixedZone 返回始終使用給定區域名稱和偏移量(UTC 以東秒)的Location。UTC +08:00
	shanghaiTimezone := time.FixedZone("Asia/Shanghai", timezone)

	// 如果當前系統有時區資料庫,則可以載入一個位置得到對應的時區,例如,載入紐約所在的時區,UTC -05:00
	newYorkTimezone, _ := time.LoadLocation("America/New_York")

	utc := time.Date(2009, 1, 1, 12, 0, 0, 0, time.UTC)
	shanghai := time.Date(2009, 1, 1, 20, 0, 0, 0, shanghaiTimezone)
	NewYork := time.Date(2009, 1, 1, 7, 0, 0, 0, newYorkTimezone)

	// 北京時間(東八區)比UTC早8小時,所以上面兩個時間看似差了8小時,但表示的是同一個時間
	t1 := utc.Equal(shanghai)

	// 紐約(西五區)比UTC晚5小時,所以上面兩個時間看似差了5小時,但表示的是同一個時間
	t2  := utc.Equal(NewYork)


	fmt.Printf("[%v] = [%v] => [%t]\n",utc,shanghai,t1)
	fmt.Printf("[%v] = [%v] => [%t]\n",utc,NewYork,t2)
}

三.時間戳unix time

1.Unix Time概述

Unix Time是自1970年1月1日 00:00:00 UTC至當前時間經過的總秒數。下面的程式碼片段演示瞭如何基於時間物件獲取到Unix 時間。

2.獲取時間戳

package main

import (
	"fmt"
	"time"
)

func main() {
	// 獲取當前時間
	now := time.Now()

	// 秒級時間戳
	timestamp := now.Unix()

	// 毫秒時間戳 Go1.17+
	milli := now.UnixMilli()

	// 微秒時間戳 Go1.17+
	micro := now.UnixMicro()

	// 納秒時間戳
	nano := now.UnixNano()

	fmt.Printf("秒級時間戳: %v\n毫級時間戳: %v\n微級時間戳: %v\n納級時間戳: %v\n", timestamp, milli, micro, nano)
}

3.將時間戳轉為時間物件

package main

import (
	"fmt"
	"time"
)

func main() {
	// 獲取北京時間所在的東八區時區物件
	secondsEastOfUTC := int((8 * time.Hour).Seconds())
	beijing := time.FixedZone("Beijing Time", secondsEastOfUTC)

	// 北京時間 2022-02-22 22:22:22.000000022 +0800 CST
	t := time.Date(2030, 11, 11, 23, 59, 59, 59, beijing)

	var (
		sec  = t.Unix()
		msec = t.UnixMilli()
		usec = t.UnixMicro()
	)

	// 將秒級時間戳轉為時間物件(第二個引數為不足1秒的納秒數)
	t1 := time.Unix(sec, 99999)

	// 毫秒級時間戳轉為時間物件
	t2 := time.UnixMilli(msec)

	// 微秒級時間戳轉為時間物件
	t3 := time.UnixMicro(usec)

	fmt.Printf("t1 = [%v], t2 = [%v], t3 = [%v]\n", t1, t2, t3)
}

四.時間間隔設定及比較

1.時間間隔型別的常量

time.Duration是time包定義的一個型別,它代表兩個時間點之間經過的時間,以納秒為單位。

time.Duration表示一段時間間隔,可表示的最長時間段大約290年。

time包中定義的時間間隔型別的常量如下:

const (
    Nanosecond  Duration = 1
    Microsecond          = 1000 * Nanosecond
    Millisecond          = 1000 * Microsecond
    Second               = 1000 * Millisecond
    Minute               = 60 * Second
    Hour                 = 60 * Minute
)


例如:time.Duration表示1納秒,time.Second表示1秒。

2.Add

package main

import (
	"fmt"
	"time"
)

func main() {
	now := time.Now()
	/*
		Go語言的時間物件有提供Add方法如下:
			func (t Time) Add(d Duration) Time
	*/

	later := now.Add(time.Hour) // 當前時間加1小時後的時間

	fmt.Printf("now = [%v] later = [%v]\n", now, later)
}

3.sub

package main

import (
	"fmt"
	"time"
)

func main() {
	now := time.Now()
	

	t1, _ := time.Parse("2006/01/02 15:04:05", "2024/08/20 11:25:20")

	/*
		Go語言的時間物件有提供Sub方法如下:
			func (t Time) Sub(u Time) Duration
	*/
	t2 := now.Sub(t1) // 比較現在和t1時間相差的時間

	fmt.Printf("now = [%v] t2 = [%v]\n", now, t2)
}

4.Equal

package main

import (
	"fmt"
	"time"
)

func main() {

	t1, _ := time.Parse("2006/01/02 15:04:05", "2030/08/20 11:25:20")

	t2, _ := time.Parse(time.RFC3339, "2030-08-20T19:25:20+08:00")

	/*
		Go語言的時間物件有提供Equal方法如下:
			func (t Time) Equal(u Time) bool

		判斷兩個時間是否相同,會考慮時區的影響,因此不同時區標準的時間也可以正確比較。

		本方法和用t==u不同,這種方法還會比較地點和時區資訊。
	*/
	flag := t1.Equal(t2)

	fmt.Printf("[%v] = [%v] ---> [%t]\n", t1, t2, flag)
}

5.Before

package main

import (
	"fmt"
	"time"
)

func main() {

	t1, _ := time.Parse("2006/01/02 15:04:05", "2030/08/21 12:25:20")

	t2, _ := time.Parse(time.RFC3339, "2030-08-30T19:25:20+08:00")

	/*
		Go語言的時間物件有提供Before方法如下:
				func (t Time) Before(u Time) bool

		如果t代表的時間點在u之前,返回真;否則返回假。
	*/
	flag := t1.Before(t2)

	fmt.Printf("[%v] = [%v] ---> [%t]\n", t1, t2, flag)
}

6.After

package main

import (
	"fmt"
	"time"
)

func main() {

	t1, _ := time.Parse("2006/01/02 15:04:05", "2030/09/21 12:25:20")

	t2, _ := time.Parse(time.RFC3339, "2030-08-30T19:25:20+08:00")

	/*
		Go語言的時間物件有提供Before方法如下:
			func (t Time) After(u Time) bool
			
		如果t代表的時間點在u之後,返回真;否則返回假。
	*/
	flag := t1.After(t2)

	fmt.Printf("[%v] = [%v] ---> [%t]\n", t1, t2, flag)
}

五.定時器

1.定時器概述

使用time.Tick(時間間隔)來設定定時器,定時器的本質上是一個通道(channel)。

2.定時器案例

package main

import (
	"fmt"
	"time"
)

func main() {
	// //定義一個1秒間隔的定時器,如果想要換成每分鐘,可以使用"time.Minute",依此類推...
	ticker := time.Tick(time.Second)

	for i := range ticker {
		//每秒都會執行的任務
		fmt.Println(i)
	}
}

六.時間格式化

1.時間格式化

time.Format函式能夠將一個時間物件格式化輸出為指定佈局的文字表示形式,需要注意的是Go語言中時間格式化的佈局不是常見的Y-m-d H:M:S,而是使用"2006-01-02 15:04:05.000"(記憶口訣為2006 1 2 3 4 5)。

其中:
	- 2006:年(Y)
	- 01:月(m)
	- 02:日(d)
	- 15:時(H)
	- 04:分(M)
	- 05:秒(S)
	
	
溫馨提示:
	(1)如果想格式化為12小時格式,需在格式化佈局中新增PM。
	(2)小數部分想保留指定位數就寫0,如果想省略末尾可能的0就寫9。

2.參考案例

package main

import (
	"fmt"
	"time"
)

func main() {
	// 獲取當前時間物件,後續方便基於對時間物件進行格式化操作
	now := time.Now()

	// 格式化的模板為 2006-01-02 15:04:05

	// 24小時制
	fmt.Println(now.Format("2006-01-02 15:04:05.000 Mon Jan"))

	// 12小時制
	fmt.Println(now.Format("2006-01-02 03:04:05.000 PM Mon Jan"))

	// 小數點後寫0,因為有3個0所以格式化輸出的結果也保留3位小數
	fmt.Println(now.Format("2006/01/02 15:04:05.000"))

	// 小數點後寫9,會省略末尾可能出現的0
	fmt.Println(now.Format("2006/01/02 15:04:05.999"))

	// 只格式化時分秒部分
	fmt.Println(now.Format("15:04:05"))

	// 只格式化日期部分
	fmt.Println(now.Format("2006.01.02"))
}

七.解析字串的時間

1.解析時間的函式

對於從文字的時間表示中解析出時間物件,time包中提供了time.Parse和time.ParseInLocation兩個函式。

其中time.Parse在解析時不需要額外指定時區資訊。

time.ParseInLocation函式需要在解析時額外指定時區資訊。

2.Parse從文字解析時間

package main

import (
	"fmt"
	"time"
)

func main() {
	// 在沒有時區指示符的情況下,time.Parse 返回UTC時間
	t1, _ := time.Parse("2006/01/02 15:04:05", "2030/10/05 11:25:20")

	// 在有時區指示符的情況下,time.Parse 返回對應時區的時間表示
	// RFC3339     = "2006-01-02T15:04:05Z07:00"
	t2, _ := time.Parse(time.RFC3339, "2030-10-05T11:25:20+08:00")

	fmt.Printf("t1 = [%v], t2 = [%v]\n", t1, t2)
}

3.ParseInLocation從文字解析時間

package main

import (
	"fmt"
	"time"
)

func main() {
	now := time.Now()

	// 載入時區
	timezone, _ := time.LoadLocation("Asia/Shanghai")

	// 按照指定時區和指定格式解析字串時間
	t1, _ := time.ParseInLocation("2006/01/02 15:04:05", "2030/07/20 11:25:20", timezone)

	fmt.Println(now)

	fmt.Println(t1.Sub(now))
}

八.練習題

1.獲取當前時間,格式化輸出為"2030/01/01 23:30:05"格式

package main

import (
	"fmt"
	"time"
)

func PrintTime(t time.Time) {
	// 方式一: Go語言中時間格式化的佈局不是常見的Y-m-d H:M:S,而是使用 2006-01-02 15:04:05.000(記憶口訣為2006 1 2 3 4 5)
	// 溫馨提示: 
	// 		1."2006/01/02 15:04:05"分別對應著年月日時分秒;
	//		2.如果只想看年則傳入"2006",如果想要看月份則傳入"01",如果想要看小時則傳入15,以此推類;
	t1 := t.Format("2006/01/02 15:04:05")
	fmt.Printf("t1 = [%v]\n", t1)

	// 方式二: 使用Sprintf
	t2 := fmt.Sprintf("%d/%d/%d %d:%d:%d", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())
	fmt.Printf("t2 = [%v]\n", t2)

}

func main() {
	now := time.Now()
	PrintTime(now)
}

2.編寫程式統計一段程式碼的執行耗時時間,單位精確到微秒。

package main

import (
	"fmt"
	"time"
)

func calctime1() {
	// 計算出納秒
	start := time.Now().UnixNano() / 1000 
	
	fmt.Println("正在執行程式碼...")
	time.Sleep(time.Millisecond * 50)
	end := time.Now().UnixNano() / 1000

	fmt.Printf("in calctime1()... 耗費了%v微妙\n", end-start)

}

func calctime2() {
	start := time.Now()
	fmt.Println("正在執行程式碼...")
	time.Sleep(time.Millisecond * 100)

	// 注意, time.Since時內建的方法,就是拿當前的時間減去start的時間喲。
	fmt.Printf("in calctime2()... 耗費了%v\n", time.Since(start))

}

func main() {
	calctime1()
	calctime2()
}

相關文章