マシンでタイムゾーンが変更されたときのケースをテストするためのユニットテストを作成しようとしています。
テストでは、ローカルタイムゾーンなしでDateTimeオブジェクトを作成できる必要があります。これにより、テストを実行しているユーザーが、場所に関係なく作成できるようになります。
DateTimeコンストラクターから確認できることから、TimeZoneをローカルタイムゾーン、UTCタイムゾーン、または指定なしに設定できます。
PSTなどの特定のタイムゾーンでDateTimeを作成するにはどうすればよいですか?
ジョンの答え は TimeZone について語っていますが、代わりに TimeZoneInfo を使用することをお勧めします。
個人的には、可能な限りUTCで物事を維持するのが好きです(少なくとも過去については、 futureにUTCを保存すると潜在的な問題があります ) 、したがって、私はこのような構造を提案したいと思います:
public struct DateTimeWithZone
{
private readonly DateTime utcDateTime;
private readonly TimeZoneInfo timeZone;
public DateTimeWithZone(DateTime dateTime, TimeZoneInfo timeZone)
{
var dateTimeUnspec = DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified);
utcDateTime = TimeZoneInfo.ConvertTimeToUtc(dateTimeUnspec, timeZone);
this.timeZone = timeZone;
}
public DateTime UniversalTime { get { return utcDateTime; } }
public TimeZoneInfo TimeZone { get { return timeZone; } }
public DateTime LocalTime
{
get
{
return TimeZoneInfo.ConvertTime(utcDateTime, timeZone);
}
}
}
わかりやすくするために、「TimeZone」の名前を「TimeZoneInfo」に変更することをお勧めします-短い名前を自分で使います。
DateTimeOffset構造は、まさにこのタイプの使用のために作成されました。
参照: http://msdn.Microsoft.com/en-us/library/system.datetimeoffset.aspx
特定のタイムゾーンでDateTimeOffsetオブジェクトを作成する例を次に示します。
DateTimeOffset do1 = new DateTimeOffset(2008, 8, 22, 1, 0, 0, new TimeSpan(-5, 0, 0));
ここの他の回答は便利ですが、特に太平洋へのアクセス方法についてはカバーしていません-ここに行きます:
public static DateTime GmtToPacific(DateTime dateTime)
{
return TimeZoneInfo.ConvertTimeFromUtc(dateTime,
TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"));
}
奇妙なことに、「太平洋標準時」は通常「太平洋夏時間」とは異なるものを意味しますが、この場合は一般に太平洋時間を指します。実際、FindSystemTimeZoneById
を使用してフェッチする場合、使用可能なプロパティの1つは、そのタイムゾーンが現在夏時間かどうかを示すブールです。
この一般的な例を、ユーザーが要求している場所などに基づいて異なるTimeZonesで必要なDateTimeを処理するためにまとめたライブラリで見ることができます。
https://github.com/b9chris/TimeZoneInfoLib.Net
時刻のリストはWindowsレジストリから取得されるため、これはWindowsの外部では機能しません(LinuxのMonoなど):HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\
その下にキー(レジストリエディターのフォルダーアイコン)があります。これらのキーの名前は、FindSystemTimeZoneById
に渡すものです。 Linuxでは、タイムゾーン定義の個別のLinux標準セットを使用する必要がありますが、これについては十分に検討していません。
私は Jon Skeet answer 拡張メソッドを使用したWeb用に少し変更しました。また、Azureでもチャームのように機能します。
public static class DateTimeWithZone
{
private static readonly TimeZoneInfo timeZone;
static DateTimeWithZone()
{
//I added web.config <add key="CurrentTimeZoneId" value="Central Europe Standard Time" />
//You can add value directly into function.
timeZone = TimeZoneInfo.FindSystemTimeZoneById(ConfigurationManager.AppSettings["CurrentTimeZoneId"]);
}
public static DateTime LocalTime(this DateTime t)
{
return TimeZoneInfo.ConvertTime(t, timeZone);
}
}
Jon Skeetの答えが好きですが、一つだけ付け加えたいと思います。ジョンが常にローカルタイムゾーンで渡されることを期待していたかどうかはわかりません。しかし、私はそれがローカル以外の何かである場合にそれを使用したいと思います。
私はデータベースから値を読んでおり、そのデータベースがどのタイムゾーンにあるかを知っています。そのため、ctorでは、データベースのタイムゾーンを渡します。しかし、その後、現地時間で値が欲しいです。 JonのLocalTimeは、ローカルタイムゾーンの日付に変換された元の日付を返しません。元のタイムゾーンに変換された日付を返します(あなたがctorに渡したものは何でも)。
これらのプロパティ名はそれをクリアすると思う...
public DateTime TimeInOriginalZone { get { return TimeZoneInfo.ConvertTime(utcDateTime, timeZone); } }
public DateTime TimeInLocalZone { get { return TimeZoneInfo.ConvertTime(utcDateTime, TimeZoneInfo.Local); } }
public DateTime TimeInSpecificZone(TimeZoneInfo tz)
{
return TimeZoneInfo.ConvertTime(utcDateTime, tz);
}
そのためのカスタムオブジェクトを作成する必要があります。カスタムオブジェクトには2つの値が含まれます。
CLRが提供するデータ型が既にあるかどうかはわかりませんが、少なくともTimeZoneコンポーネントは既に利用可能です。