トップC# > 日付時刻に関する処理

日付時刻に関する処理

現在日時の表示[1]

現在の日時はDateTime 構造体の Now プロパティから得る。 世界協定時刻 (UTC) で取得したい場合は、UtcNow プロパティから取得する。

using System;

class DateTime01 {
    static void Main() {
        // 現在の日付と時刻を取得する
        DateTime dtNow = DateTime.Now;
        Console.WriteLine(dtNow.ToString());

        // 現在の日付と時刻を世界協定時刻 (UTC) で取得する
        DateTime dtUtcNow = DateTime.UtcNow;
        Console.WriteLine(dtUtcNow.ToString());
    }
}
c:\mh\mcc>datetime01
2013/06/01 13:24:04
2013/06/01 4:24:04

DateTime構造体の年、月、日、時、分、秒、ミリ秒を表すプロパティはそれぞれ Year, Month, Day(1~31), Hour(0~23), Minute, Second, Millisecond である。

曜日は DayOfWeekプロパティ(int型にキャストすると日~土が 0~6 となる。)

年間積算日は DayOfYearプロパティ (int型)であり、1~366 である。

TimeOfDayプロパティ(TimeSpan型)は1日の端数の時間を表す。


DateTime dt を UTCに変換するには

    DateTime dtUTC = System.TimeZoneInfo.ConvertTimeToUtc(dt);  
とする。

文字列をDateTimeの値に変換する

using System;

class DateTime02 {
    static void Main() {
        // カルチャ情報を設定する
        System.Globalization.CultureInfo cFormat = 
            new System.Globalization.CultureInfo("ja-JP", false);
        // 文字列から DateTime の値に変換する
        DateTime dt = DateTime.ParseExact("2013/06/01 13:52:12", "G", cFormat);
        Console.WriteLine(dt.ToString());
    }
}

日付だけから DateTime型を得るには DateTime.Parse("2013/6/1"), DateTime.Parse("2013-6-1") などとすればよい。

c:\mh\mcc>datetime02
2013/06/01 13:52:12

独自の書式の日時、例えば、"20130601" から DateTime型を得るには

DateTime.ParseExact("20130601", "yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture) 
とする。

高い精度で時間を計測する[2]

プログラムの実行時間など短い時間を精度よく計測したいときは StopWatch クラスを使う。 TimeSpan値がElapsedプロパティで返される。 下のプログラムで sw.Elapsed.TotalSeconds とすれば、秒単位での経過時間(double型実数)が得られる。

// stopwatch01.cs
using System;

class StopWatch01 {
    static void Main() {
        System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
        fib(40);
        sw.Stop();
        Console.WriteLine(sw.Elapsed);
    }

    static int fib(int n) {
        if (n <= 2) return 1;
        return fib(n-1) + fib(n-2);
    }
}
フィボナッチ再帰関数 fib の引数の値が 40 のときの実行時間は下に示すように 2.79… となった。この値は実行毎にかなり変動する。
c:\mh\mcc>stopwatch01
00:00:02.7926426

因みに、C言語(MS VCでコンパイル)の場合、実行時間は 2.246秒 となった。 C# の方が遅いが、その差は 2割程度である。

連続的に日付文字列を生成する

例として、2001年1月1日から今日までの日付文字列データを生成するプログラムを下に示す。

using System;

class Days {
    static void Main() {
        TimeSpan tSpan = new TimeSpan(1,0,0,0); // 1日
        DateTime dt = new DateTime(2001,1,1);
        for ( ; dt < DateTime.Now; dt += tSpan) {
            Console.WriteLine(dt.ToShortDateString());
        }
    }
}
/* 実行結果
2001/01/01
2001/01/02
2001/01/03
[中略]
2013/10/23
2013/10/24
*/

1日進めるには AddDaysメソッドを使う方が簡単なことが分かった[2013.11.30]。

        DateTime dt = new DateTime(2001,1,1);
        for ( ; dt < DateTime.Now; dt = dt.AddDays(1)) {
            Console.WriteLine(dt.ToShortDateString());
        }

日付を n か月先に進めるには dt = dt.AddMonth(n) とする。n の値を負数にすると、日付が過去になる。 3月31日を1か月進めた場合には、4月30日となる。すなわち該当する日付がない時はその月の末日になる。 m 年先に進めるには dt = dt.AddYears(m) とする。

従って、去年の今日(の現在日時)は DataTime.Now.AddYears(-1) となる。

UNIXの通算ミリ秒とDateTimeの変換

UNIXでは時刻を 1970.1.1 を起点とした通算秒で表す。 この通算秒を DataTimeの値に変えたり、あるいはこの逆を行うには次のようにすればよい。

uint ut; // UNIX 通算秒
DateTime dt = new DateTime(1970, 1, 1).AddSeconds((double)ut);
DateTime dt; // Ticksは100ナノ秒単位 
uint ut = (uint)((dt.Ticks - new DateTime(1970,1,1).Ticks)/10000000);

タイム ゾーン間での時刻の変換

ネットであるページを見ると時刻が 8:15AM CST となっていた。これを JST に変換してみよう。

色んな方法が考えられるが、一つの方法を下に示す。 日時の表示形式(CultureInfo)は日本流としている。時刻の表示(DateTimeStyles)は日本時間(ローカル)とする。 CST(米国Central Standard Time)のUSTに対する時差は -6時間である。

using System;
using System.Globalization;

class Program {
    static void Main() {
        CultureInfo culture = CultureInfo.CreateSpecificCulture("ja-JP");
        DateTimeStyles styles = DateTimeStyles.AssumeLocal;
        DateTime dt = DateTime.Parse("2013/12/13 8:15AM-6:00", culture, styles);
        Console.WriteLine(dt.ToString());
    }
}

実行結果は次の通りである。

2013/12/13 23:15:00

サマータイムへの対応を自動的に行ってくれる方法があるかも知れないし、ないかも知れない。 必要が生じたときに検討する。

日時に関する計算

任意の日時間の経過時間は DateTime の引き算により求めることができる。 例えば、2001年1月1日から現在までの経過時間は次式で得られる。

   TimeSpan ts = DateTime.Now - new DataTime(2001,1,1);

経過日数は ts.Days (System.Int32型)で得られる。時分秒などの端数を含めた日数は ts.TotalDays(double型)で表される。秒単位では ts.TotalSeconds(double型)で表される。

ある日時 dateTime からある時間 timeSpan だけ経過した日時は足し算、過去の日時は引き算で得られる。 例えば、現在より10日前の日時は次式で得られる。 このときの TimeSpanのコンストラクタの引数は順に、日数、時間、分、秒、ミリ秒である。

   DateTime datetime = DateTime.Now - new TimeSpan(10,0,0,0,0);

書式を指定して日時を文字列に変換する

例えば 2014.2.16 のように表示するには次のようにする。

Console.WriteLine(dt.ToString("yyyy.M.d"));

20140206 のように、月日をかならず2桁で表示するには、次のようにする。

Console.WriteLine(dt.ToString("yyyyMMdd"));

曜日の完全名の書式は dddd、省略名は ddd である。"2008/1/7 月曜日" のように表示するには、次のようにする。

Console.WriteLine(dt.ToString("yyyy/M/d dddd"));

24時間表記の時分秒は "HHmmss" とする。例えば午後3時4分56秒は "150456" となる。

指定した時間だけ停止する

指定した時間だけ現在のスレッドを停止するには、Thread.Sleepメソッドを使う。 Windowsフォームアプリケーションでメインスレッドを停止すると、その間フリーズ状態のようになる。

System.Threading.Thread.Sleep(1000);	// 1000ミリ秒停止する。

日付のみを取り出す

日付だけを比較したい場合には、Dateプロパティによって日付だけを取り出す。

例えば 2014年6月12日の任意の時刻に次のプログラム

Console.WriteLine(DateTime.Now.Date.ToString());
を実行すると、結果は次のようになる。すなわち、Dateプロパティの時刻は 0時0分0秒である。
2014/06/12 0:00:00

OSM(Open Street Map)のタイムスタンプの操作

OSMの書式は 2021-08-05T03:06:48Z のようになっている。これは ISO8601拡張形式に当たるものであろう。 末尾の Z はUTC を表す。日本時間の場合、Z の所が +9:00 となる。 地図システムおよびレンダリングの内部データとしては、文字列形式ではなく、整数データ化したい。

PostgreSQL で整数化できれば今回の場合、その方が楽である。 次のようにすれば UNIX Time に変換できる。

select extract(epoch from cast('2021-08-05T03:06:48Z' as timestamp)) ;
または
select extract(epoch from timestamp '2021-08-05T03:06:48Z');

hstore型の tags から取り出すときは次のようにする。timestamp tags->'osm_timestamp' ではエラーとなった。

select extract(epoch from cast(tags->'osm_timestamp' as timestamp))
from japan_point limit 10;

参考文献

[1] 現在の日付と時刻を取得する
[2] より高い精度で時間を計測する
[3] [C#] UNIX 通算秒を DateTime に直す
[4] タイム ゾーン間での時刻の変換[msdn]
[5] PostgreSQLで特定期間の日数/時間数などを数える