Goで日付と時刻を使用する方法
著者は、 Diversity in Tech Fund を選択して、 Write forDOnationsプログラムの一環として寄付を受け取りました。
序章
ソフトウェアは、仕事をより簡単に行えるように設計されており、多くの人にとって、日付と時刻の操作が含まれます。 日付と時刻の値は、最新のソフトウェアのいたるところに表示されます。 たとえば、車がいつサービスを必要とするかを追跡して所有者に知らせたり、データベース内の変更を追跡して監査ログを作成したり、ある時間を別の時間と比較してプロセスにかかった時間を判断したりします。 したがって、現在の時刻を取得し、時刻の値を操作して情報を抽出し、わかりやすい形式でユーザーに表示することは、アプリケーションの重要な特性です。
このチュートリアルでは、コンピューターの現在の現地時間を取得するGoプログラムを作成し、それを人々が読みやすい形式で画面に印刷します。 次に、文字列を解釈して日付と時刻の情報を抽出します。 また、2つのタイムゾーン間の日付と時刻の値を変換し、時刻の値を加算または減算して2つの時間の間隔を決定します。
前提条件
このチュートリアルに従うには、次のものが必要です。
- Goバージョン1.16以降がインストールされています。これは、シリーズGoのローカルプログラミング環境をインストールおよびセットアップする方法に従って実行できます。
現在の時刻を取得する
このセクションでは、Goのtime
パッケージを使用して現在の時刻を取得します。 Goの標準ライブラリのtime
パッケージは、日付と時刻に関連するさまざまな関数を提供し、time.Time
タイプを使用して特定の時点を表すために使用できます。 時刻と日付に加えて、表された日付と時刻が含まれるタイムゾーンに関する情報も保持できます。
time
パッケージを探索するプログラムの作成を開始するには、ファイル用のディレクトリを作成する必要があります。 このディレクトリは、コンピュータのどこにでも作成できますが、多くの開発者はプロジェクト用のディレクトリを持っている傾向があります。 このチュートリアルでは、projects
という名前のディレクトリを使用します。
projects
ディレクトリを作成し、次の場所に移動します。
- mkdir projects
- cd projects
projects
ディレクトリから、mkdir
を実行してdatetime
ディレクトリを作成し、cd
を使用してそのディレクトリに移動します。
- mkdir datetime
- cd datetime
プロジェクトディレクトリを作成したら、nano
またはお好みのエディタを使用してmain.go
ファイルを開きます。
- nano main.go
main.go
ファイルに、現在の時刻を取得して出力するmain
関数を追加します。
package main
import (
"fmt"
"time"
)
func main() {
currentTime := time.Now()
fmt.Println("The time is", currentTime)
}
このプログラムでは、time
パッケージのtime.Now
関数を使用して、現在の現地時間をtime.Time
値として取得し、currentTime
に格納します。 ] 変数。 変数に格納されると、fmt.Println
関数は、time.Time
のデフォルトの文字列出力形式を使用してcurrentTime
を画面に出力します。
go run
とmain.go
ファイルを使用してプログラムを実行します。
- go run main.go
現在の日付と時刻を示す出力は、次のようになります。
OutputThe time is 2021-08-15 14:30:45.0000001 -0500 CDT m=+0.000066626
出力には現在の日付と時刻が表示されますが、これは例とは異なります。 さらに、time.Now()
はローカルタイムゾーンの時刻を返すため、表示されるタイムゾーン(この出力では-0500 CDT
)は異なる可能性があります。
また、出力にm=
の値が表示される場合があります。 この値は単調時計であり、時間の差を測定するときにGoによって内部的に使用されます。 単調クロックは、プログラムの実行中にコンピュータのシステムクロックの日付と時刻が変更される可能性を補正するように設計されています。 単調クロックを使用することにより、5分後のtime.Now
値と比較したtime.Now
値は、システムクロックがその5分間の間に、コンピューターが1時間前後に変更されます。 このチュートリアルのコードや例について完全に理解する必要はありませんが、単調時計とGoの使用方法について詳しく知りたい場合は、time
パッケージのドキュメントには、追加の詳細が記載されています。
これで、現在の時刻が表示されますが、ユーザーにとっては役に立たない場合があります。 探している形式ではないか、表示したい日付または時刻の一部が含まれている可能性があります。
幸い、time.Time
タイプには、必要な日付または時刻の特定の部分を取得するためのさまざまなメソッドが含まれています。 たとえば、currentTime
変数の年の部分だけを知りたい場合は、Year
メソッドを使用するか、Hour
メソッドを使用して現在の時間を取得できます。
main.go
ファイルを再度開き、time.Time
メソッドのいくつかを出力に追加して、それらが何を生成するかを確認します。
...
func main() {
currentTime := time.Now()
fmt.Println("The time is", currentTime)
fmt.Println("The year is", currentTime.Year())
fmt.Println("The month is", currentTime.Month())
fmt.Println("The day is", currentTime.Day())
fmt.Println("The hour is", currentTime.Hour())
fmt.Println("The minute is", currentTime.Hour())
fmt.Println("The second is", currentTime.Second())
}
次に、go run
を使用してプログラムを再実行します。
- go run main.go
出力は次のようになります。
OutputThe time is 2021-08-15 14:30:45.0000001 -0500 CDT m=+0.000066626
The year is 2021
The month is August
The day is 15
The hour is 14
The minute is 14
The second is 45
前の出力と同様に、現在の日付と時刻は例とは異なりますが、形式は類似している必要があります。 今回の出力では、以前と同じように完全な日付と時刻が印刷されますが、年、月、日、時、分、秒のリストもあります。 月が数字として印刷されるのではなく(完全な日付のように)、英語の文字列August
として表示されることに注意してください。 これは、Month
メソッドが月を数値ではなく、time.Month
タイプとして返すためです。このタイプは、
ここで、プログラムのmain.go
ファイルを再度更新し、さまざまな関数出力をfmt.Printf
への単一の関数呼び出しに置き換えて、現在の日付と時刻をより近い形式で印刷できるようにします。ユーザーに表示したい場合があります:
...
func main() {
currentTime := time.Now()
fmt.Println("The time is", currentTime)
fmt.Printf("%d-%d-%d %d:%d:%d\n",
currentTime.Year(),
currentTime.Month(),
currentTime.Day(),
currentTime.Hour(),
currentTime.Hour(),
currentTime.Second())
}
更新をmain.go
ファイルに保存したら、前と同じようにgo run
コマンドを使用して実行します。
- go run main.go
出力は次のようになります。
OutputThe time is 2021-08-15 14:30:45.0000001 -0500 CDT m=+0.000066626
2021-8-15 14:14:45
今回の出力は希望するものにかなり近いかもしれませんが、出力に関して微調整できることがいくつかあります。 fmt.Printf
形式は%d
を使用してtime.Month
タイプに、string
ではなく数字を使用する必要があるため、月は再び数値形式で表示されます。 ]ですが、1桁でしか表示されません。 2桁を表示する場合は、fmt.Printf
形式を変更してそのようにすることができますが、上記の出力に示すように、24時間制ではなく12時間制も表示する場合はどうでしょうか。 fmt.Printf
メソッドを使用すると、それを計算するために独自の計算を行う必要があります。 fmt.Printf
を使用して日付と時刻を印刷することは可能ですが、ご覧のとおり、最終的には面倒になる可能性があります。 このようにすると、表示するパーツごとに多数の行が作成されるか、表示する内容を決定するために独自の計算を行う必要があります。
このセクションでは、time.Now
を使用して現在の時刻を取得する新しいプログラムを作成しました。 現在時刻を取得したら、time.Time
タイプのYear
やHour
などのさまざまな機能を使用して、現在時刻に関する情報を出力します。 ただし、カスタム形式で表示するのは大変な作業になり始めました。 このタイプの一般的な作業を簡単にするために、Goを含む多くのプログラミング言語は、fmt.Printf
を使用して文字列をフォーマットする方法と同様に、日付と時刻をフォーマットする特別な方法を提供します。
特定の日付の印刷とフォーマット
Year
、Hour
、およびtime.Time
タイプが提供するその他のデータ関連のメソッドに加えて、Format
と呼ばれるメソッドも提供します。 Format
メソッドを使用すると、fmt.Printf
またはfmt.Sprintf
の形式を提供するのと同様に、Format
日付と時刻をどのように印刷するかを方法で説明します。 このセクションでは、前のセクションで追加した時間出力を複製しますが、Format
メソッドを使用するとはるかに簡潔になります。
ただし、Format
メソッドを使用する前に、プログラムを実行するたびに変更されない場合、Format
が日付と時刻の出力にどのように影響するかを簡単に確認できます。 これまでは、time.Now
を使用して現在の時刻を取得していたため、実行するたびに異なる番号が表示されていました。 Go time
パッケージは、time.Time
が表す特定の日時を指定できるtime.Date
関数というもう1つの便利な関数を提供します。
プログラムでtime.Now
の代わりにtime.Date
の使用を開始するには、main.go
ファイルを再度開き、time.Now
をtime.Date
に置き換えるように更新します。
...
func main() {
theTime := time.Date(2021, 8, 15, 14, 30, 45, 100, time.Local)
fmt.Println("The time is", theTime)
}
time.Date
関数のパラメーターには、time.Time
を使用する日時の年、月、日、時、分、秒が含まれます。 最後の2つのパラメーターの最初はナノ秒を占め、最後のパラメーターは時間を作成するためのタイムゾーンです。 タイムゾーン自体の使用については、このチュートリアルの後半で説明します。
更新を保存した後、go run
を使用してプログラムを実行します。
- go run main.go
出力は次のようになります。
OutputThe time is 2021-08-15 14:30:45.0000001 -0500 CDT
プログラムの実行時に現在の日付と時刻ではなく特定のローカルの日付と時刻を使用しているため、表示される出力は上記の出力に非常に近くなるはずです。 (ただし、コンピューターが設定されているタイムゾーンによっては、タイムゾーンの表示が異なる場合があります。)出力形式は、デフォルトのtime.Time
形式を使用しているため、以前と同じように表示されます。 作業する標準の日時ができたので、これを使用して、Format
メソッドを使用して表示するときの時刻のフォーマット方法の調整を開始できます。
Format
メソッドを使用した日付文字列のカスタマイズ
他の多くのプログラミング言語には、表示する日付と時刻をフォーマットする同様の方法が含まれていますが、Goがこれらのフォーマットのレイアウトを構築する方法は、他の言語で使用した場合とは少し異なる場合があります。 他の言語では、日付の書式設定は、Printf
がGoで機能するのと同様のスタイルを使用し、%
文字の後に、挿入する日付または時刻の一部を表す文字が続きます。 たとえば、4桁の年は%Y
で表されます。 ただし、Goでは、日付または時刻のこれらの部分は、特定の日付を表す文字で表されます。 Go日付形式で4桁の年を含めるには、実際には文字列自体に2006
を含めます。 このタイプのレイアウトの利点は、コードに表示される内容が実際に出力に表示される内容を表すことです。 出力の表現を見ることができると、フォーマットが探しているものと一致することを再確認しやすくなり、他の開発者がプログラムを実行せずにプログラムの出力を理解しやすくなります。最初にプログラムします。
Goが文字列形式の日付と時刻のレイアウトに使用する特定の日付は01/02 03:04:05PM '06 -0700
です。 日付と時刻の各コンポーネントを見ると、パーツごとに1つずつ増加していることがわかります。 月は最初に01
で、次に月の日が02
で、次に時が03
で、分が04
で、2番目が05
で、06
(または2006
)で年、そして最後に07
でタイムゾーン。 この順序を覚えておくと、将来の日付と時刻の形式を簡単に作成できるようになります。 フォーマットに使用できるオプションの例は、Goのタイムパッケージのドキュメントにもあります。
次に、この新しいFormat
メソッドを使用して、前のセクションで印刷した日付形式を複製してクリーンアップします。 表示するには数行と関数呼び出しが必要でした。Format
メソッドを使用すると、複製がはるかに簡単でクリーンになります。
main.go
ファイルを開き、新しいfmt.Println
呼び出しを追加して、Format
メソッドを使用してフォーマットされた日付でtheTime
を渡します。
...
func main() {
theTime := time.Date(2021, 8, 15, 14, 30, 45, 100, time.Local)
fmt.Println("The time is", theTime)
fmt.Println(theTime.Format("2006-1-2 15:4:5"))
}
フォーマットに使用されているレイアウトを見ると、上から同じ時刻を使用して、日付と時刻のフォーマット方法を指定していることがわかります(2006年1月2日)。 注意すべき点の1つは、前の例のように03
ではなく15
を使用していることです。 これは、12時間形式ではなく24時間形式で時間を表示することを希望していることを示しています。
この新しい形式からの出力を表示するには、プログラムを保存し、go run
を使用して実行します。
- go run main.go
出力は次のようになります。
OutputThe time is 2021-08-15 14:30:45.0000001 -0500 CDT
2021-8-15 14:30:45
ここに表示される出力は、前のセクションの終わりからの出力と似ていますが、実行するのがはるかに簡単でした。 含める必要があるのは、1行のコードとレイアウト文字列だけでした。 Format
関数が残りの作業を行います。
表示している日付または時刻によっては、数値を直接印刷するときに使用したような可変長形式を使用すると、自分自身、ユーザー、または値を読み取ろうとする他のコードが読みにくくなる可能性があります。 月の形式に1
を使用すると、3月は3
と表示され、10月は2文字を使用して10
と表示されます。 次に、main.go
を開き、別のより構造化されたレイアウトでプログラムに行を追加します。 このレイアウトでは、コンポーネントに0
プレフィックスを含め、12時間形式を使用するように時間を更新します。
...
func main() {
theTime := time.Date(2021, 8, 15, 14, 30, 45, 100, time.Local)
fmt.Println("The time is", theTime)
fmt.Println(theTime.Format("2006-1-2 15:4:5"))
fmt.Println(theTime.Format("2006-01-02 03:04:05 pm"))
}
コードを保存した後、go run
を使用してプログラムを再実行します。
- go run main.go
出力は次のようになります。
OutputThe time is 2021-08-15 14:30:45.0000001 -0500 CDT
2021-8-15 14:30:45
2021-08-15 02:30:45 pm
レイアウト文字列の数値に0
プレフィックスを追加すると、新しい出力の月の8
がレイアウトに一致する08
になることがわかります。 現在は12時間形式になっている時間にも、独自の0
プレフィックスが付いています。 ただし、最終的には、出力に表示される内容はコードに表示される形式を反映しているため、必要に応じて形式を微調整する方が簡単です。
多くの場合、フォーマットされた日付は他のプログラムによって解釈されることを意図しており、使用するたびにそれらのフォーマットを再作成するのは負担になる可能性があります。 場合によっては、事前定義された形式を使用できます。
事前定義された形式の使用
ログメッセージのタイムスタンプなど、一般的に使用される日付形式は多数あり、使用するたびにそれらを再作成すると、面倒になる可能性があります。 これらの場合のいくつかでは、time
パッケージには、使用できる事前定義された形式が含まれています。
利用可能で頻繁に使用される形式の1つは、 RFC3339で定義されている形式です。 RFC は、インターネット上の標準がどのように機能するかを定義するために使用されるドキュメントであり、他のRFCは相互に構築できます。 たとえば、HTTPがどのように機能するかを定義するRFC( RFC 2616 )や、HTTPをさらに定義するためにその上に構築されるRFCがあります。 したがって、RFC 3339の場合、RFCは、インターネット上のタイムスタンプに使用する標準形式を定義します。 このフォーマットはインターネット上でよく知られており、十分にサポートされているため、他の場所で見られる可能性が高くなります。
time
パッケージで事前定義された各時間形式は、それらが表す形式にちなんで名付けられたconst string
で表されます。 RFC 3339形式には、time.RFC3339
と呼ばれる形式とtime.RFC3339Nano
と呼ばれる形式の2つの形式があります。 フォーマット間の違いは、time.RFC3339Nano
バージョンのフォーマットにナノ秒が含まれていることです。
次に、main.go
ファイルを再度開き、出力にtime.RFC3339Nano
形式を使用するようにプログラムを更新します。
...
func main() {
theTime := time.Date(2021, 8, 15, 14, 30, 45, 100, time.Local)
fmt.Println("The time is", theTime)
fmt.Println(theTime.Format(time.RFC3339Nano))
}
事前定義された形式はstring
値であり、目的の形式であるため、通常使用する形式をいずれかの形式に置き換える必要があります。
出力を確認するには、go run
を使用してプログラムを再度実行します。
- go run main.go
出力は次のようになります。
OutputThe time is 2021-08-15 14:30:45.0000001 -0500 CDT
2021-08-15T14:30:45.0000001-05:00
RFC 3339形式は、時間値をstring
としてどこかに保存する必要がある場合に使用すると便利です。 他の多くのプログラミング言語やアプリケーションで読み取ることができ、日付と時刻を柔軟なstring
形式にすることができるのとほぼ同じくらいコンパクトです。
このセクションでは、Format
メソッドを使用して日付と時刻を出力するようにプログラムを更新しました。 この柔軟なレイアウトを使用すると、コードを最終出力のように見せることもできます。 最後に、事前定義されたレイアウト文字列の1つを使用して、十分にサポートされている形式を使用して日付と時刻を印刷しました。 次のセクションでは、プログラムを更新して、同じstring
値を操作可能なtime.Time
値に変換し直します。
文字列での日付と時刻の解析
多くの場合、アプリケーションを開発するときに、何らかの方法で解釈する必要があるstring
値として表される日付に出くわします。 値の日付部分を知る必要がある場合もあれば、時間部分を知る必要がある場合もありますが、値全体が必要な場合もあります。 Format
メソッドを使用してtime.Time
値からstring
値を作成することに加えて、Gotime
パッケージは変換するtime.Parse
関数を提供しますstring
をtime.Time
値に変換します。 time.Parse
関数は、Format
メソッドと同様に機能し、パラメーターとしてstring
値だけでなく予想される日付と時刻のレイアウトも取ります。
次に、プログラムでmain.go
ファイルを開き、time.Parse
関数を使用してtimeString
をtime.Time
変数に解析するように更新します。
...
func main() {
timeString := "2021-08-15 02:30:45"
theTime, err := time.Parse("2006-01-02 03:04:05", timeString)
if err != nil {
fmt.Println("Could not parse time:", err)
}
fmt.Println("The time is", theTime)
fmt.Println(theTime.Format(time.RFC3339Nano))
}
Format
メソッドとは異なり、time.Parse
メソッドは、渡されたstring
値が最初に提供されたレイアウトと一致しない場合に、潜在的なerror
値も返します。パラメータ。 使用されているレイアウトを見ると、time.Parse
に指定されたレイアウトは、同じ1
を月に使用し、2
を月の日に使用していることがわかります。 Format
メソッドで使用されます。
更新を保存した後、go run
を使用して更新されたプログラムを実行できます。
- go run main.go
出力は次のようになります。
OutputThe time is 2021-08-15 02:30:45 +0000 UTC
2021-08-15T02:30:45Z
この出力には、注意すべき点がいくつかあります。 1つは、timeString
から解析されるタイムゾーンが、+0
オフセットであり、協定世界時(UTC)として知られるデフォルトのタイムゾーンを使用していることです。 時間値もレイアウトにもタイムゾーンが含まれていないため、time.Parse
関数は、どのタイムゾーンに関連付けるかを認識していません。 ただし、ある時点で必要になった場合は、time
パッケージにtime.ParseInLocation 関数が含まれているため、使用する場所を指定できます。 注意すべき他の部分はRFC3339出力にあります。 出力はtime.RFC3339Nano
レイアウトを使用していますが、出力にはナノ秒が含まれていません。 これは、time.Parse
関数がナノ秒を解析していないため、値がデフォルトの0
に設定されているためです。 ナノ秒が0
の場合、time.RFC3339Nano
形式では出力にナノ秒が含まれません。
time.Parse
メソッドは、string
値を解析するときに、time
パッケージで提供される事前定義された時間レイアウトのいずれかを使用することもできます。 これを実際に確認するには、main.go
ファイルを開き、timeString
値を更新して、以前のtime.RFC3339Nano
からの出力と一致させ、time.Parse
パラメーターを更新して一致させます。 :
...
func main() {
timeString := "2021-08-15T14:30:45.0000001-05:00"
theTime, err := time.Parse(time.RFC3339Nano, timeString)
if err != nil {
fmt.Println("Could not parse time:", err)
}
fmt.Println("The time is", theTime)
fmt.Println(theTime.Format(time.RFC3339Nano))
}
コードを更新したら、プログラムを保存して、go run
を使用して再度実行できます。
- go run main.go
出力は次のようになります。
OutputThe time is 2021-08-15 14:30:45.0000001 -0500 CDT
2021-08-15T14:30:45.0000001-05:00
今回は、Format
メソッドからの出力は、time.Parse
がtimeString
からのタイムゾーンとナノ秒の両方を解析できたことを示しています。
このセクションでは、time.Parse
関数を使用して、任意の形式の日付と時刻の文字列値と事前定義されたレイアウトを解析しました。 ただし、これまでのところ、これまでに見たさまざまなタイムゾーンを操作していません。 Goがtime.Time
タイプに提供する別の機能セットは、次のセクションで説明するように、異なるタイムゾーン間で変換する機能です。
タイムゾーンの操作
世界中のユーザー、または少数のタイムゾーンのみでアプリケーションを開発する場合、一般的な方法は、協定世界時(UTC)を使用して日付と時刻を保存し、次の場合にユーザーの現地時間に変換することです。必要。 これにより、データを一貫した形式で保存でき、ユーザーに日付と時刻を表示する場合にのみ変換が必要になるため、データ間の計算が容易になります。
このチュートリアルの前のセクションでは、主に独自のローカルタイムゾーンに基づく時間に基づいて動作するプログラムを作成しました。 time.Time
値をUTCとして保存するには、最初にそれらをUTCに変換する必要があります。 これは、UTC
メソッドを使用して行います。このメソッドは、呼び出した時刻のコピーをUTCで返します。
注:このセクションでは、コンピューターのローカルタイムゾーンとUTCの間の時刻を変換します。 使用しているコンピューターのローカルタイムゾーンがUTCと一致するものに設定されている場合、UTCとその逆の変換では時間の違いが表示されないことに気付くでしょう。
次に、main.go
ファイルを開いてプログラムを更新し、theTime
でUTC
メソッドを使用して時刻のUTCバージョンを返します。
...
func main() {
theTime := time.Date(2021, 8, 15, 14, 30, 45, 100, time.Local)
fmt.Println("The time is", theTime)
fmt.Println(theTime.Format(time.RFC3339Nano))
utcTime := theTime.UTC()
fmt.Println("The UTC time is", utcTime)
fmt.Println(utcTime.Format(time.RFC3339Nano))
}
今回は、プログラムがローカルタイムゾーンにtime.Time
値としてtheTime
を作成し、2つの異なる形式で出力してから、UTC
メソッドを使用してその時間を現地時間からUTC時間。
プログラムからの出力を確認するには、go run
を使用して実行できます。
- go run main.go
出力は次のようになります。
OutputThe time is 2021-08-15 14:30:45.0000001 -0500 CDT
2021-08-15T14:30:45.0000001-05:00
The UTC time is 2021-08-15 19:30:45.0000001 +0000 UTC
2021-08-15T19:30:45.0000001Z
出力はローカルタイムゾーンによって異なりますが、上記の出力では、最初に印刷されるのはCDT
(北米中部夏時間)であるUTC
メソッドが呼び出され、UTC時刻が出力されると、時刻をUTCに変換すると5時間が追加されるため、時刻が14
から19
に変わることがわかります。 。
同様に、time.Time
でLocal
メソッドを使用して、UTC時刻を現地時間に戻すこともできます。 main.go
ファイルを再度開き、更新してutcTime
のLocal
メソッドへの呼び出しを追加し、ローカルタイムゾーンに変換し直します。
...
func main() {
theTime := time.Date(2021, 8, 15, 14, 30, 45, 100, time.Local)
fmt.Println("The time is", theTime)
fmt.Println(theTime.Format(time.RFC3339Nano))
utcTime := theTime.UTC()
fmt.Println("The UTC time is", utcTime)
fmt.Println(utcTime.Format(time.RFC3339Nano))
localTime := utcTime.Local()
fmt.Println("The Local time is", localTime)
fmt.Println(localTime.Format(time.RFC3339Nano))
}
ファイルが保存されたら、go run
を使用してプログラムを実行します。
- go run main.go
出力は次のようになります。
OutputThe time is 2021-08-15 14:30:45.0000001 -0500 CDT
2021-08-15T14:30:45.0000001-05:00
The UTC time is 2021-08-15 19:30:45.0000001 +0000 UTC
2021-08-15T19:30:45.0000001Z
The Local time is 2021-08-15 14:30:45.0000001 -0500 CDT
2021-08-15T14:30:45.0000001-05:00
UTC時刻がローカルタイムゾーンに変換されていることがわかります。 上記の出力では、UTCからCDTへの変換は、UTCから5時間が差し引かれ、時間を19
から14
に変更したことを意味します。
このセクションでは、UTC
メソッドを使用して、ローカルタイムゾーンと標準UTCタイムゾーンの間で日付と時刻を変換し、Local
メソッドを使用して、プログラムを更新しました。
日付と時刻の値を利用できるようになると、Go time
パッケージが提供する、アプリケーションで役立つ追加機能がいくつかあります。 これらの機能の1つは、特定の時間が次の時間の前か後かを判断することです。
2回の比較
2つの日付を互いに比較することは、それらを比較するときに考慮する必要のあるすべての変数のために、一見難しい場合があります。 たとえば、タイムゾーンを考慮する必要がある、または月の日数が互いに異なるという事実。 time
パッケージは、これを簡単にするためのいくつかの方法を提供します。
time
パッケージは、これらの比較を容易にする2つのメソッドを提供します。Before
メソッドとAfter
メソッドで、time.Time
タイプで使用できます。 これらのメソッドは両方とも単一の時間値を受け入れ、呼び出されている時間が指定された時間の前か後かに応じて、true
またはfalse
のいずれかを返します。
これらの関数の動作例を確認するには、main.go
ファイルを開き、2つの異なる日付を含むように更新してから、Before
とAfter
を使用してこれらの日付を比較し、出力:
...
func main() {
firstTime := time.Date(2021, 8, 15, 14, 30, 45, 100, time.UTC)
fmt.Println("The first time is", firstTime)
secondTime := time.Date(2021, 12, 25, 16, 40, 55, 200, time.UTC)
fmt.Println("The second time is", secondTime)
fmt.Println("First time before second?", firstTime.Before(secondTime))
fmt.Println("First time after second?", firstTime.After(secondTime))
fmt.Println("Second time before first?", secondTime.Before(firstTime))
fmt.Println("Second time after first?", secondTime.After(firstTime))
}
ファイルを更新したら、ファイルを保存して、go run
を使用して実行します。
- go run main.go
出力は次のようになります。
OutputThe first time is 2021-08-15 14:30:45.0000001 +0000 UTC
The second time is 2021-12-25 16:40:55.0000002 +0000 UTC
First time before second? true
First time after second? false
Second time before first? false
Second time after first? true
コードはUTCタイムゾーンで明示的な日付を使用しているため、出力は上記の出力と一致する必要があります。 firstTime
でBefore
メソッドを使用し、比較するためにsecondTime
を提供すると、true
が2021-12-25
の前にあります。 firstTime
のAfter
メソッドを使用してsecondTime
を提供すると、2021-08-15
が2021-12-25
の後にあるのはfalse
であると表示されます。 。 secondTime
のメソッドを呼び出す順序を変更すると、予想どおり、逆の結果が表示されます。
time
パッケージで2つの日付と時刻を比較する別の方法は、Sub
メソッドです。 Sub
メソッドは、ある日付を別の日付から減算し、新しいタイプtime.Duration
を使用して値を返します。 絶対的な時点を表すtime.Time
値とは異なり、time.Duration
値は時間の差を表します。 たとえば、「1時間以内」は、現在の時刻に基づいて異なる意味を持つため、期間になりますが、「正午」は特定の絶対時間を表します。 Goは、time.Duration
タイプをさまざまな場所で使用します。たとえば、関数がエラーを返すまでの待機時間を定義する場合や、1つの時間の間の時間を知る必要がある場合などです。と別の。
次に、main.go
ファイルを更新してfirstTime
およびsecondTime
値でSub
メソッドを使用し、結果を出力します。
...
func main() {
firstTime := time.Date(2021, 8, 15, 14, 30, 45, 100, time.UTC)
fmt.Println("The first time is", firstTime)
secondTime := time.Date(2021, 12, 25, 16, 40, 55, 200, time.UTC)
fmt.Println("The second time is", secondTime)
fmt.Println("Duration between first and second time is", firstTime.Sub(secondTime))
fmt.Println("Duration between second and first time is", secondTime.Sub(firstTime))
ファイルを保存し、go run
を使用して実行します。
- go run main.go
出力は次のようになります。
OutputThe first time is 2021-08-15 14:30:45.0000001 +0000 UTC
The second time is 2021-12-25 16:40:55.0000002 +0000 UTC
Duration between first and second time is -3170h10m10.0000001s
Duration between second and first time is 3170h10m10.0000001s
上記の出力は、2つの日付の間に3,170時間、10分、10秒、および100ナノ秒があることを示しており、出力について注意すべき点がいくつかあります。 1つ目は、1回目と2回目の間の期間が負の値であるということです。 これは、2回目が1回目以降であり、0
から5
を引いて、-5
を取得した場合と同様です。 2つ目の注意点は、期間の最大の測定単位は1時間であるため、日や月に分割されないことです。 1か月の日数には一貫性がなく、夏時間の切り替え時に「日」の意味が異なる可能性があるため、変動しない最も正確な測定値は1時間です。
このセクションでは、3つの異なる方法を使用して2回比較するようにプログラムを更新しました。 最初に、Before
およびAfter
メソッドを使用して、ある時間が別の時間の前後かどうかを判断し、次にSub
を使用して2つの時間の間の長さを確認しました。 ただし、time
パッケージがtime.Duration
を使用する方法は、2つの時間の間の期間を取得することだけではありません。 次のセクションで説明するように、これを使用してtime.Time
値に時間を追加または削除することもできます。
時間の加算または減算
アプリケーションを作成する場合、日付と時刻を使用する一般的な操作の1つは、別の時刻に基づいて過去または未来の時刻を決定することです。 これは、サブスクリプションが次に更新される時期を決定したり、値がチェックされてから一定の時間が経過したかどうかを判断するなどの機能に使用できます。 いずれにせよ、Gotime
パッケージはそれを処理する方法を提供します。 ただし、すでに知っている日付に基づいて別の日付を見つけるには、独自のtime.Duration
値を定義できる必要があります。
time.Duration
値の作成は、時間の単位を乗算するだけで、紙に期間を書き込む方法と似ています。 たとえば、1時間を表すtime.Duration
を作成するには、time.Hour
の値にtime.Duration
で表す時間数を掛けて定義します。
oneHour := 1 * time.Hour
twoHours := 2 * time.Hour
tenHours := 10 * time.Hour
time.Minute
、time.Second
などを使用することを除いて、より小さな時間単位の宣言も同様の方法で処理されます。
tenMinutes := 10 * time.Minute
fiveSeconds := 5 * time.Second
ある期間を別の期間に追加して、期間の合計を取得することもできます。 これが実際に動作することを確認するには、main.go
ファイルを開き、それを更新してtoAdd
期間変数を宣言し、それに異なる期間を追加します。
...
func main() {
toAdd := 1 * time.Hour
fmt.Println("1:", toAdd)
toAdd += 1 * time.Minute
fmt.Println("2:", toAdd)
toAdd += 1 * time.Second
fmt.Println("3:", toAdd)
}
更新が完了したら、ファイルを保存し、go run
を使用してプログラムを実行します。
- go run main.go
出力は次のようになります。
Output1: 1h0m0s
2: 1h1m0s
3: 1h1m1s
出力を見ると、最初に印刷される期間は1時間であり、コードの1 * time.Hour
に対応していることがわかります。 次に、1 * time.Minute
をtoAdd
の値に追加しました。これは、1時間1分の値として表示されます。 最後に、1 * time.Second
をtoAdd
に追加しました。これにより、time.Duration
の値は1時間、1分、1秒になります。
1つのステートメントで期間を合計したり、別のステートメントから期間を減算したりすることもできます。
oneHourOneMinute := 1 * time.Hour + 1 * time.Minute
tenMinutes := 1 * time.Hour - 50 * time.Minute
次に、main.go
ファイルを開き、プログラムを更新して、次のような組み合わせを使用して、toAdd
から1分1秒を減算します。
...
func main() {
...
toAdd += 1 * time.Second
fmt.Println("3:", toAdd)
toAdd -= 1*time.Minute + 1*time.Second
fmt.Println("4:", toAdd)
}
コードを保存した後、go run
を使用してプログラムを実行できます。
- go run main.go
出力は次のようになります。
Output1: 1h0m0s
2: 1h1m0s
3: 1h1m1s
4: 1h0m0s
出力に追加された新しい4行目は、1 * time.Minute
と1 * time.Second
の合計を差し引くために含めた新しいコードを示しており、元の1時間の値になります。
これらの期間をtime.Time
タイプのAdd
メソッドと組み合わせて使用すると、すでに持っている時間値を取得し、その時間の前後の他の任意の時点で時間を決定できます。 この実行例を確認するには、main.go
ファイルを開き、toAdd
値を24時間、または24 * time.Hour
に設定するように更新します。 次に、time.Time
値に対してAdd
メソッドを使用して、その時点から24時間後の時刻を確認します。
...
func main() {
theTime := time.Date(2021, 8, 15, 14, 30, 45, 100, time.UTC)
fmt.Println("The time is", theTime)
toAdd := 24 * time.Hour
fmt.Println("Adding", toAdd)
newTime := theTime.Add(toAdd)
fmt.Println("The new time is", newTime)
}
ファイルを保存した後、go run
を使用してプログラムを実行します。
- go run main.go
出力は次のようになります。
OutputThe time is 2021-08-15 14:30:45.0000001 +0000 UTC
Adding 24h0m0s
The new time is 2021-08-16 14:30:45.0000001 +0000 UTC
出力を見ると、2021-08-15
に24時間を追加すると、2021-08-16
の新しい日付になることがわかります。
時間を差し引くには、Add
メソッドも使用しますが、これは少し直感に反します。 Sub
メソッドは、2つの日付間の時間の差を取得するために使用されるため、負の値のAdd
を使用して、time.Time
値から時間を減算します。
もう一度、これがプログラムで実行されていることを確認するには、main.go
ファイルを開いて更新し、24時間のtoAdd
値を負の値に変更します。
...
func main() {
theTime := time.Date(2021, 8, 15, 14, 30, 45, 100, time.UTC)
fmt.Println("The time is", theTime)
toAdd := -24 * time.Hour
fmt.Println("Adding", toAdd)
newTime := theTime.Add(toAdd)
fmt.Println("The new time is", newTime)
}
ファイルを保存した後、go run
を使用してプログラムをもう一度実行します。
- go run main.go
出力は次のようになります。
OutputThe time is 2021-08-15 14:30:45.0000001 +0000 UTC
Adding -24h0m0s
The new time is 2021-08-14 14:30:45.0000001 +0000 UTC
今回の出力では、元の時刻に24時間を追加する代わりに、新しい日付が元の時刻の24時間前になっていることがわかります。
このセクションでは、time.Hour
、time.Minute
、およびtime.Second
を使用して、さまざまな次数のtime.Duration
値を作成しました。 また、time.Duration
値をAdd
メソッドとともに使用して、元の値の前後の両方で新しいtime.Time
値を取得しました。 time.Now
、Add
メソッド、およびBefore
またはAfter
メソッドを組み合わせることで、アプリケーションの強力な日付と時刻の機能にアクセスできます。
結論
このチュートリアルでは、time.Now
を使用して、コンピューターの現在の現地時間のtime.Time
値を取得してから、Year
、Month
、Hour
、およびその時間に関する特定の情報にアクセスするための他の方法。 次に、Format
メソッドを使用して、カスタム形式と事前定義された形式を使用して時刻を印刷しました。 次に、time.Parse
関数を使用して、時刻を含むstring
値を解釈し、そこから時刻値を抽出しました。 時間値を取得したら、UTC
およびLocal
メソッドを使用して、UTCとローカルタイムゾーンの間の時間を変換しました。 その後、Sub
メソッドを使用して、2つの異なる時間の間の期間を取得してから、Add
メソッドを使用して、異なる時間値に関連する時間を検索しました。
このチュートリアルで説明されているさまざまな関数とメソッドを使用すると、アプリケーションで大いに役立ちますが、興味がある場合は、Go timeパッケージに他の多くの機能も含まれています。
このチュートリアルは、 DigitalOcean How to Code inGoシリーズの一部でもあります。 このシリーズでは、Goの初めてのインストールから、言語自体の使用方法まで、Goに関する多くのトピックを取り上げています。