swardsman
詳解 Go 語言中的 time.Duration 類型
swardsman · 2018-03-17 23:10:54 · 5448 次點擊 · 預計閱讀時間 5 分鍾 · 31分鍾之前 開始瀏覽
這是一個創建於 2018-03-17 23:10:54 的文章,其中的信息可能已經有所發展或是發生改變。
長久以來,我一直抓狂於 Go 標准庫中的 Time 包,我的抓狂來自於兩個功能,一是捕獲兩個不同時間段之間間隔的毫秒數,二是將一個用毫秒表示的連續時間段與預先定義的時間段進行比較。這聽起來很簡單,沒錯,確實如此,但它的確讓我抓狂了。
在 Time 包中,定義有一個名為 Duration 的類型和一些輔助的常量:
type Duration int64
const (
Nanosecond Duration = 1
Microsecond = 1000 * Nanosecond
Millisecond = 1000 * Microsecond
Second = 1000 * Millisecond
Minute = 60 * Second
Hour = 60 * Minute
)
這些東西我可能已經看了有上千次了,但我的大腦依舊一片迷茫。我只是想比較兩個時間段、恢復要持續的時間、比較持續時間的長短並且當預設的時間用完時做一些別的事情,但無論如何這個結構還是無法解決我的困擾。我寫下了下面的測試代碼,但它沒有卵用:
func Test() {
var waitFiveHundredMillisections int64 = 500
startingTime := time.Now().UTC()
time.Sleep(10 * time.Millisecond)
endingTime := time.Now().UTC()
var duration time.Duration = endingTime.Sub(startingTime)
var durationAsInt64 = int64(duration)
if durationAsInt64 >= waitFiveHundredMillisections {
fmt.Printf("Time Elapsed : Wait[%d] Duration[%d]\n", waitFiveHundredMillisections, durationAsInt64)
} else {
fmt.Printf("Time DID NOT Elapsed : Wait[%d] Duration[%d]\n", waitFiveHundredMillisections, durationAsInt64)
}
}
我運行了這段測試代碼,然后得到了下面的輸出,從輸出內容來看,我定義的 500 毫秒的時間已經用完了,但怎么可能。
Time Elapsed : Wait[500] Duration[10724798]
那么問題出在哪里?我又一次將眼光投向了 Duration 類型的定義:
type Duration int64
const (
Nanosecond Duration = 1
Microsecond = 1000 * Nanosecond
Millisecond = 1000 * Microsecond
Second = 1000 * Millisecond
Minute = 60 * Second
Hour = 60 * Minute
)
從代碼上看, Duration 類型中時間的基本單位是 Nanosecond ,所以當我將一個表示 10 毫秒的 Duration 類型對象轉換為 int64 類型時,我實際上得到的是 10,000,000。
所以直接轉換是不行的,我需要一個不同的策略使用和轉換 Duration 類型。
我知道最好使用 Duration 類型中定義的數據,這將最大可能地減少問題的發生。基於 Duration 中定義的常量,我能夠像下面這樣創建一個 Duration 變量:
func Test() {
var duration_Milliseconds time.Duration = 500 * time.Millisecond
var duration_Seconds time.Duration = (1250 * 10) * time.Millisecond
var duration_Minute time.Duration = 2 * time.Minute
fmt.Printf("Milli [%v]\nSeconds [%v]\nMinute [%v]\n", duration_Milliseconds, duration_Seconds, duration_Minute)
}
在上面的代碼中,我創建了 3 個 Duration 類型的變量,通過使用時間常數,我能夠創建正確的持續時間的值。然后我使用標准庫函數 Printf 和 %v 操作符,得到了下面的輸出結果:
Milli [500ms]
Seconds [12.5s]
Minute [2m0s]
很酷,有木有? Printf 函數知道如何本地化顯示一個 Duration 類型,它基於 Duration 類型中的每一個值,選擇合適的格式進行時間的顯示,當然,我也得到了期待中的結果。
實際上, Duration 類型擁有一些便捷的類型轉換函數,它們能將 Duration 類型轉化為 Go 語言的內建類型 int64 或 float64 ,像下面這樣:
func Test() {
var duration_Seconds time.Duration = (1250 * 10) * time.Millisecond
var duration_Minute time.Duration = 2 * time.Minute
var float64_Seconds float64 = duration_Seconds.Seconds()
var float64_Minutes float64 = duration_Minute.Minutes()
fmt.Printf("Seconds [%.3f]\nMinutes [%.2f]\n", float64_Seconds, float64_Minutes)
}
我也迅速注意到了在時間轉換函數中,並沒有轉換毫秒值的函數,使用 Seconds 和 Minutes 函數,我得到了如下輸出:
Seconds [12.500]
Minutes [2.00]
但我需要轉換毫秒值,為什么包里面單單沒有提供毫秒值的轉換呢?因為 Go 語言的設計者希望我有更多的選擇,而不只是將毫秒值轉換成某種單獨的內建類型。下面的代碼中,我將毫秒值轉化為了 int64 類型和 float64 類型:
func Test() {
var duration_Milliseconds time.Duration = 500 * time.Millisecond
var castToInt64 int64 = duration_Milliseconds.Nanoseconds() / 1e6
var castToFloat64 float64 = duration_Milliseconds.Seconds() * 1e3
fmt.Printf("Duration [%v]\ncastToInt64 [%d]\ncastToFloat64 [%.0f]\n", duration_Milliseconds, castToInt64, castToFloat64)
}
我將納秒值除以 1^6 得到了 int64 類型表示的毫秒值,將秒值乘以 1^3 ,我得到了 float64 類型表示的毫秒值,上面代碼的輸出如下:
Duration [500ms]
castToInt64 [500]
castToFloat64 [500]
現在,我知道了 Duration 類型是什么和怎么用,下面是我最終寫的使用毫秒值的測試代碼示例:
func Test() {
var waitFiveHundredMillisections time.Duration = 500 * time.Millisecond
startingTime := time.Now().UTC()
time.Sleep(600 * time.Millisecond)
endingTime := time.Now().UTC()
var duration time.Duration = endingTime.Sub(startingTime)
if duration >= waitFiveHundredMillisections {
fmt.Printf("Wait %v\nNative [%v]\nMilliseconds [%d]\nSeconds [%.3f]\n", waitFiveHundredMillisections, duration, duration.Nanoseconds()/1e6, duration.Seconds())
}
}
得到的輸出如下:
Wait 500ms
Native [601.091066ms]
Milliseconds [601]
Seconds [0.601]
不再通過比較本地類型來確定時間是否已經用完,而是比較兩個 Duration 類型變量,這樣更加清晰明了。雖然花了一些時間,但最終我理解了 Duration 類型,我也希望這篇文章能幫助其他人在使用 Go 語言的過程中解決 Duration 類型的疑惑。
via: https://www.ardanlabs.com/blog/2013/06/gos-duration-type-unravelled.html
作者:William Kennedy 譯者:swardsman 校對:polaris1119