<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    學會 Go 中的時間處理

    VSole2022-08-29 14:38:40

    作為程序員,我們經常需要對時間進行處理。在 Go 中,標準庫 time 提供了對應的能力。

    本文將介紹 time 庫中一些重要的函數和方法,希望能幫助到那些一遇到 Go 時間處理問題就需要百度的童鞋。

    應對時區問題

    在編程中,我們經常會遭遇八小時時間差問題。這是由時區差異引起的,為了能更好地解決它們,我們需要理解幾個時間定義標準。

    GMT(Greenwich Mean Time),格林威治平時。GMT 根據地球的自轉和公轉來計算時間,它規定太陽每天經過位于英國倫敦郊區的皇家格林威治天文臺的時間為中午12點。GMT 是前世界標準時。

    UTC(Coordinated Universal Time),協調世界時。UTC 比 GMT 更精準,它根據原子鐘來計算時間。在不需要精確到秒的情況下,可以認為 UTC=GMT。UTC 是現世界標準時。

    從格林威治本初子午線起,往東為正,往西為負,全球共劃分為 24 個標準時區,相鄰時區相差一個小時。

    package main
    import (
     "fmt"
     "time"
    )
    func main() {
     fmt.Println(time.Now())
    }
    

    中國大陸使用的是東八時區的標準時,即北京時間 CST,China Standard Time。

    $ go run main.go 
    2022-07-17 16:37:31.186043 +0800 CST m=+0.000066647
    

    這是默認時區下的結果,time.Now()的打印中會標注+0800 CST

    假設我們是在美國洛杉磯時區下,那得到的結果是什么呢?

    $ TZ="America/Los_Angeles" go run main.go
    2022-07-17 01:39:12.391505 -0700 PDT m=+0.000069514
    

    可以看到,此時的結果是-0700 PDT 時間,即 PDT(Pacific Daylight Time)太平洋夏季時間。由于時區差異,兩次執行的時間結果相差了 15 小時。

    注意,在使用 Docker 容器時,系統默認的時區就是 UTC 時間(0 時區),和我們實際需要的北京時間相差八個小時,這是導致八小時時間差問題的經典場景。

    時區問題的應對策略,可以詳細查看 src/time/zoneinfo_unix.go 中 initLocal() 函數的加載邏輯。例如,可以通過指定環境變量 TZ,修改/etc/localtime文件等方式來解決。

    因為時區問題非常重要,所以放在了文章第一部分講述。下面開始介紹 time 庫的使用。

    時間瞬間 time.Time

    time 庫,最核心的對象是 time.Time 結構體。它的定義如下,用以表示某個瞬間的時間。

    type Time struct {
      // wall and ext encode the wall time seconds, wall time nanoseconds,
     // and optional monotonic clock reading in nanoseconds.
       wall uint64
       ext  int64
       loc *Location
    }
    

    計算機在時間處理上,主要涉及到兩種時鐘。

    • 墻上時鐘(wall time),又稱為鐘表時間,用于表示具體的日期與時間。
    • 單調時鐘(monotonic clocks),總是保證時間是向前的,不會出現墻上時鐘的回撥問題,因此它很適合用于測量持續時間段。

    wall 和 ext 字段就是用于記錄墻上時鐘和單調時鐘,精度為納秒。字段的對應位數上關聯著用于確定時間的具體年、月、日、小時、分鐘、秒等信息。

    loc 字段記錄時區位置,當 loc 為 nil 時,默認為 UTC 時間。

    因為 time.Time 用于表示具有納秒精度的時間瞬間,在程序中通常應該將它作為值存儲和傳遞,而不是指針。

    即在時間變量或者結構體字段中,我們應該使用 time.Time,而非 *time.Time。

    獲取 time.Time

    我們可以通過 Now 函數獲取當前本地時間

    func Now() Time {}
    

    也可以通過 Date 函數,根據年、月、日等時間和時區參數獲取指定時間

    func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time {}
    
    轉換時間戳

    計算機世界中,將 UTC 時間 1970 年1月1日 0 時 0 分 0 秒作為 Unix 時間 0。所謂的時間瞬間轉換為 Unix 時間戳,即計算的是從 Unix 時間 0 到指定瞬間所經過的秒數、微秒數等。

    func (t Time) Unix() int64 {}      // 從 Unix 時間 0 經過的秒數
    func (t Time) UnixMicro() int64 {} // 從 Unix 時間 0 經過的微秒數
    func (t Time) UnixMilli() int64 {} // 從 Unix 時間 0 經過的毫秒數
    func (t Time) UnixNano() int64 {}  // 從 Unix 時間 0 經過的納秒數
    
    獲取基本字段
     t := time.Now()
     fmt.Println(t.Date())      // 2022 July 17
     fmt.Println(t.Year())      // 2022
     fmt.Println(t.Month())     // July
     fmt.Println(t.ISOWeek())   // 2022 28
     fmt.Println(t.Clock())     // 22 21 56
     fmt.Println(t.Day())       // 17
     fmt.Println(t.Weekday())   // Sunday
     fmt.Println(t.Hour())      // 22
     fmt.Println(t.Minute())    // 21
     fmt.Println(t.Second())    // 56
     fmt.Println(t.Nanosecond())// 494313000
     fmt.Println(t.YearDay())   // 198
    

    持續時間 time.Duration

    持續時間 time.Duration 用于表示兩個時間瞬間 time.Time 之間所經過的時間。它通過 int64 表示納秒計數,能表示的極限大約為 290 年。

    // A Duration represents the elapsed time between two instants
    // as an int64 nanosecond count. The representation limits the
    // largest representable duration to approximately 290 years.
    type Duration int64
    

    在 Go 中,持續時間只是一個以納秒為單位的數字而已。如果持續時間等于 1000000000,則它代表的含義是 1 秒或 1000 毫秒或 1000000 微秒或 1000000000 納秒。

    例如,相隔 1 小時的兩個時間瞬間 time.Time 值,它們之間的持續時間 time.Duration 值為

    1*60*60*1000*1000*1000
    

    Go 的 time 包中定義了這些持續時間常量值

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

    同時,time.Duration 提供了能獲取各時間粒度數值的方法

    func (d Duration) Nanoseconds() int64 {}   // 納秒
    func (d Duration) Microseconds() int64 {}  // 微秒
    func (d Duration) Milliseconds() int64 {}  // 毫秒
    func (d Duration) Seconds() float64 {}     // 秒
    func (d Duration) Minutes() float64 {}     // 分鐘
    func (d Duration) Hours() float64 {}       // 小時
    

    時間計算

    在學習了時間瞬間和持續時間之后,我們來看如何做時間計算。

    func (t Time) Add(d Duration) Time {}
    

    Add 函數用于增加/減少( d 的正值表示增加、負值表示減少) time.Time 的持續時間。我們可以對某瞬時時間,增加或減少指定納秒級以上的時間。

    func (t Time) Sub(u Time) Duration {}
    

    Sub 函數可以得出兩個時間瞬間之間的持續時間。

    func (t Time) AddDate(years int, months int, days int) Time {}
    

    AddDate 函數基于年、月和日的維度增加/減少 time.Time 的值。

    當然,基于當前時間瞬間 time.Now() 的計算是最普遍的需求。因此,time 包還提供了以下便捷的時間計算函數。

    func Since(t Time) Duration {}
    

    Since 函數是 time.Now().Sub(t) 的快捷方法。

    func Until(t Time) Duration {}
    

    Until 函數是 t.Sub(time.Now()) 的快捷方法。

    使用示例
     t := time.Now()
     fmt.Println(t)                      // 2022-07-17 22:41:06.001567 +0800 CST m=+0.000057466
     //時間增加 1小時
     fmt.Println(t.Add(time.Hour * 1))   // 2022-07-17 23:41:06.001567 +0800 CST m=+3600.000057466
     //時間增加 15 分鐘
     fmt.Println(t.Add(time.Minute * 15))// 2022-07-17 22:56:06.001567 +0800 CST m=+900.000057466
     //時間增加 10 秒鐘
     fmt.Println(t.Add(time.Second * 10))// 2022-07-17 22:41:16.001567 +0800 CST m=+10.000057466
     //時間減少 1 小時
     fmt.Println(t.Add(-time.Hour * 1))  // 2022-07-17 21:41:06.001567 +0800 CST m=-3599.999942534
     //時間減少 15 分鐘
     fmt.Println(t.Add(-time.Minute * 15))// 2022-07-17 22:26:06.001567 +0800 CST m=-899.999942534
     //時間減少 10 秒鐘
     fmt.Println(t.Add(-time.Second * 10))// 2022-07-17 22:40:56.001567 +0800 CST m=-9.999942534
     time.Sleep(time.Second * 5)
     t2 := time.Now()
     // 計算 t 到 t2 的持續時間
     fmt.Println(t2.Sub(t))              // 5.004318874s
     // 1 年之后的時間
     t3 := t2.AddDate(1, 0, 0)
     // 計算從 t 到當前的持續時間
     fmt.Println(time.Since(t))          // 5.004442316s
     // 計算現在到明年的持續時間
     fmt.Println(time.Until(t3))         // 8759h59m59.999864s
    

    格式化時間

    在其他語言中,一般會使用通用的時間模板來格式化時間。例如 Python,它使用 %Y 代表年、%m 代表月、%d 代表日等。

    但是,Go 不一樣,它使用固定的時間(需要注意,使用其他的時間是不可以的)作為布局模板,而這個固定時間是 Go 語言的誕生時間。

    Mon Jan 2 15:04:05 MST 2006
    

    格式化時間涉及到兩個轉換函數

    func Parse(layout, value string) (Time, error) {}
    

    Parse 函數用于將時間字符串根據它所能對應的布局轉換為 time.Time 對象。

    func (t Time) Format(layout string) string {}
    

    Formate 函數用于將 time.Time 對象根據給定的布局轉換為時間字符串。

    示例
    const (
       layoutISO = "2006-01-02"
       layoutUS  = "January 2, 2006"
    )
    date := "2012-08-09"
    t, _ := time.Parse(layoutISO, date)
    fmt.Println(t)                  // 2012-08-09 00:00:00 +0000 UTC
    fmt.Println(t.Format(layoutUS)) // August 9, 2012
    

    在 time 庫中,Go 提供了一些預定義的布局模板常量,這些可以直接拿來使用。

    const (
     Layout      = "01/02 03:04:05PM '06 -0700" // The reference time, in numerical order.
     ANSIC       = "Mon Jan _2 15:04:05 2006"
     UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
     RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
     RFC822      = "02 Jan 06 15:04 MST"
     RFC822Z     = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
     RFC850      = "Monday, 02-Jan-06 15:04:05 MST"
     RFC1123     = "Mon, 02 Jan 2006 15:04:05 MST"
     RFC1123Z    = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
     RFC3339     = "2006-01-02T15:04:05Z07:00"
     RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
     Kitchen     = "3:04PM"
     // Handy time stamps.
     Stamp      = "Jan _2 15:04:05"
     StampMilli = "Jan _2 15:04:05.000"
     StampMicro = "Jan _2 15:04:05.000000"
     StampNano  = "Jan _2 15:04:05.000000000"
    )
    

    下面是我們可選的布局參數對照表

    年         06/2006
    月         01/1/Jan/January
    日         02/2/_2
    星期       Mon/Monday
    小時       03/3/15
    分         04/4
    秒         05/5
    毫秒       .000/.999
    微秒       .000000/.999999
    納秒       .000000000/.999999999
    am/pm     PM/pm
    時區       MST
    時區小時數差-0700/-07/-07:00/Z0700/Z07:00
    

    時區轉換

    在文章開頭,我們介紹了時區問題。如果在代碼中,需要獲取同一個 time.Time 在不同時區下的結果,我們可以使用它的 In 方法。

    func (t Time) In(loc *Location) Time {}
    

    它的使用非常簡單,直接看示例代碼

    now := time.Now()
    fmt.Println(now)          // 2022-07-18 21:19:59.9636 +0800 CST m=+0.000069242
    loc, _ := time.LoadLocation("UTC")
    fmt.Println(now.In(loc)) // 2022-07-18 13:19:59.9636 +0000 UTC
    loc, _ = time.LoadLocation("Europe/Berlin")
    fmt.Println(now.In(loc)) // 2022-07-18 15:19:59.9636 +0200 CEST
    loc, _ = time.LoadLocation("America/New_York")
    fmt.Println(now.In(loc)) // 2022-07-18 09:19:59.9636 -0400 EDT
    loc, _ = time.LoadLocation("Asia/Dubai")
    fmt.Println(now.In(loc)) // 2022-07-18 17:19:59.9636 +0400 +04
    

    總結

    整體而言,time 庫提供的時間處理函數和方法,基本滿足我們的使用需求。

    有意思的是,Go 時間格式化轉換必須采用 Go 誕生時間,確實有夠自戀。

    utctime函數
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    國家太空安全是國家安全在空間領域的表現。方位角舵機和仰角舵機由來自控制器的PWM信號控制。要求得出控制舵機信號在觀測的720s內每一秒的占空比來控制天線,從而成功跟蹤衛星。查看solution[0].txt得知我們最終要輸入的文件格式如下,要輸入720行,每一行對應1s:包括3個要素,分別為時間戳、控制地面站衛星天線方位、俯仰的舵機PWM值。
    學會 Go 中的時間處理
    2022-08-29 14:38:40
    在 Go 中,標準庫 time 提供了對應的能力。這是由時區差異引起的,為了能更好地解決它們,我們需要理解幾個時間定義標準。GMT 根據地球的自轉和公轉來計算時間,它規定太陽每天經過位于英國倫敦郊區的皇家格林威治天文臺的時間為中午12點。
    cast 用于一致且簡單的方式在不同的 go 類型之間進行安全的轉換。在 Go 程序中,我們通常需要將數據由一種類型轉換為另一種類型。它不僅僅適用于類型斷言,更強大的功能在于我們使用接口來處理動態數據的時候,cast 提供了一種簡單的方法將接口優雅的轉換為我們需要的數據類型。
    最近不知道怎么回事,家里電腦經常性地出現藍屏,很多時候有些文檔沒有保存便藍屏導致文檔丟失,其中也包括您現在正在看到的這一篇文章,以前一直比較懶,重啟大法一頓懟,然后重新再做編輯,只不過PPT重做簡直要人命,無奈之下,放下了所有的工作。
    loguru 是一個 Python 簡易且強大的第三方日志記錄庫,該庫旨在通過添加一系列有用的功能來解決標準記錄器的注意事項,從而減少 Python 日志記錄的痛苦。
    可以認為IAM分成兩類,一個是AWS提供的IAM,這是一個完整的身份管理系統,但AWS只提供了系統,基于該系統的配置及信息維護,由客戶完全負責。AWS 提供了虛擬網絡及其之上的VPC,子網,ACL,安全組等,客戶需要準確設計配置自己的網絡,以確保正確的隔離和防護。用戶控制權限的修改通常由特權用戶或者管理員組實現。
    Sophos MDR威脅情報團隊曾于2023年5月發表過一篇博文,稱Akira勒索軟件“將1988年的時光帶回”。起因是Akira會將受害者網站篡改為具有復古美學的頁面,讓人想起20世紀80年代的綠色屏幕控制臺。而且,Akira的名字也可能取自1988年流行的同名動畫電影《阿基拉》(Akira)。
    如今,網絡空間日益復雜,越來越多的終端設備如智能手機、打印機、網絡攝像頭、數字媒體設備等也加入到網絡空間中。通過網絡空間資產探測,可以及時發現潛在的安全風險,避免被不法之徒攻擊。基于此,論述了國內外網絡空間資產探測相關研究成果,并簡要介紹了網絡探測中的常用的網絡空間資產主動探測方法及其關鍵技術,歸納和梳理了主動探測的優點和缺點,為網絡空間資產探測技術研究人員提供借鑒。
    如今,網絡空間日益復雜,越來越多的終端設備如智能手機、打印機、網絡攝像頭、數字媒體設備等也加入到網絡空間中。通過網絡空間資產探測,可以及時發現潛在的安全風險,避免被不法之徒攻擊。基于此,論述了國內外網絡空間資產探測相關研究成果,并簡要介紹了網絡探測中的常用的網絡空間資產主動探測方法及其關鍵技術,歸納和梳理了主動探測的優點和缺點,為網絡空間資產探測技術研究人員提供借鑒。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类