淺談 Timestamp === ###### tags: `技術分享` 舉例兩組timestamp,然後以下是相等於個別時區,轉換成人在看的時間格式 1599753600 - 1599839999 ## 台灣時間 UTC+8 2020/09/11 00:00:00 2020/09/11 23:59:59 ## 格林威治時間 UTC 2020/09/10 16:00:00 2020/09/11 15:59:59 ## 美東時間 UTC-4 2020/09/10 12:00:00 2020/09/11 11:59:59   --- ## 1. 問題: 想要查今天的資料,時間範圍限定在今天。 請問把下列時間丟到timestamp 轉換,會得到『1599753600』呢? A. 2020/09/11 00:00:00 B. 2020/09/10 16:00:00 C. 2020/09/10 12:00:00 以上選項都很爛,因為關鍵點,還是這些時間的『**時區**』。 所以沒給時區丟下去轉timestamp,只會有兩種可能: ``` 方案1. 程式處理把你帶來的時間,自動視為是UTC時區的時間。 ``` ``` 方案2. 看目前機器所在的時間,自動視為目前所在的時區時間。 ``` 若是以第2點的方式,就會很可怕,你機器擺在不同的地區,轉出來的timestamp就不同。   --- ## 2. 實作上常發生誤會的原因: 目前我們系統上顯示的是『美東時間』 所以在台灣工作的我們,在2020/09/11 早上09:00am,打開系統一看。 看到的是顯示『美東時間』,2020/09/10 晚上21:00pm 。 資料的查詢條件,是帶入timestamp,那麼我們要把目前抓到的時間,轉成timestamp,請問要怎麼轉? 選項如下: A. 2020/09/11 09:00:00 (查詢一整天就會是 2020/09/11 00:00:00 ~ 2020/09/11 23:59:59) B. 2020/09/10 21:00:00 (查詢一整天就會是 2020/09/10 12:00:00 ~ 2020/09/11 11:59:59) 有沒有強烈的**既視感**,沒錯,就是上面我們講到的狀況     問題不在於帶什麼區間,而是你有沒有辦法,帶給轉換timestamp做轉換的處理函式,告訴他,你給的時間是用什麼**時區**。 所以看到程式有人處理的方式,是事先 加/減 12小時,4小時,8小時...... 的用加減去轉換,那麼程式碼的作者。 可能不清楚丟給程式幫忙轉換timestamp,是用方案一,還是方案二。   不過反過來說,若沒有辦法把『時區』的資訊,帶到轉換函式, 至少你要知道你使用的函式,是看怎麼看到你帶進來時間,把它當作什麼時區。 (我不確定所有的程式語言函式,都可不可以都吃一些像iso之類的有時區的標準格式,或者處理方式就很死板,方案1 or 方案2的轉換方式,沒二話)。     --- ## 3. 那麼,作為資料的寫入方,寫入資料庫的timestamp的時候,要怎麼做呢? 在golang來說就是 ``` go time.Now().Unix() ``` 那要指定時區嗎?不指定時區嗎? 當然不用,無論在什麼樣的時區,當下的時間那一瞬間,timestamp 都是一樣的 ``` 台灣時間UTC+8 2020/09/11 00:00:00 = 格林威治時間 UTC 2020/09/10 16:00:00 = 美東時間 UTC-4 2020/09/10 12:00:00 ```     --- ## 4. golang抓時間的format轉換,與『識別時區』很有關係 ``` go package main import ( "log" "time" ) func main() { log.Println("目前時間", time.Now(), "timestamp:", time.Now().Unix()) // 2020/09/11 20:53:43 目前時間 2020-09-11 20:53:43.048544 +0800 CST m=+0.000089287 timestamp: 1599828823 // 指定抓目前時間是UTC的狀況 // 關鍵在這裡,format幫忙轉換的時區,它要抓哪裡的時區? // 以結果來看,它就是幫你轉成UTC的時區 temp := time.Now().UTC().Add(8 * time.Hour) log.Println(temp.Zone()) // 2020/09/11 20:53:43 UTC 0 log.Println(temp.Format("2006-01-02 15:04:05")) // 2020/09/11 20:53:43 2020-09-11 20:53:43 // 即便format的格式有帶zone,跟它轉出來的時區似乎無關 log.Println(temp.Format("2006-01-02 15:04:05Z0800")) // 2020/09/11 20:53:43 2020-09-11 20:53:43Z0800 log.Println("沒有指定抓目前時間是UTC的狀況") temp2 := time.Now() log.Println(temp2.Zone()) // 2020/09/11 20:53:43 CST 28800 // 這裡的format就幫你抓台灣的時區 // 所以稍微想一下,如果你的機器所在地區,在某個奇怪的時區.......事情就悲劇了 log.Println(temp2.Format("2006-01-02 15:04:05")) // 2020/09/11 20:53:43 2020-09-11 20:53:43 log.Println(temp.Format("2006-01-02 15:04:05Z0800")) // 2020/09/11 20:53:43 2020-09-11 20:53:43Z0800 } ```   --- # 5. 尋找目標的timestamp 如果我們要找指定的時間,然後轉換成timestamp去資料庫挖資料 應該怎麼做呢? 一樣的,把你認知的時間,包含『時區』的資訊,帶給它做轉換 ``` go package main import ( "fmt" "time" ) func main() { // 讓程式自己抓系統目前時區 t := time.Now().Add(-1 * time.Hour).Unix() fmt.Println(t) // 1599826859 // 讓程式指定UTC時間 t2 := time.Now().Add(-1 * time.Hour).UTC().Unix() fmt.Println(t2) // 1599826859 // 再次證明一下,不管是什麼時間,轉換出來的timestamp是一樣 // 指定台灣時間 // 輸入的時間:2020-09-11 20:00:00 // 轉換結果:1599825600 // 我們看一下轉換有沒有符合預期 t3, err := time.Parse("2006/01/02 15:04:05 MST", "2020/09/11 20:00:00 CST") if err != nil { fmt.Println(err) } fmt.Println(t3) // 2020-09-11 20:00:00 +0800 CST fmt.Println(t3.Unix()) // 1599825600 符合預期! // 指定時區也是一種方式 loc, locErr := time.LoadLocation("Asia/Taipei") if locErr != nil { } // recentTime := time.Unix(ret[0].Begin.Unix(), 0).In(loc).Format("2006-01-02 15:04:05") + " (" + loc.String() + ")" now := time.Now().In(loc).Format("2006-01-02 15:04:05") + " (" + loc.String() + ")" log.Println(now) } ```
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up