日付と時刻1

DateTime構造体

C#で日付や時刻の操作を行うには、標準ライブラリのDateTime構造体を使用します。
(System名前空間)
構造体はクラスと同じく、便利な機能がまとめられたものと考えてください。
(詳しくは構造体の項で説明します)

現在の日時情報の取得

システム(パソコン等)の現在の日時はDateTime.Nowプロパティで取得できます。
(読み取り専用プロパティ。「プロパティ」とはあるオブジェクトが内部に持つデータのこと)


static void Main(string[] args)
{
    Console.WriteLine(DateTime.Now);
}
2020/01/02 3:04:56

DateTime.NowプロパティをそのままConsole.WriteLineメソッドに渡すと、日時が出力されます。
しかしこれは文字列型ではなく、DateTimeというデータ型です。
つまりstring型ではなくDateTime型の変数に格納できます。


//DateTime型の変数に格納
DateTime dt = DateTime.Now;

この変数dtはDateTime構造体のオブジェクトインスタンスと言います。
DateTime型のオブジェクトはConsole.WriteLineメソッドに渡すと保存している日時を表示します。
(Console.WriteLineメソッドは、指定したオブジェクトが持つToStringメソッドを呼び出して文字列に変換する)

任意の日時情報の作成

現在日時ではなく任意の日時を作成するにはコンストラクタを呼び出してDateTimeオブジェクトを作成します。


//0001/01/01 0:00:00
DateTime dt1 = new DateTime();

//2001/02/03 0:00:00
DateTime dt2 = new DateTime(2001, 2, 3);

//2001/02/03 4:05:06
DateTime dt3 = new DateTime(2001, 2, 3, 4, 5, 6);

Console.WriteLine(dt1);
Console.WriteLine(dt2);
Console.WriteLine(dt3);
0001/01/01 0:00:00
2001/02/03 0:00:00
2001/02/03 4:05:06

new DateTimeに続いて丸括弧の中に作成したい日時の情報を指定します。
(newで呼び出す特殊なメソッドをコンストラクタといいます)
値は「年,月,日,時,分,秒」の順です。
時刻の部分は省略できます。

ここに指定できる値は「日時」として有効な範囲内の数値です。
以下の表の数値以外の値を指定するとエラー(例外)になります。

単位 範囲
1~9999
1~12
1~31
0~23
0~59
0~59
ミリ秒 0~999
マイクロ秒 0~999

DateTime型のプロパティ

DateTimeオブジェクトには、年や日などを個別に表すプロパティや、その他の日時情報に関するプロパティが多数用意されています。
これらはすべて読み取り専用で、プロパティに値を直接設定することはできません。

プロパティ 説明 データ型
Year int
Month int
Day int
Hour int
Minute int
Second int
Millisecond ミリ秒 int
Microsecond マイクロ秒
(.NET7以降)
int
Nanosecond ナノ秒
0~900の100刻みの単位
(.NET7以降)
int
DayOfYear 年間積算日
(その年の1月1日から通算した日数)
int
Date 年月日 DateTime
TimeOfDay 時刻 TimeSpan
DayOfWeek 曜日 DayOfWeek
Ticks 0001年1月1日 0時0分0秒からの経過時間
(100ナノ秒単位)
long
Kind ローカル時刻かUTC時刻かの設定 DateTimeKind

以下は静的プロパティです。
(DateTime.○○という形式のもの)

プロパティ 説明 データ型
DateTime.Now システムのローカル時刻 DateTime
DateTime.UtcNow システムのUTC時刻 DateTime
DateTime.Today システムの年月日 DateTime

年/月/日/時/分/秒/ミリ秒/マイクロ秒

これらは日時を表すint型の値です。


DateTime dt = new DateTime(2001, 2, 3, 4, 5, 6, 789, 123);

Console.WriteLine(dt);
Console.WriteLine(dt.Year);
Console.WriteLine(dt.Month);
Console.WriteLine(dt.Day);
Console.WriteLine(dt.Hour);
Console.WriteLine(dt.Minute);
Console.WriteLine(dt.Second);
Console.WriteLine(dt.Millisecond);
Console.WriteLine(dt.Microsecond); //.NET7以降
2001/02/03 4:05:06
2001
2
3
4
5
6
789
123

Millisecondプロパティは1/1000秒(ミリ秒)です。
Microsecondプロパティはミリ秒のさらに1/1000の単位(マイクロ秒)で、.NET7以降で使用できます。
これらはDateTime型オブジェクトの作成時に値を指定することもできます。


//ミリ秒の指定
DateTime dt1 = new DateTime(2001, 2, 3, 4, 5, 6, 789);

//ミリ秒とマイクロ秒の指定
DateTime dt2 = new DateTime(2001, 2, 3, 4, 5, 6, 789, 123);

Console.WriteLine(dt1.Millisecond);
Console.WriteLine(dt1.Microsecond);
Console.WriteLine(dt2.Millisecond);
Console.WriteLine(dt2.Microsecond);
789
0
789
123

年間積算日

DayOfYearプロパティは、その年の1月1日から起算した経過日数を取得します。
値はint型で、1~366の数値になります。


DateTime dt1 = new DateTime(2001, 1, 2);
DateTime dt2 = new DateTime(2001, 7, 1);

Console.WriteLine(dt1.DayOfYear);
Console.WriteLine(dt2.DayOfYear);
2
182

年月日/時刻

Dateプロパティは、DateTimeオブジェクトから日付部分の情報だけを取り出したものを取得します。
TimeOfDayプロパティは、DateTimeオブジェクトから時刻部分だけを取り出したものを取得します。


DateTime dt = new DateTime(2001, 2, 3, 4, 5, 6);

Console.WriteLine(dt);
Console.WriteLine(dt.Date);
Console.WriteLine(dt.TimeOfDay);
2001/02/03 4:05:06
2001/02/03 0:00:00
04:05:06

Dateプロパティは(時刻の部分をゼロにした)DateTimeオブジェクトを返しますが、TimeOfDayプロパティはTimeSpanというデータ型(構造体)を返します。
これは日付の情報は持たずに時刻の情報だけを持つデータ型で、時間の差の表現や計算などに用いられます。

曜日

曜日はDayOfWeekプロパティで取得できます。
これはDayOfWeekという列挙型の値です。


static void ShowDate(DateTime dt)
{
    Console.WriteLine($"{dt.Year}/{dt.Month}/{dt.Day} {dt.DayOfWeek}({(int)dt.DayOfWeek})");
}

static void Main(string[] args)
{
    DateTime dt1 = new DateTime(2001, 1, 7);
    DateTime dt2 = new DateTime(2001, 1, 8);
    DateTime dt3 = new DateTime(2001, 1, 12);
    DateTime dt4 = new DateTime(2001, 1, 13);

    ShowDate(dt1);
    ShowDate(dt2);
    ShowDate(dt3);
    ShowDate(dt4);

    //DayOfWeek型の変数に格納できる
    DayOfWeek dow = dt1.DayOfWeek;
}
2001/1/7 Sunday(0)
2001/1/8 Monday(1)
2001/1/12 Friday(5)
2001/1/13 Saturday(6)

DayOfWeek列挙型は日曜日が0で、0~6の値で各曜日を表します。

タイマー刻み数

Ticksプロパティはタイマー刻み数という値を取得します。
タイマー刻み数はシステムが計測できる時間の最小の単位で、「0001年1月1日 0時0分0秒」からの経過時間を100ナノ秒単位で表す数値です。
(ナノはマイクロの1/1000、100ナノ秒は1マイクロ秒の1/10)
膨大な数になるのでlong型(64ビット)です。


DateTime dt = new DateTime(2001, 2, 3, 4, 5, 6, 789);
Console.WriteLine(dt.Ticks);
631167699067890000

DateTime型のYearHourなどの情報は、すべてこのTicksプロパティの値から計算されています。
タイマー刻み数をDateTime型やTimeSpan型のコンストラクタ(newするときに指定する値)に渡すことで、日時情報を復元することができます。
(ただしDateTime型の場合は、後述するKindプロパティの値は復元されません)


DateTime dt1 = new DateTime(2001, 2, 3, 4, 5, 6);
long ticks = dt1.Ticks;

DateTime dt2  = new DateTime(ticks);
TimeSpan ts = new TimeSpan(ticks);

Console.WriteLine(dt2);
Console.WriteLine(ts);
2001/02/03 4:05:06
730518.04:05:06

ローカル時刻とUTC時刻

Kindプロパティは、その日時情報がローカル時刻を表すかUTC時刻を表すかを取得します。
このプロパティはDateTimeKindという列挙型で、DateTime型オブジェクトを作成するときに引数の最後に指定することができます。


DateTime dt1 = DateTime.Now; //NowプロパティはLocal
DateTime dt2 = new DateTime(2001, 2, 3, 4, 5, 6); //省略した場合
DateTime dt3 = new DateTime(2001, 2, 3, 4, 5, 6, DateTimeKind.Utc);

Console.WriteLine(dt1.Kind);
Console.WriteLine(dt2.Kind);
Console.WriteLine(dt3.Kind);
Local
Unspecified
Utc

DateTimeKind列挙型は、UTC時刻を表すUtcと、ローカル時刻を表すLocalのほかに、どちらか不明な状態を表すUnspecifiedというフィールドがあります。
DateTime型のオブジェクトを作成するときに何も指定しないとUnspecifiedになります。

Kindプロパティはローカル時刻だけを扱う場合は特に設定しなくても問題ありません。
詳しく説明すると結構な分量になるので、ここでは簡単にローカル時刻とUTC時刻の変換メソッドをいくつか使用しているサンプルコードを掲載しておきます。


static void ShowDate(DateTime dt)
{
    Console.WriteLine($"{dt} {dt.Kind}");
}

static void Main(string[] args)
{
    //現在のローカル時刻 
    ShowDate(DateTime.Now);

    //現在のUTC時刻
    ShowDate(DateTime.UtcNow);

    //ローカル時刻 
    DateTime dtLocal = new DateTime(2001, 2, 3, 4, 5, 6, DateTimeKind.Local);

    //ローカル時刻→UTC時刻
    DateTime dtUtc = dtLocal.ToUniversalTime();

    //UTC時刻→ローカル時刻
    DateTime dtLocal2 = dtUtc.ToLocalTime();

    ShowDate(dtLocal);
    ShowDate(dtUtc);
    ShowDate(dtLocal2);
}
2020/01/02 3:04:56 Local
2020/01/01 18:04:56 Utc
2001/02/03 4:05:06 Local
2001/02/02 19:05:06 Utc
2001/02/03 4:05:06 Local

static void ShowDate(DateTime dt)
{
    Console.WriteLine($"{dt} {dt.Kind}");
}

static void Main(string[] args)
{
    //ローカル時刻 
    DateTime dtLocal = new DateTime(2001, 2, 3, 4, 5, 6, DateTimeKind.Local);

    //ローカル時刻→UTC時刻
    DateTime dtUtc = System.TimeZoneInfo.ConvertTimeToUtc(dtLocal);

    //UTC時刻→ローカル時刻
    DateTime dtLocal2 = System.TimeZoneInfo.ConvertTimeFromUtc(dtUtc, TimeZoneInfo.Local);

    ShowDate(dtLocal);
    ShowDate(dtUtc);
    ShowDate(dtLocal2);
}
2001/02/03 4:05:06 Local
2001/02/02 19:05:06 Utc
2001/02/03 4:05:06 Local

ここでいう「ローカル時刻」はシステムのローカル時刻です。
DateTime構造体では、他の地域のローカル時刻を扱うことはできません。

時間は地域によって時差があり、時差の扱い方を各国がバラバラに決めていては困るので国際的な基準が決められています。
これを協定世界時(UTC)といいます。
各国はこのUTCを基準として、それぞれの地域の時差に合わせた標準時を使用しています。
標準時はその地域(ローカル)で使用される時間なのでローカル時刻とも呼ばれ、コンピュータ関係ではこう呼ばれることが多いです。
地域による時刻の設定を「タイムゾーン」といいます。

UTCはイギリスが基準(時差0時間)となっていて、日本はイギリス時間に+9時間したJST(日本標準時)をローカル時刻として使用しています。
JSTは「UTC+9」や「UTC+0900」とも表記されます。

TimeSpan構造体

日時情報を扱うプログラムではTimeSpan構造体がよく使用されます。
(System名前空間)
DateTime構造体は日時情報を扱いますが、TimeSpan構造体は時間の「範囲、間隔、期間」(time span)を扱います。

.NET Core2.1以降にはDateTime.UnixEpochというUNIXエポックを表す定数があるのでこれを利用できますが、.NET Frameworkにはないため

TimeSpan型オブジェクトの作成

TimeSpan構造体はnewでコンストラクタを呼び出して初期化します。


//01:02:03
//時、分、秒
TimeSpan ts1 = new TimeSpan(1, 2, 3);

//1.02:03:04
//日、時、分、秒
TimeSpan ts2 = new TimeSpan(1, 2, 3, 4);

//1.02:03:04.0050000
//日、時、分、秒、ミリ秒
TimeSpan ts3 = new TimeSpan(1, 2, 3, 4, 5);

//1.02:03:04.0050060
//日、時、分、秒、ミリ秒、マイクロ秒
TimeSpan ts4 = new TimeSpan(1, 2, 3, 4, 5, 6);

//00:00:12.3456789
//Ticks
TimeSpan ts5 = new TimeSpan(123456789);

//-00:58:20
//その時間単位の範囲外の値や負の値も指定可能
TimeSpan ts6 = new TimeSpan(-1, 0, 100);

Console.WriteLine(ts1);
Console.WriteLine(ts2);
Console.WriteLine(ts3);
Console.WriteLine(ts4);
Console.WriteLine(ts5);
Console.WriteLine(ts6);
01:02:03
1.02:03:04
1.02:03:04.0050000
1.02:03:04.0050060
00:00:12.3456789
-00:58:20

TimeSpan構造体が持つ時間情報の最大の単位は「日」です。
DateTime型は例えば分や秒の値は0~59の範囲で指定する必要がありましたが、TimeSpan型はそれを超える値や、マイナス値を指定することもできます。

初期化用のメソッド

「1時間」や「30分」という単純な時間情報のTimeSpanオブジェクトを作成する場合は、以下のメソッドを使用すると便利です。

メソッド 説明
TimeSpan.FromDays(double) 日数の指定
TimeSpan.FromHours(double) 時間数の指定
TimeSpan.FromMinutes(double) 分数の指定
TimeSpan.FromSeconds(double) 秒数の指定
TimeSpan.FromMilliseconds(double) ミリ秒数の指定
TimeSpan.FromMicroseconds(double) マイクロ秒数の指定
(.NET7以降)
TimeSpan.FromTicks(long) タイマー刻み数の指定

FromTicksメソッド以外は小数を指定することができます。
例えばTimeSpan.FromDays(0.5)は12時間を表します。


TimeSpan ts1 = TimeSpan.FromDays(0.5);      //0.5日(12時間)
TimeSpan ts2 = TimeSpan.FromHours(6);       //6時間
TimeSpan ts3 = TimeSpan.FromMinutes(30.1);  //30分6秒

Console.WriteLine(ts1);
Console.WriteLine(ts2);
Console.WriteLine(ts3);
12:00:00
06:00:00
00:30:06

定数

以下の定数は分や秒などの固定の長さのタイマー刻み数を取得する際に利用できます。
これらは全てlong型です。

定数 説明
TimeSpan.TicksPerDay 1日あたりのタイマー刻み数
(864000000000)
TimeSpan.TicksPerHour 1時間あたりのタイマー刻み数
(36000000000)
TimeSpan.TicksPerMinute 1分あたりのタイマー刻み数
(600000000)
TimeSpan.TicksPerSecond 1秒あたりのタイマー刻み数
(10000000)
TimeSpan.TicksPerMillisecond 1ミリ秒あたりのタイマー刻み数
(10000)
TimeSpan.TicksPerMicrosecond 1マイクロ秒あたりのタイマー刻み数
(10)
TimeSpan.NanosecondsPerTick 1タイマー刻み数あたりのナノ秒
(100)

時間間隔がゼロのTimeSpanオブジェクトはTimeSpan.Zeroという定数で作成することができます。


//1日
TimeSpan ts1 = TimeSpan.FromTicks(TimeSpan.TicksPerDay);

//ゼロ
TimeSpan ts2 = TimeSpan.Zero;

TimeSpan構造体のプロパティ

作成したTimeSpanオブジェクトは以下のプロパティで値を取り出すことができます。

プロパティ 説明 データ型
Days int
Hours 時間 int
Minutes int
Seconds int
Milliseconds ミリ秒 int
Microseconds 現マイクロ秒 int
Nanoseconds ナノ秒 int
Ticks タイマー刻み数 long
TotalDays 全体の日数 double
TotalHours 全体の時間数 double
TotalMinutes 全体の分数 double
TotalSeconds 全体の秒数 double
TotalMilliseconds 全体のミリ秒数 double
TotalMicroseconds 全体のマイクロ秒数 double
TotalNanoseconds 全体のナノ秒数 double

「全体の○○」とは、そのTimeSpanオブジェクトが保存する時間情報を指定の単位で表した場合の値です。
例えばちょうど1日の長さを持つオブジェクトならば、そのTotalHoursプロパティは「24」になり、TotalMinutesプロパティは「1440」になります。


TimeSpan ts = new TimeSpan(1, 2, 3, 4);
Console.WriteLine(ts.Days);
Console.WriteLine(ts.Hours);
Console.WriteLine(ts.Minutes);
Console.WriteLine(ts.Seconds);
Console.WriteLine();
Console.WriteLine(ts.TotalDays);
Console.WriteLine(ts.TotalHours);
Console.WriteLine(ts.TotalMinutes);
Console.WriteLine(ts.TotalSeconds);
1
2
3
4

1.085462962962963
26.051111111111112
1563.0666666666666
93784

DateTimeOffset構造体

日時情報を扱う場合、DateTime構造体のほかにDateTimeOffset構造体を使用することもできます。
(System名前空間)
DateTime構造体はKindプロパティでローカル時刻かUTC時刻か(あるいは不明か)の情報を持っていますが、これがローカル時刻を表すとき、UTC時刻との差が具体的にいくつなのかの情報は持っていません。
つまり「どこの地域のローカル時刻なのか」はそれだけでは判断できず、時差を扱うプログラムでは不都合なことがあります。
DateTime構造体はUTC時刻との差(オフセット)を持っており、時差を容易に扱えるようになっています。

時差情報がない分DateTime構造体のほうが単純なので、時差を考慮する必要がない場合はそちらを使用し、時差を扱うプログラムではDateTimeOffset構造体を使用するのが良いでしょう。

DateTimeOffset型オブジェクトの作成

現在の日時情報の取得

DateTimeOffset型オブジェクトは、DateTime型と同じくDateTimeOffset.Nowプロパティで現在のシステムローカル時刻と時差を、DateTimeOffset.UtcNowプロパティでUTC時刻(時差はゼロ)を取得することができます。


DateTimeOffset dto1 = DateTimeOffset.Now;
DateTimeOffset dto2 = DateTimeOffset.UtcNow;

任意の日時情報の作成

DateTime型と同じく、コンストラクタ(newするやつ)で日付と時刻を指定して作成することができます。
この時、引数の最後にTimeSpan構造体でUTC時刻からの時差(オフセット)を指定します。
(時差情報の省略はできません)


//時差+9時間(日本時間)
DateTimeOffset dto1 = new DateTimeOffset(
    2001, 2, 3, 4, 5, 6, new TimeSpan(9, 0, 0));
Console.WriteLine(dto1);

//ミリ秒
DateTimeOffset dto2 = new DateTimeOffset(
    2001, 2, 3, 4, 5, 6, 789, new TimeSpan(9, 0, 0));

//ミリ秒とマイクロ秒(.NET7)
DateTimeOffset dto3 = new DateTimeOffset(
    2001, 2, 3, 4, 5, 6, 789, 123, new TimeSpan(9, 0, 0));
2001/02/03 4:05:06 +09:00

TimeSpanのコンストラクタは「時,分,秒」の順で値を指定しますが、時差は時間数と分数で表すので、DateTimeOffset型を作成するときは秒の値は必ず0を指定する必要があります。
(0以外を指定するとArgumentException例外発生)
また、時差は「-14時間~+14時間」の範囲で指定する必要があります。
(範囲外の値を指定するとArgumentOutOfRangeException例外発生)

また、既存のDateTime型を使用してDateTimeOffset型を作成することもできます。


DateTime dtLocal = new DateTime(2001, 2, 3, 4, 5, 6, DateTimeKind.Local);
DateTime dtUtc = new DateTime(2001, 2, 3, 4, 5, 6, DateTimeKind.Utc);
DateTime dtUnspecified = new DateTime(2001, 2, 3, 4, 5, 6, DateTimeKind.Unspecified);

DateTimeOffset dto1 = new DateTimeOffset(dtLocal);
DateTimeOffset dto2 = new DateTimeOffset(dtUtc);
DateTimeOffset dto3 = new DateTimeOffset(dtUnspecified);

DateTimeOffset dto4 = new DateTimeOffset(dtLocal, new TimeSpan(9, 0, 0));
DateTimeOffset dto5 = new DateTimeOffset(dtUtc, new TimeSpan(0, 0, 0));
DateTimeOffset dto6 = new DateTimeOffset(dtUnspecified, new TimeSpan(3, 0, 0));

Console.WriteLine(dto1);
Console.WriteLine(dto2);
Console.WriteLine(dto3);
Console.WriteLine();
Console.WriteLine(dto4);
Console.WriteLine(dto5);
Console.WriteLine(dto6);
2001/02/03 4:05:06 +09:00
2001/02/03 4:05:06 +00:00
2001/02/03 4:05:06 +09:00

2001/02/03 4:05:06 +09:00
2001/02/03 4:05:06 +00:00
2001/02/03 4:05:06 +03:00

既存のDateTime型オブジェクトを使用する場合、時差の指定は省略することができます。
省略した場合、KindプロパティがLocalまたはUnspecifiedの場合はシステムの時差(UTC時刻との差)が使用されます。
Utcの場合は時差はゼロになります。

省略しない場合、KindプロパティがLocalの場合はシステムの時差と同じ値を指定する必要があります。
Utcの場合はゼロを指定する必要があります。
いずれもそれ以外の値を指定するとエラー(ArgumentException例外)が発生します。
Unspecifiedの場合は任意の時差を設定できます。

DateTime型オブジェクトからの暗黙的型変換

DateTime型をDateTimeOffset型に変換する場合、わざわざコンストラクタを呼び出さなくてもそのまま代入することで暗黙的に変換が可能です。
これは内部的に時差(TimeSpan型)の指定を省略したコンストラクタを呼び出しており、変換のルールも上記で説明した通りになります。


DateTime dt = new DateTime(2001, 2, 3, 4, 5, 6, DateTimeKind.Local);
DateTimeOffset dto = dt;
Console.WriteLine(dto);
2001/02/03 4:05:06 +09:00

DateTimeOffset構造体のプロパティ

DateTimeOffset構造体は、Kindプロパティを除いてDateTime構造体と同じプロパティを持っています。
以下にDateTime構造体にはない、DateTimeOffset構造体固有のプロパティを説明します。

プロパティ 説明 データ型
Offset UTC時刻からの時差
-14時間~14時間の範囲の値
TimeSpan
DateTime Offsetプロパティを無視した日時
(Offsetプロパティが表す地域のローカル時刻)
取得されるDateTimeオブジェクトのKindプロパティはUnspecified
DateTime
LocalDateTime 日時情報をシステムのローカル時刻に変換した日時
DateTimeプロパティからOffsetプロパティを減算し(UTC時刻に変換)、さらにシステムローカルの時刻を加算した値
取得されるDateTimeオブジェクトのKindプロパティはLocal
DateTime
UtcDateTime UTC時刻
DateTimeプロパティからOffsetプロパティを減算した値
取得されるDateTimeオブジェクトのKindプロパティはUtc
DateTime
UtcTicks UTC時刻のタイマー刻み数 long
TotalOffsetMinutes UTC時刻からの分単位のオフセット
(.NET8以降)
int

//時差+3時間
DateTimeOffset dto = new DateTimeOffset(
    2001, 2, 3, 4, 5, 6, TimeSpan.FromHours(3));

Console.WriteLine(dto);
Console.WriteLine($"Offset\t\t: {dto.Offset}");
Console.WriteLine($"DateTime\t: {dto.DateTime}");
Console.WriteLine($"LocalDateTime\t: {dto.LocalDateTime}");
Console.WriteLine($"UtcDateTime\t: {dto.UtcDateTime}");
2001/02/03 4:05:06 +03:00
Offset          : 03:00:00
DateTime        : 2001/02/03 4:05:06
LocalDateTime   : 2001/02/03 10:05:06
UtcDateTime     : 2001/02/03 1:05:06