目次
タイムゾーンの問題への対処" >タイムゾーンの問題への対処
时间瞬间 time.Time" >时间瞬间 time.Time
获取 time.Time
转换时间戳
获取基本字段
持续时间 time.Duration" >持续时间 time.Duration
时间计算" >时间计算
使用示例
格式化时间" >格式化时间
示例
时区转换" >时区转换
总结" >总结
ホームページ バックエンド開発 Golang Go での時間処理を学ぶ

Go での時間処理を学ぶ

Jul 21, 2023 am 10:38 AM
go 時間処理

プログラマーとして、私たちは時間に対処する必要があることがよくあります。 Go では、標準ライブラリ時間が対応する機能を提供します。

この記事では、Go 時間処理の問題に遭遇したときに Baidu を必要とする子供たちを助けることを願って、タイム ライブラリのいくつかの重要な関数とメソッドを紹介します。

タイムゾーンの問題への対処

プログラミングでは、8 時間の時差の問題によく遭遇します。これはタイムゾーンの違いが原因で発生するため、タイムゾーンの違いをより適切に解決するには、いくつかの時間定義標準を理解する必要があります。

GMT (グリニッジ標準時)、グリニッジ標準時。 GMT は地球の自転と公転に基づいて時間を計算し、毎日正午に太陽がイギリスのロンドン郊外にある王立グリニッジ天文台を通過することを定めています。 GMT は以前の世界時です。

UTC (協定世界時)、協定世界時。 UTC は GMT よりも正確で、原子時計に基づいて時間を計算します。秒までの精度が必要ない場合は、UTC=GMT を考慮できます。 UTC は協定世界時です。

グリニッジの本初子午線を起点として、東方向が正、西方向が負になります。世界は 24 の標準時間帯に分かれており、隣接する時間帯間の差は 1 時間です。

1

2

3

4

5

6

7

8

9

10

package main

 

import (

 "fmt"

 "time"

)

 

func main() {

 fmt.Println(time.Now())

}

ログイン後にコピー

中国本土では、東部第 8 時間帯の標準時、つまり北京時間 CST、中国標準時が使用されます。

1

2

$ go run main.go

2022-07-17 16:37:31.186043 +0800 CST m=+0.000066647

ログイン後にコピー

这是默认时区下的结果,<span style="font-size: 15px;">time.Now()</span>的打印中会标注<span style="font-size: 15px;">+0800 CST</span>

假设我们是在美国洛杉矶时区下,那得到的结果是什么呢?

1

2

$ TZ="America/Los_Angeles" go run main.go

2022-07-17 01:39:12.391505 -0700 PDT m=+0.000069514

ログイン後にコピー

可以看到,此时的结果是<span style="font-size: 15px;">-0700 PDT</span> 时间,即 PDT(Pacific Daylight Time)太平洋夏季时间。由于时区差异,两次执行的时间结果相差了 15 小时。

注意,在使用 Docker 容器时,系统默认的时区就是 UTC 时间(0 时区),和我们实际需要的北京时间相差八个小时,这是导致八小时时间差问题的经典场景。

时区问题的应对策略,可以详细查看 src/time/zoneinfo_unix.go 中 initLocal() 函数的加载逻辑。例如,可以通过指定环境变量 TZ,修改/etc/localtime文件等方式来解决。

因为时区问题非常重要,所以放在了文章第一部分讲述。下面开始介绍 time 库的使用。

时间瞬间 time.Time

time 库,最核心的对象是 time.Time 结构体。它的定义如下,用以表示某个瞬间的时间。

1

2

3

4

5

6

7

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 函数获取当前本地时间

1

func Now() Time {}

ログイン後にコピー

也可以通过 Date 函数,根据年、月、日等时间和时区参数获取指定时间

1

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 到指定瞬间所经过的秒数、微秒数等。

1

2

3

4

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 经过的纳秒数

ログイン後にコピー
获取基本字段

1

2

3

4

5

6

7

8

9

10

11

12

13

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 年。

1

2

3

4

// 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

1*60*60*1000*1000*1000

ログイン後にコピー

Go 的 time 包中定义了这些持续时间常量值

1

2

3

4

5

6

7

8

const (

 Nanosecond  Duration = 1

 Microsecond          = 1000 * Nanosecond

 Millisecond          = 1000 * Microsecond

 Second               = 1000 * Millisecond

 Minute               = 60 * Second

 Hour                 = 60 * Minute

)

ログイン後にコピー

同时,time.Duration 提供了能获取各时间粒度数值的方法

1

2

3

4

5

6

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 {}       // 小时

ログイン後にコピー

时间计算

在学习了时间瞬间和持续时间之后,我们来看如何做时间计算。

1

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

ログイン後にコピー
  • Add 函数用于增加/减少( d 的正值表示增加、负值表示减少) time.Time 的持续时间。我们可以对某瞬时时间,增加或减少指定纳秒级以上的时间。

1

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

ログイン後にコピー
  • Sub 函数可以得出两个时间瞬间之间的持续时间。

1

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

ログイン後にコピー
  • AddDate 函数基于年、月和日的维度增加/减少 time.Time 的值。

当然,基于当前时间瞬间 time.Now() 的计算是最普遍的需求。因此,time 包还提供了以下便捷的时间计算函数。

1

func Since(t Time) Duration {}

ログイン後にコピー

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

1

func Until(t Time) Duration {}

ログイン後にコピー

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

使用示例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

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 语言的诞生时间。

1

Mon Jan 2 15:04:05 MST 2006

ログイン後にコピー

格式化时间涉及到两个转换函数

1

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

ログイン後にコピー
  • Parse 函数用于将时间字符串根据它所能对应的布局转换为 time.Time 对象。

1

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

ログイン後にコピー
  • Formate 函数用于将 time.Time 对象根据给定的布局转换为时间字符串。
示例

1

2

3

4

5

6

7

8

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 提供了一些预定义的布局模板常量,这些可以直接拿来使用。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

const (

 Layout      = "01/02 03:04:05PM &#39;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"

)

ログイン後にコピー

下面是我们可选的布局参数对照表

1

2

3

4

5

6

7

8

9

10

11

12

13

年         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 方法。

1

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

ログイン後にコピー

它的使用非常简单,直接看示例代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

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 での時間処理を学ぶの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Go WebSocket メッセージを送信するにはどうすればよいですか? Go WebSocket メッセージを送信するにはどうすればよいですか? Jun 03, 2024 pm 04:53 PM

Go では、gorilla/websocket パッケージを使用して WebSocket メッセージを送信できます。具体的な手順: WebSocket 接続を確立します。テキスト メッセージを送信します。 WriteMessage(websocket.TextMessage,[]byte("message")) を呼び出します。バイナリ メッセージを送信します。WriteMessage(websocket.BinaryMessage,[]byte{1,2,3}) を呼び出します。

Golang 関数のライフサイクルと変数スコープの深い理解 Golang 関数のライフサイクルと変数スコープの深い理解 Apr 19, 2024 am 11:42 AM

Go では、関数のライフ サイクルには定義、ロード、リンク、初期化、呼び出し、戻り値が含まれます。変数のスコープは関数レベルとブロック レベルに分割されますが、ブロック内の変数はブロック内でのみ表示されます。 。

GolangとGo言語の違い GolangとGo言語の違い May 31, 2024 pm 08:10 PM

Go と Go 言語は、異なる特性を持つ別個の存在です。 Go (Golang とも呼ばれます) は、同時実行性、高速なコンパイル速度、メモリ管理、およびクロスプラットフォームの利点で知られています。 Go 言語の欠点としては、他の言語に比べてエコシステムが充実していないこと、構文が厳格であること、動的型付けが欠如していることが挙げられます。

Go で正規表現を使用してタイムスタンプを照合するにはどうすればよいですか? Go で正規表現を使用してタイムスタンプを照合するにはどうすればよいですか? Jun 02, 2024 am 09:00 AM

Go では、正規表現を使用してタイムスタンプを照合できます。ISO8601 タイムスタンプの照合に使用されるような正規表現文字列をコンパイルします。 ^\d{4}-\d{2}-\d{2}T \d{ 2}:\d{2}:\d{2}(\.\d+)?(Z|[+-][0-9]{2}:[0-9]{2})$ 。 regexp.MatchString 関数を使用して、文字列が正規表現と一致するかどうかを確認します。

Golang の技術的なパフォーマンスの最適化でメモリ リークを回避するにはどうすればよいですか? Golang の技術的なパフォーマンスの最適化でメモリ リークを回避するにはどうすればよいですか? Jun 04, 2024 pm 12:27 PM

メモリ リークは、ファイル、ネットワーク接続、データベース接続などの使用されなくなったリソースを閉じることによって、Go プログラムのメモリを継続的に増加させる可能性があります。弱参照を使用してメモリ リークを防ぎ、強参照されなくなったオブジェクトをガベージ コレクションの対象にします。 go coroutine を使用すると、メモリ リークを避けるために、終了時にコルーチンのスタック メモリが自動的に解放されます。

IDE で Golang 関数のドキュメントを表示するにはどうすればよいですか? IDE で Golang 関数のドキュメントを表示するにはどうすればよいですか? Apr 18, 2024 pm 03:06 PM

IDE を使用して Go 関数のドキュメントを表示する: 関数名の上にカーソルを置きます。ホットキーを押します (GoLand: Ctrl+Q; VSCode: GoExtensionPack をインストールした後、F1 キーを押して「Go:ShowDocumentation」を選択します)。

Golang関数がマップパラメータを受け取る際の注意点 Golang関数がマップパラメータを受け取る際の注意点 Jun 04, 2024 am 10:31 AM

Go の関数にマップを渡すと、デフォルトでコピーが作成され、コピーへの変更は元のマップには影響しません。元のマップを変更する必要がある場合は、ポインタを介してそれを渡すことができます。空のマップは技術的には nil ポインターであり、空ではないマップを期待する関数に空のマップを渡すとエラーが発生するため、空のマップは慎重に扱う必要があります。

Golang のエラー ラッパーを使用するにはどうすればよいですか? Golang のエラー ラッパーを使用するにはどうすればよいですか? Jun 03, 2024 pm 04:08 PM

Golang では、エラー ラッパーを使用して、元のエラーにコンテキスト情報を追加することで新しいエラーを作成できます。これを使用すると、さまざまなライブラリまたはコンポーネントによってスローされるエラーの種類を統一し、デバッグとエラー処理を簡素化できます。手順は次のとおりです。errors.Wrap 関数を使用して、元のエラーを新しいエラーにラップします。新しいエラーには、元のエラーのコンテキスト情報が含まれています。 fmt.Printf を使用してラップされたエラーを出力し、より多くのコンテキストとアクション性を提供します。異なる種類のエラーを処理する場合は、errors.Wrap 関数を使用してエラーの種類を統一します。

See all articles