この記事は機械翻訳されたものです。

働くプログラマ

Noda Time (機械翻訳)

Ted Neward

 

Ted Newardこれまで多くの時間を考える時間を過ごした?

非常に初期の私のキャリアの中で、いくつかの異なるコール センターへの展開を終了したシステムを取り組んでいた。 「イベントが発生したとき」の追跡はとくに重要視 (医療 - だった­関連システム、コール センターの看護師の) とので、それについてはあまり考えて、なし我々 忠実イベントの時刻をデータベース行に書いて、それを残しました。 除いて、システムはそれぞれ異なる米国で 4 つの異なるコール センターに展開した場合その後、我々 は発見しました。 タイム ゾーンの時間ログ少し「オフ」タイム ゾーン オフセットを含めると考えられていなかったという事実のおかげですべてだった。

ソフトウェア システムではそのような-それは突然もうしないまでそれはすべて非常に簡単でシンプルです。

私の過去の 2 つの列のテーマに合わせて (私のすべての列で見つけることができます bit.ly/ghMsco)、もう一度 Java コミュニティによって; 仕事から .NET コミュニティの利点 この場合は、Microsoft .NET Framework ポート「野田タイム」と呼ばれるパッケージは Java"ジョダ時間"のプロジェクトは、それ自体は、「日付」Java クラス (ソフトウェアを遡る Java 1.0 時代には恐ろしく破ら個) ための取り替えとして設計されていた。 野田時間の著者ジョン スキート射撃アルゴリズムとジョダ時間の概念に基づいて、.NET ライブラリとしては、地上から構築します。

十分なプリアンブル:"インストール パッケージ NodaTime"を行う (「のだ」と「時間」間にスペース通知なし)、およびいくつかのコードを見てみましょう。

'私' の時間します。

実現する最初の事はすべての原因に関してアインシュタインの理論をその時間を実現するために光の速度に近づいている必要はありません、相対的であります。 19 の場合 (1900 年、ヨーロッパの人々 には) ここでシアトルで、19 は シアトル、しかしそれで私たちのすべては 20 ソルト レイク シティ、21 で私の人々 のため 私の旅行代理店ダラスで 22 ボストンでの私の飲酒の友人を。 私達はすべてそれを得る — は、タイム ゾーンの魔法です。 しかし、私のコンピューターは本当にそれ自体のタイム ゾーン、理解していない — この場合は、時間の正確な同じ瞬間私たちは世界中のすべてのという事実にもかかわらず 19 はそれには、設定されている時間報告します。 他の言葉ではない時間自体が相対的である、それは時間の私たちの表現が相対的であることです。 野田時間では誰もが同意する普遍的なタイムラインの瞬間を意味「グローバル」時間として、この表現を反映します。 私たちが「ローカル」時刻とする — その時に関連付けられたタイム ゾーンとは、— 野田時は、すべての接続されているタイムゾーン (詳細は後述) は、「時間、野田時間「ローカル」考慮ではなくゾーン」の時間を呼び出します。

したがって、たとえば、野田時間「インスタント」グローバル タイムライン上のポイントを 1 月の午前 0 時の原点を意味します。 1、1970 年、世界協定時刻 (UTC)。 (がない魔法の日については、この規約では、「スタート」時代の「ダニ」カウントその日以来、Unix システムのためです、このように良いと参照原点として他を機能することを除いて)だから、これを私たちの現在のインスタント与える (野田時間名前空間が参照されていると仮定すると-「NodaTime を使用して」— もちろん)。

 

var now = SystemClock.Instance.Now;

シアトルの相対時間を取得するには、ZonedDateTime をしたいです。 それ自体"ジョンはシアトル基準として識別されるように、インスタントですが含まれて、タイム ゾーン情報は本質的にであります。 9、2013"(我々 は我々 が夏時間 [DST] かどうかを知る必要があるので重要であること日)。 ZonedDateTime、インスタントと日付を渡して、コンス トラクターを通じて得られた­タイム ゾーン。 我々 は、インスタントが DateTime ゾーン シアトル DST に必要な。 DateTime のゾーンを取得するには、IDateTime zoneProvider 必要があります。 (この間接指定の理由は微妙、ですが、実際に .NET Framework が他のプログラミング プラットフォームから; 別のタイム ゾーンを表すを使用することを行う必要があります。 インターネット名の権限が割り当てられている、または IANA、「アメリカ/太平洋」のような形式を使用します)野田時間を提供しています 2 つの組み込みプロバイダー、IANA バージョンと他の標準の .NET クラス ライブラリ (BCL) バージョン DateTime zoneProviders クラスの静的プロパティを通じての基本します。

var seattleTZ = dtzi["America/Vancouver"];
var dtzi = DateTime zoneProviders.Tzdb;

タイム ゾーン データベース (TZDB) のバージョンは IANA バージョンでそれを選択する問題であるのでシアトルを表すタイム ゾーンを取得する (は、IANA によるとは「アメリカ/太平洋、」、または何かに近い、「アメリカ/バンクーバー」をする場合)。

var seattleNow = new ZonedDateTime(now, seattleTZ);

我々 はこれを印刷する場合、我々 の表現を取得"ローカル。2013/01/09 19:54:16 オフセット。-08 ゾーン:アメリカ/バンクーバー。」「オフセット」部分表現に注意してくださいか? それは重要ですのでおいて何年の日 (と何の下とあなたがいる国とあなたがカレンダーを動作している) に基づく、UTC からのオフセットが変更されます。 シアトルでのそれらのため、DST 得る、または UTC からのオフセットを注意することが重要ですので、ローカルの時計を 1 時間を失うことを意味します。 実際には、野田時間は別からの追跡など、日付を解析するとき"2012年-06-26T20:41:00 + 1:00、"たとえば、我々 はそれも 1 時間早い、だったが、我々 は DST のため、特定のタイム ゾーンかどうかは分かりませんが知っています。

はまだ、時間は簡単ですか?

'私たちは' 時間します。

今私の人生で重要な日付までの時間を知っているしたいと仮定しましょう-私 25 結婚記念日など、1 月の結果を得るでしょう。 16, 2018. (任意の配偶者があなたを言うだろう私は本当に高価な贈り物を購入する前に、どのくらい私が知っている必要があります考えるとそのようなことの追跡やや重要です)。これはやっかいな小さな詳細あなたのための追跡ため野田時間が本当に輝きには、起こっているです。

最初に、私は、原因を構築する必要があります (または、私は時間についてはのローカルな日付; 気にしないなら または場合は、localtime 関数日付について気にしませんでした)。 原因 (またはのローカルな日付または LocalTime) まさにそれが相対的には知っているいないタイムライン上の相対的な位置です-他の言葉では、そのタイム ゾーンを知ることがなく、時間でポイントです。

(タイム ゾーンが知らずして、にもかかわらず、これはまだ便利です情報のビット。 それをこのように考える:あなたと私は一緒に、同じオフィスで仕事をして、我々 が今日この後、私は言うでしょう、「16 で会いましょう」満たすためにしたい場合我々 は同じタイム ゾーンの両方をしているので、追加情報この明確に時間を修飾する必要ありません。)

時間のポイントを知っているので、私はすでにの簡単を構築する気します。

var twentyFifth = new LocalDate(2018, 1, 16);

私はちょうど 2 つの日付のタイム ゾーンに関係なくの違いについて求めていますので、私は私の以前の計算から、ZonedDateTime の原因の一部のローカルな日付部分を必要があります。

var today = seattleNow.LocalDateTime.Date;

しかし、我々 がここで求めている新たな時間単位です:「期間」2 回の間。 (BCL には、この期間です。)野田時間は、別の構成を使用してこれを表現する — 期間 — のすべてが正しく表される単位のようなそれを移動する単位を必要とします。 たとえば、「47」答え「47 日」、「47 時間」または「47 年」など、付属の単位なし役に立たないです。期間の間、いくつかの特定の時間単位 2 LocalDates 間の数を計算する便利なメソッドを提供します。

var period = Period.Between(today, twentyFifth, PeriodUnits.Days);
testContextInstance.WriteLine("Only {0} more days to shop!", period.Days);

これは正確にどのように多くの日、私を指示が、我々 は通常そのような日に大規模な量を (この記事を書いた時は 1,833) をカウントされません。 我々 は我々 は再び野田を管理する時間を求めることができるより管理しやすいチャンクのように「年、月、日」の時間を好みます。 私たちは私たち一緒に、年/月/日、内訳 or PeriodUnits フラグが含まれている期間を与えるために求めることができます。

Period.Between(today, twentyFifth,
  PeriodUnits.Years | PeriodUnits.Months | PeriodUnits.Days)

または、これはかなり一般的な要求であるため、我々 私たちデータマップ フラグの同じ名前を使用して、年/月/日の内訳が含まれている期間を与えるために質問をすることができます。

Period.Between(today, twentyFifth, PeriodUnits.YearMonthDay)

(明らかに、私はまだまだ、私は彼女にあげるもののないアイデアを持っているので、良いです、少しの時間ある。)

テスト時間

この列の頻繁な読者は、新しいライブラリを調査するとき調査テストを記述するよう、この列は例外ではない知っています。 ただし、特に時間上で継続してこの厄介な癖があるので、時間に基づくテストを書くことが可能です。 どのような期待される結果はオフ、渡します各ミリ秒をスローしては難しい、不可能ではない場合に、私たちすることができます主張し、違反を報告予測可能な結果を生成するテストを記述すること。

このため、何かを提供時間 (あなたが知っているよう、時計)、IClock インターフェイスを (今のところ静的プロパティ) 昔は前の瞬間を「今」を SystemClock を含む実装します。 我々 は、たとえば、ため IClock インターフェイスを実装し、戻って (唯一のメンバー必要な IClock インターフェイスでは、実際には) 今のプロパティを定数値を提供する実装を作成した場合、野田時間ライブラリ バシの残りの部分­具体的瞬間はその瞬間に認識を使用して、我々 は本質的に全体のことをテストすることができます、完全にテスト環境を作成しています。、アサート、検証します。 したがって、私の以前のコードを少し変更して調査テスト セットの作成図 1

図 1 の作成調査テスト

[TestClass]
public class UnitTest1
{
  // SystemClock.Instance.Now was at 13578106905161124 when I
  // ran it, so let's mock up a clock that returns that moment
  // in time as "Now"
  public class MockClock : IClock
  {
    public Instant Now
    {
      get { return new Instant(13578106905161124); }
    }
  }
  [TestMethod]
  public void TestMethod1()
  {
    IClock clock = new MockClock(); // was SystemClock.Instance;
    var now = clock.Now;
    Assert.AreEqual(13578106905161124, now.Ticks);
    var dtzi = DateTime zoneProviders.Tzdb;
    var seattleTZ = dtzi["America/Vancouver"];
    Assert.AreEqual("America/Vancouver", seattleTZ.Id);
    var seattleNow = new ZonedDateTime(now, seattleTZ);
    Assert.AreEqual(1, seattleNow.Hour);
    Assert.AreEqual(38, seattleNow.Minute);
    var today = seattleNow.LocalDateTime.Date;
    var twentyFifth = new LocalDate(2018, 1, 16);
    var period = Period.Between(today, twentyFifth, PeriodUnits.Days);
    Assert.AreEqual(1832, period.Days);
  }
}

 

野田時間を使用して、組み込みの .NET 時間型ではなく、時間に関連するコードのすべてを行って、コードを使用して、インスタント「今は」制御可能な知られている何かを取得 iclock」と交換するだけではるかにテストなります。

しかし、待って.

ちょうど何私はここで示したよりも野田時間をより多くです。 たとえば、時間の単位を追加するには比較的簡単です (日, ヶ月ように) 与えられた時間「プラス」を使用して、「マイナス」(が存在も演算子のオーバー ロード、それらを使用するより多くの意味をなさない場合) 方法として具体的には時間に関連するコードをテストするために設計された FakeClock クラスには、プログラムによっては"時間いくつかの独立した方法で進めるためには"など、簡単に経過時間依存コード (などアクティビティなしの期間が経過した後の行動になっている Windows ワークフロー インスタンスなど) をテストすること。

深くより概念的なレベルでは、野田時間はまた微妙に異なる種類の問題ドメイン内の値の間を区別する、型システムのプログラミング言語でどのように役立つかを示しています。離散的かつ相互に関連する種類に時間 (瞬間、現地時間、ローカル日付、ローカル日付と時間とゾーン日付および時刻、たとえば) の種類を分離することで、まさにこのコードを行うまたは作業になっているものについてはっきりと明示的に、プログラマことができます。 たとえば、「誕生日」いくつかのコードで「誕生の日」から区別するために特に重要ながすることができます。人が生まれたとき、1 つ宇宙のタイムラインの瞬間を反映し、他に私たちその瞬間に宇宙のタイムラインを祝う定期的な日付です。 (実質的に言えば、1 つそれに接続されている 1 年を持って、他はしません)。

スキート射撃それをオフに彼は、ライブラリが「終了」は、考慮していないしている、彼は強化し、さらにそれを拡張する計画。 幸いにも、野田時間は、今日では、使用可能な開発者は、それ自身に NuGet 野田時間を借りて、見て、考え出すを開始方法と、問題のドメインで使用する場所。 結局のところ、時間は貴重です。

コーディングを楽しんでください。

Ted Neward Neward のプリンシパルである & アソシエイツ LLC。彼は 100 以上の記事を書いて、執筆し、など、たくさんの書籍は共著の「プロ F c# 2.0"(Wrox、2010年).彼は、F c# MVP と Java を指摘する専門家、です、Java と .NET の両方の会議、世界中で話します。彼はコンサルティングを行い、定期的に指導者 — は彼に到達 ted@tedneward.com 彼のチームと協力して来ることに興味があるなら。彼のブログは blogs.tedneward.com (英語) で、Twitter は twitter.com/tedneward (英語) でフォローすることができます。

この記事のレビュー、技術スタッフのおかげで: ジョン スキート射撃
ジョン スキート ロンドンでグーグルでシニア ソフトウェア エンジニアです。 日彼は Java では、コードしますが、彼の情熱は c# です。 ジョン Twitter 上に到達することができます (@jonskeet) または単にスタック オーバーフローに質問を投稿します。