Tìm hiểu thời gian và ngày trong Golang

Post on: 2023-04-17 23:33:59 | in: Golang
Trong Go, gói time được sử dụng để làm việc với các giá trị thời gian và ngày.

Tổng quan

Thời gian hoặc ngày tháng được đại diện trong Go bằng cấu trúc time.Time. Thời gian cũng có thể được biểu diễn dưới dạng

  • Unix Time (Also known as Epoch Time) – Đó là số giây trôi qua kể từ 00:00:00 UTC ngày 1 tháng 1 năm 1970. Thời điểm này cũng được gọi là epoch của Unix.

Structure

Đối tượng time.Time được sử dụng để đại diện cho một thời điểm cụ thể. Cấu trúc time.Time được định nghĩa như sau:

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
    //Location to represent timeZone
    // The nil location means UTC
    loc *Location
}

Như bạn có thể thấy, mỗi đối tượng time.Time đều có một giá trị location liên kết được sử dụng để xác định phút, giờ, tháng, ngày và năm tương ứng với thời gian đó.

Tạo một thời gian mới

Sử dụng  time.Now()

Hàm này có thể được sử dụng để lấy thời điểm địa phương hiện tại. Chữ ký của hàm là:

func Now() Time

Sử dụng time.Date()

Hàm này trả về thời gian có định dạng yyyy-mm-dd hh:mm:ss + nsec nano giây với múi giờ phù hợp với vị trí được chỉ định. Chữ ký của hàm là:

func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time

Hiểu về Duration

duration là thời gian đã trôi qua giữa hai thời điểm. Nó được biểu diễn dưới dạng int64nanosecond. Vì vậy, trong Go, duration không phải là gì khác ngoài một con số biểu thị thời gian tính bằng nanosecond. Vì vậy, nếu giá trị của duration là 1000000000, thì nó đại diện cho 1 giây hoặc 1000 mili giây hoặc 10000000000 nanosecond.

Ví dụ, thời lượng giữa hai giá trị thời gian cách nhau 1 giờ sẽ là giá trị dưới đây, tương đương với số nanosecond trong 1 giờ.

1 *60*60*1000*1000*1000

Nó được biểu diễn như sau trong gói time.

type Duration int64

Dưới đây là một số duration thông dụng được định nghĩa trong gói "time":

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

Hàm được định nghĩa trên đối tượng time.Time trả về Duration bao gồm:

  • func (t Time) Sub(u Time) Duration – Trả về thời gian trễ giữa hai thời điểm t-u.
  • func Since(t Time) Duration – Trả về khoảng thời gian đã trôi qua kể từ thời điểm t.
  • func Until(t Time) Duration – Trả về khoảng thời gian còn lại cho đến thời điểm t.

Thêm hoặc trừ thời gian

Bây giờ khi bạn đã hiểu được về duration, hãy xem cách chúng ta có thể thêm hoặc trừ một khoảng thời gian từ một thời điểm cụ thể.

Golang's time package định nghĩa hai cách để thêm hoặc trừ một khoảng thời gian từ một thời điểm:

  • Hàm Add - được sử dụng để thêm/trừ một duration vào thời điểm t. Vì duration có thể được biểu diễn dưới dạng giờ, phút, giây, mili giây, micro giây và nano giây, do đó hàm Add có thể được sử dụng để thêm/trừ các giá trị này từ một thời điểm. Chữ ký của nó là:
func (t Time) Add(d Duration) Time
  • Hàm AddDate - nó được sử dụng để thêm / bớt số năm, tháng và ngày vào thời gian t. Chữ ký của nó là:
func (t Time) AddDate(years int, months int, days int) Time

Ghi chú: Giá trị dương được sử dụng để thêm vào thời gian và giá trị âm được sử dụng để trừ. Hãy xem một ví dụ về cách thêm và trừ thời gian.

Thêm thời gian

Dưới đây là đoạn mã để thêm vào thời gian:

package main

import (
    "fmt"
    "time"
)

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

    //Add 1 hours
    newT := t.Add(time.Hour * 1)
    fmt.Printf("Adding 1 hour\n: %s\n", newT)

    //Add 15 min
    newT = t.Add(time.Minute * 15)
    fmt.Printf("Adding 15 minute\n: %s\n", newT)

    //Add 10 sec
    newT = t.Add(time.Second * 10)
    fmt.Printf("Adding 10 sec\n: %s\n", newT)

    //Add 100 millisecond
    newT = t.Add(time.Millisecond * 10)
    fmt.Printf("Adding 100 millisecond\n: %s\n", newT)

    //Add 1000 microsecond
    newT = t.Add(time.Millisecond * 10)
    fmt.Printf("Adding 1000 microsecond\n: %s\n", newT)

    //Add 10000 nanosecond
    newT = t.Add(time.Nanosecond * 10000)
    fmt.Printf("Adding 1000 nanosecond\n: %s\n", newT)

    //Add 1 year 2 month 4 day
    newT = t.AddDate(1, 2, 4)
    fmt.Printf("Adding 1 year 2 month 4 day\n: %s\n", newT)
}

Output:

Adding 1 hour:
2020-02-01 02:16:35.893847 +0530 IST m=+3600.000239893

Adding 15 minute:
2020-02-01 01:31:35.893847 +0530 IST m=+900.000239893

Adding 10 sec:
2020-02-01 01:16:45.893847 +0530 IST m=+10.000239893

Adding 100 millisecond:
2020-02-01 01:16:35.903847 +0530 IST m=+0.010239893

Adding 1000 microsecond:
2020-02-01 01:16:35.903847 +0530 IST m=+0.010239893

Adding 1000 nanosecond:
2020-02-01 01:16:35.893857 +0530 IST m=+0.000249893

Adding 1 year 2 month 4 day:
2021-04-05 01:16:35.893847 +0530 IST

Trừ thời gian

Dưới đây là đoạn mã để trừ thời gian:

package main

import (
    "fmt"
    "time"
)

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

    //Add 1 hours
    newT := t.Add(-time.Hour * 1)
    fmt.Printf("Subtracting 1 hour:\n %s\n", newT)

    //Add 15 min
    newT = t.Add(-time.Minute * 15)
    fmt.Printf("Subtracting 15 minute:\n %s\n", newT)

    //Add 10 sec
    newT = t.Add(-time.Second * 10)
    fmt.Printf("Subtracting 10 sec:\n %s\n", newT)

    //Add 100 millisecond
    newT = t.Add(-time.Millisecond * 10)
    fmt.Printf("Subtracting 100 millisecond:\n %s\n", newT)

    //Add 1000 microsecond
    newT = t.Add(-time.Millisecond * 10)
    fmt.Printf("Subtracting 1000 microsecond:\n %s\n", newT)

    //Add 10000 nanosecond
    newT = t.Add(-time.Nanosecond * 10000)
    fmt.Printf("Subtracting 1000 nanosecond:\n %s\n", newT)

    //Add 1 year 2 month 4 day
    newT = t.AddDate(-1, -2, -4)
    fmt.Printf("Subtracting 1 year 2 month 4 day:\n %s\n", newT)
}

Output:

Subtracting 1 hour:
2020-02-01 00:18:29.772673 +0530 IST m=-3599.999784391

Subtracting 15 minute:
2020-02-01 01:03:29.772673 +0530 IST m=-899.999784391

Subtracting 10 sec:
2020-02-01 01:18:19.772673 +0530 IST m=-9.999784391

Subtracting 100 millisecond:
2020-02-01 01:18:29.762673 +0530 IST m=-0.009784391

Subtracting 1000 microsecond:
2020-02-01 01:18:29.762673 +0530 IST m=-0.009784391

Subtracting 1000 nanosecond:
2020-02-01 01:18:29.772663 +0530 IST m=+0.000205609

Subtracting 1 year 2 month 4 day:
2018-11-27 01:18:29.772673 +0530 IST

Định dạng/ phân tích thời gian

Nếu bạn đã làm việc với định dạng/ phân tích ngày giờ trong các ngôn ngữ khác, bạn có thể đã nhận thấy rằng các ngôn ngữ khác sử dụng các ký tự đặc biệt để định dạng thời gian/ngày. Ví dụ như trong Ruby, ngôn ngữ này sử dụng

%d cho ngày %Y cho năm v.v.

Go, thay vì sử dụng các ký tự như trên, sử dụng các giá trị định dạng thời gian và ngày trông giống như ngày tháng và thời gian thực tế. Go sử dụng định dạng thời gian chuẩn, bao gồm:

Mon Jan 2 15:04:05 MST 2006  (MST is GMT-0700)
or
01/02 03:04:05PM '06 -0700

Vì vậy, nếu bạn nhận thấy, Go sử dụng

  • 01 để biểu thị ngày trong tháng
  • 02 để biểu thị tháng
  • 03 để biểu thị giờ
  • 04 để biểu thị phút
  • 05 để biểu thị giây
  • và còn nhiều hơn thế.

 

Bảng placeholder dưới đây mô tả phép ánh xạ chính xác. Go tiếp cận một cách hiệu quả hơn, khi bạn không cần phải nhớ hoặc tra cứu các mã định dạng truyền thống như trong các ngôn ngữ khác.

Type Placeholder
Day 2 or 02 or _2
Day of Week Monday or Mon
Month 01 or 1 or Jan or January
Year 2006 or 06
Hour 03 or or 15
Minutes 04 or 4
Seconds 05 or 5
Milli Seconds  (ms) .000        //Trailing zero will be includedor .999   //Trailing zero will be omitted
Micro Seconds (μs) .000000             //Trailing zero will be includedor .999999        //Trailing zero will be omitted
Nano Seconds (ns) .000000000        //Trailing zero will be includedor .999999999 //Trailing zero will be omitted
am/pm PM or pm
Timezone MST
Timezone offset Z0700 or Z070000 or Z07 or Z07:00 or Z07:00:00  or -0700 or  -070000 or -07 or -07:00 or -07:00:00

Ví dụ phân tích cú pháp thời gian

Giờ quay lại với hàm time.Parse. Chữ ký của hàm như sau:

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

Hàm time.Parse() nhận vào hai tham số:

  • Tham số đầu tiên là chuỗi định dạng của thời gian gồm các định dạng thay thế thời gian.
  • Tham số thứ hai là chuỗi được định dạng thực tế đại diện cho một thời gian.

Cách tiếp cận của bạn là đảm bảo chuỗi định dạng (tham số đầu tiên) khớp với chuỗi biểu diễn (tham số thứ hai) của thời gian bạn muốn phân tích thành time.Time. Để phân tích cú pháp

  • Để phân tích cú pháp 2020-01-29, chuỗi định dạng phải là 06-01-02 hoặc 2006-01-02 hoặc một cái gì đó phù hợp với bảng định dạng thay thế thời gian trên.
  • Tương tự, để phân tích cú pháp "2020-Jan-29 Wednesday 12:19:25", chuỗi định dạng có thể là "2006-Jan-02 Monday 03:04:05"

Dưới đây là các ví dụ mã hoạt động của time.Parse().

package main

import (
    "fmt"
    "time"
)

func main() {
    //Parse YYYY-MM-DD
    timeT, _ := time.Parse("2006-01-02", "2020-01-29")
    fmt.Println(timeT)

    //Parse YY-MM-DD
    timeT, _ = time.Parse("06-01-02", "20-01-29")
    fmt.Println(timeT)

    //Parse YYYY-#{MonthName}-DD
    timeT, _ = time.Parse("2006-Jan-02", "2020-Jan-29")
    fmt.Println(timeT)

    //Parse YYYY-#{MonthName}-DD WeekDay HH:MM:SS
    timeT, _ = time.Parse("2006-Jan-02 Monday 03:04:05", "2020-Jan-29 Wednesday 12:19:25")
    fmt.Println(timeT)

    //Parse YYYY-#{MonthName}-DD WeekDay HH:MM:SS PM Timezone TimezoneOffset
    timeT, _ = time.Parse("2006-Jan-02 Monday 03:04:05 PM MST -07:00", "2020-Jan-29 Wednesday 12:19:25 AM IST +05:30")
    fmt.Println(timeT)
}

Output:

2020-01-29 00:00:00 +0000 UTC
2020-01-29 00:00:00 +0000 UTC
2020-01-29 00:00:00 +0000 UTC
2020-01-29 12:19:25 +0000 UTC
2020-01-29 00:19:25 +0530 IST

Ví dụ định dạng thời gian

Hàm time.Format có thể được sử dụng để định dạng thời gian thành một chuỗi. Chữ ký của hàm như sau:

func (t Time) Format(layout string)

Dưới đây là một số ví dụ về mã định dạng thời gian

package main

import (
    "fmt"
    "time"
)

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

    //Format YYYY-MM-DD
    fmt.Printf("YYYY-MM-DD: %s\n", now.Format("2006-01-02"))

    //Format YY-MM-DD
    fmt.Printf("YY-MM-DD: %s\n", now.Format("06-01-02"))

    //Format YYYY-#{MonthName}-DD
    fmt.Printf("YYYY-#{MonthName}-DD: %s\n", now.Format("2006-Jan-02"))

    //Format HH:MM:SS
    fmt.Printf("HH:MM:SS: %s\n", now.Format("03:04:05"))

    //Format HH:MM:SS Millisecond
    fmt.Printf("HH:MM:SS Millisecond: %s\n", now.Format("03:04:05 .999"))

    //Format YYYY-#{MonthName}-DD WeekDay HH:MM:SS
    fmt.Printf("YYYY-#{MonthName}-DD WeekDay HH:MM:SS: %s\n", now.Format("2006-Jan-02 Monday 03:04:05"))

    //Format YYYY-#{MonthName}-DD WeekDay HH:MM:SS PM Timezone TimezoneOffset
    fmt.Printf("YYYY-#{MonthName}-DD WeekDay HH:MM:SS PM Timezone TimezoneOffset: %s\n", now.Format("2006-Jan-02 Monday 03:04:05 PM MST -07:00"))
}

Output:

YYYY-MM-DD: 2020-01-25
YY-MM-DD: 20-01-25
YYYY-#{MonthName}-DD: 2020-Jan-25
HH:MM:SS: 11:14:16
HH:MM:SS Millisecond: 11:14:16 .213
YYYY-#{MonthName}-DD WeekDay HH:MM:SS: 2020-Jan-25 Saturday 11:14:16
YYYY-#{MonthName}-DD WeekDay HH:MM:SS PM Timezone TimezoneOffset: 2020-Jan-25 Saturday 11:14:16 PM IST +05:30

Sự khác biệt thời gian

Phương thức Sub trong gói thời gian (time package) có thể được sử dụng để lấy sự khác biệt giữa hai giá trị thời gian khác nhau. Chữ ký của hàm là:

func (t Time) Sub(u Time) Duration

currentTime := time.Now()
oldTime := time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC)
diff := currentTime.Sub(oldTime)

Chuyển đổi thời gian

Dưới đây là ví dụ về chuyển đổi giữa

  • time.Time to Unix Timestamp
  • Unix Timestamp to time.Time
package main

import (
    "fmt"
    "time"
)

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

    //time.Time to Unix Timestamp
    tUnix := tNow.Unix()
    fmt.Printf("timeUnix %d\n", tUnix)

    //Unix Timestamp to time.Time
    timeT := time.Unix(tUnix, 0)
    fmt.Printf("time.Time: %s\n", timeT)
}

Output:

timeUnix 1257894000
time.Time: 2009-11-10 23:00:00 +0000 UTC

Chuyển đổi thời gian giữa các múi giờ khác nhau

Hàm In trong package time có thể được sử dụng để thay đổi location liên quan đến đối tượng time.Time cụ thể. Khi nào In được gọi trên bất kỳ đối tượng time.Time nào (ví dụ như t) thì:

  • Một bản sao của t được tạo ra đại diện cho cùng một thời điểm.
  • Vị trí của t được thiết lập thành vị trí được truyền vào hàm In để hiển thị.
  • t được trả về lại.

Hãy xem mã hoạt động dưới đây có thể được sử dụng để thay đổi giá trị vị trí liên quan đến một thời gian cụ thể.

package main

import (
    "fmt"
    "time"
)

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

    loc, _ := time.LoadLocation("UTC")
    fmt.Printf("UTC Time: %s\n", now.In(loc))

    loc, _ = time.LoadLocation("Europe/Berlin")
    fmt.Printf("Berlin Time: %s\n", now.In(loc))

    loc, _ = time.LoadLocation("America/New_York")
    fmt.Printf("New York Time: %s\n", now.In(loc))

    loc, _ = time.LoadLocation("Asia/Dubai")
    fmt.Printf("Dubai Time: %s\n", now.In(loc))
}

Output:

UTC Time: 2020-01-31 18:09:41.705858 +0000 UTC
Berlin Time: 2020-01-31 19:09:41.705858 +0100 CET
New York Time: 2020-01-31 13:09:41.705858 -0500 EST
Dubai Time: 2020-01-31 22:09:41.705858 +0400 +04