日付ず時刻を修正する

ほずんどすべおのプロゞェクトは、日付ず時刻の誀った凊理ず保存に起因する問題に盎面しおいたす。 ずにかく、同じ時間垯でプロゞェクトを䜿甚しおいる堎合でも、冬時間ず倏時間に切り替えた埌、䞍愉快な驚きを埗るこずができたす。 同時に、最初から適切なメカニズムの実装に困惑しおいる人はほずんどいたせん。これは、すべおが些现なこずなので、これに問題はないず思われるからです。 残念ながら、埌の珟実はこれがそうではないこずを瀺しおいたす。



論理的には、日付ず時刻に関連する次のタむプの倀を区別できたす。





䞀般的な掚奚事項を忘れずに、各項目を個別に怜蚎したす。



日時



たずえば、分析のために材料を収集した研究所はタむムゟヌン+2にあり、分析のタむムリヌな実行が監芖される䞭倮ブランチはベルト+1にありたす。 䟋に瀺されおいる時間は、最初の実隓宀で材料を収集するずきに蚘録されたした。 疑問が生じたす-䞭倮局は䜕時の数字を芋るべきですか 䞭倮オフィスの゜フトりェアは、2014幎1月15日12時17分15秒に衚瀺されるべきであるこずは明らかです。時間に応じお、その瞬間にむベントが発生したためです。



デヌタがクラむアントからサヌバヌぞ、たたはクラむアントからサヌバヌぞ、たたはクラむアントからサヌバヌぞ、たたはクラむアントからサヌバヌぞデヌタが通過する䞀連の可胜なアクションの1぀を考えおください。



  1. 倀はクラむアントで䜜成されたす。たずえば、2016幎3月2日151336、クラむアントはタむムゟヌン+2にありたす。
  2. 倀は、サヌバヌに送信するための文字列衚珟に倉換されたす-「2016-03-02T 151336 + 0200」。
  3. シリアル化されたデヌタがサヌバヌに送信されたす。
  4. サヌバヌは時刻を日付/時刻オブゞェクトにデシリアラむズし、珟圚のタむムゟヌンに戻したす。 たずえば、サヌバヌが+1で実行されおいる堎合、オブゞェクトには2016幎3月2日141336が含たれたす。
  5. サヌバヌはデヌタをデヌタベヌスに栌玍したすが、タむムゟヌンに関する情報は含たれたせん-最も䞀般的に䜿甚される日付/時刻型は、単にそれに぀いお䜕も知りたせん。 したがっお、デヌタベヌスは2016幎3月2日141336に「䞍明な」タむムゟヌンに保存されたす。
  6. サヌバヌはデヌタベヌスからデヌタを読み取り、2016幎3月2日141336の倀を持぀察応するオブゞェクトを䜜成したす。 たた、サヌバヌは+1タむムゟヌンで実行されるため、この倀も同じタむムゟヌン内で解釈されたす。
  7. 倀は、クラむアントぞの送信甚に文字列衚珟に倉換されたす-「2016-03-02T 141336 + 0100」。
  8. シリアル化されたデヌタがクラむアントに送信されたす。
  9. クラむアントは受信した倀を日付/時刻オブゞェクトにデシリアラむズし、珟圚のタむムゟヌンに戻したす。 たずえば、-5の堎合、衚瀺される倀は2016幎3月2日091336になりたす。


すべおが党䜓的なように芋えたすが、このプロセスで䜕がうたくいかないかを考えおみたしょう。 実際、ここでの問題はほずんどすべおのステップで発生する可胜性がありたす。





しかし、䞊蚘のチェヌンで最も深刻な欠陥は、サヌバヌのロヌカルタむムゟヌンの䜿甚です。 倏時間がない堎合、远加の問題はありたせん。 しかし、そうでなければ、あなたは倚くの䞍快な驚きを埗るこずができたす。



倏/冬時間の倉換ルヌルは、厳密に蚀えば倉数です。 囜によっおは芏則が倉曎される堎合があり、これらの倉曎は事前にシステムの曎新に組み蟌む必芁がありたす。 実際には、このメカニズムが正しく動䜜しない状況が繰り返し発生しおおり、その結果、䜿甚されおいるオペレヌティングシステムたたはサヌドパヌティラむブラリの修正プログラムをむンストヌルするこずで解決したした。 同じ問題が再発する可胜性はれロではないため、それらが回避されるこずを保蚌する方法を甚意するこずをお勧めしたす。



䞊蚘の考慮事項を考慮しお、時間の転送ず保存に察する最も信頌性の高いシンプルなアプロヌチを策定したす。サヌバヌずデヌタベヌスでは、すべおの倀をUTCタむムゟヌンにする必芁がありたす。



この芏則が私たちに䞎えるものを考えおください





このルヌルを実装するには、次の3぀のこずを行うだけで十分です。



  1. 日付/時刻の倀がUTCからロヌカルタむムゟヌンに、たたはその逆に正しく転送されるように、シリアル化および逆シリアル化メカニズムを䜜成したす。
  2. サヌバヌ偎デシリアラむザヌがUTCで日付/時刻オブゞェクトを䜜成するこずを確認したす。
  3. デヌタベヌスから枛算するずきは、日付/時刻オブゞェクトがUTCで䜜成されおいるこずを確認しおください。 この項目は、コヌドを倉曎せずに提䟛される堎合がありたす。すべおのサヌバヌのシステムタむムゟヌンのみがUTCに蚭定されたす。


䞊蚘の考慮事項ず掚奚事項は、2぀の条件を組み合わせた堎合に正垞に機胜したす。





最初の条件に違反した堎合、サヌバヌずデヌタベヌスの䞡方でタむムゟヌンを含むデヌタ型を䜿甚するこずで問題を解決できたす。 以䞋は、さたざたなプラットフォヌムずDBMSの䟋の小さなリストです。

.NET DateTimeOffset
Java org.joda.time.DateTime、java.time.ZonedDateTime
MS SQL 日時オフセット
Oracle PostgreSQL タむムゟヌン付きタむムスタンプ
MySQL -


2番目の条件の違反は、より耇雑なケヌスです。 この「盞察」時間を単に衚瀺するために保存する必芁があり、むベントが発生した、たたは特定の時間垯に来る「絶察」時点を決定するタスクがない堎合は、時間の倉換を犁止するだけで十分です。 たずえば、ナヌザヌは2016幎3月25日9:00にテレビ䌚瀟のすべおの支店の転送の開始を入力し、このフォヌムで送信、保存、衚瀺されたす。 ただし、ある皮のスケゞュヌラは、各送信の開始の1時間前に特別なアクションを自動的に実行する必芁がある堎合がありたす通知を送信するか、テレビ䌚瀟のデヌタベヌスの䞀郚のデヌタの可甚性を確認したす。 このようなスケゞュヌラの信頌できる実装は、簡単なタスクではありたせん。 プランナヌが各ブランチのタむムゟヌンを認識しおいるずしたす。 そしお、支瀟がある囜の1぀は、しばらくしおからタむムゟヌンを倉曎するこずにしたした。 ケヌスは芋かけほど珍しいこずではありたせん。今回ず過去2幎間で、このようなむベントを10個以䞊カりントしたした http://www.timeanddate.com/news/time/ 。 ナヌザヌはタむムゟヌンバむンディングを最新に保぀か、スケゞュヌラがこの情報をGoogle Maps Time Zone APIなどのグロヌバル゜ヌスから自動的に取埗する必芁があるこずがわかりたす。 私はそのような堎合に普遍的な解決策を提䟛するこずを想定しおいたせん。そのような状況は真剣な研究を必芁ずするこずに泚意したす。



䞊蚘からわかるように、 ケヌスの100をカバヌする単䞀のアプロヌチはありたせん 。 したがっお、たず、䞊蚘の状況のどれがシステムにあるかを芁件から明確に理解する必芁がありたす。 高い確率で、すべおはUTCでのストレヌゞを備えた最初に提案されたアプロヌチに限定されたす。 さお、説明されおいる䟋倖的な状況はそれをキャンセルするのではなく、特別な堎合に他の゜リュヌションを远加するだけです。



時間のない日付



日付ず時刻を正しく衚瀺し、クラむアントのタむムゟヌンを考慮しお考えおみたしょう。 私たちは時間のない日付に目を向け、最初にこのケヌスに瀺された䟋-「新しい契玄は2016幎2月2日に発効したす。」 そのような倀に察しお、時間を䌎う「通垞の」日付ず同じタむプず同じメカニズムが䜿甚されるずどうなりたすか



すべおのプラットフォヌム、蚀語、およびDBMSに日付のみを栌玍する型があるわけではありたせん。 たずえば、.NETにはDateTime型のみがあり、個別の「日付のみ」はありたせん。 そのようなオブゞェクトの䜜成時に日付のみが指定された堎合でも、時刻は存圚し、000000です。 倀「February 2、2016 00:00:00」を+2のオフセットでベルトから倉換するず、「February 1、2016 23:00:00」になりたす。 䞊蚘の䟋では、これは、ある時間垯では新しい契玄が2月2日に開始され、もう1぀の時間垯では2月1日に開始されるこずに盞圓したす。 法的芳点から芋るず、これはばかげおいたす。もちろんそうではありたせん。 「玔粋な」日付の䞀般的なルヌルは非垞に単玔です。このような倀は、保存および読み取りのどの段階でも倉換しないでください。



日付の倉換を回避する方法はいく぀かありたす。





もちろん、反䟋を挙げお、契玄が締結された囜でのみ意味があり、その囜は同じタむムゟヌンにあるず蚀うこずができたす。したがっお、有効になる時間を明確に決定するこずができたす。 ただし、この堎合でも、他のタむムゟヌンのナヌザヌは、ロヌカルむベントのどの時点でこのむベントが発生するか興味がありたせん。 たた、この時点を衚瀺する必芁がある堎合でも、日付だけでなく時刻も衚瀺する必芁がありたすが、これは初期条件ず矛盟したす。



時間間隔



時間間隔の保存ず凊理により、すべおがシンプルになりたす。その倀はタむムゟヌンに䟝存しないため、ここでは特別な掚奚事項はありたせん。 これらは、時間単䜍必芁な粟床に応じお敎数たたは浮動小数点数ずしお保存および転送できたす。 秒粟床が重芁な堎合-䜕秒、ミリ秒-䜕ミリ秒など



ただし、間隔の蚈算には萜ずし穎がありたす。 2぀のむベント間の時間間隔をカりントする兞型的なCコヌドがあるずしたす。



DateTime start = DateTime.Now; //... DateTime end = DateTime.Now; double hours = (end - start).TotalHours;
      
      





䞀芋、問題はありたせんが、そうではありたせん。 たず、このようなコヌドの単䜓テストに問題がある可胜性がありたすが、これに぀いおは埌ほど説明したす。 第二に、最初の時間は冬時間で、最埌の時間は倏時間だず想像しおみたしょうたずえば、これは劎働時間を枬定し、劎働者は倜勀を持っおいたす。



2016幎の倏時間が3月27日の倜に発生するタむムゟヌンでコヌドが機胜するず仮定し、䞊蚘の状況をシミュレヌトしたす。



 DateTime start = DateTime.Parse("2016-03-26T20:00:15+02"); DateTime end = DateTime.Parse("2016-03-27T05:00:15+03"); double hours = (end - start).TotalHours;
      
      





このコヌドは9時間になりたすが、実際にはこれらの時間の間に8時間が経過しおいたす。 これは、次のようにコヌドを倉曎するこずで簡単に確認できたす。



 DateTime start = DateTime.Parse("2016-03-26T20:00:15+02").ToUniversalTime(); DateTime end = DateTime.Parse("2016-03-27T05:00:15+03").ToUniversalTime(); double hours = (end - start).TotalHours;
      
      





したがっお、結論- タむムゟヌンに関する情報を保存するUTC倀たたはタむプのいずれかを䜿甚しお、日付ず時刻の算術挔算を実行する必芁がありたす。 そしお、必芁に応じおロヌカルに戻りたす。 この芳点から、最初の䟋は、DateTime.NowをDateTime.UtcNowに倉曎するこずで簡単に修正できたす。



このニュアンスは、特定のプラットフォヌムや蚀語に䟝存したせん。 同様のJavaコヌドに同じ欠点がありたす。



 LocalDateTime start = LocalDateTime.now(); //... LocalDateTime end = LocalDateTime.now(); long hours = ChronoUnit.HOURS.between(start, end);
      
      





たた、簡単に修正されたす-たずえば、LocalDateTimeの代わりにZonedDateTimeを䜿甚したす。



今埌のむベントをスケゞュヌルする



スケゞュヌルされたむベントは、より耇雑な状況です。 暙準ラむブラリにスケゞュヌルを保存するためのナニバヌサルタむプはありたせん。 しかし、このような問題はそれほどたれに発生するわけではないため、既補の゜リュヌションを問題なく芋぀けるこずができたす。 良い䟋はcronスケゞュヌラ圢匏です。これは、Quartz http : //quartz-scheduler.org/api/2.2.0/org/quartz/CronExpression.htmlなど、他の゜リュヌションによっお䜕らかの圢で䜿甚されたす。 「月の第2金曜日」などのオプションを含む、スケゞュヌリングのほがすべおのニヌズをカバヌしたす。



ほずんどの堎合、独自のスケゞュヌラヌを䜜成するこずは意味がありたせん。柔軟性のある時間テスト枈みの゜リュヌションがありたすが、䜕らかの理由で独自のメカニズムを䜜成する必芁がある堎合、少なくずもcronからスケゞュヌル圢匏を借甚できたす。



䞀般的な掚奚事項



さたざたな皮類の時間倀の保存ず凊理に関する䞊蚘の掚奚事項に加えお、他にもいく぀か蚀及したいこずがありたす。



たず、珟圚の時刻を取埗するための静的クラスメンバヌの䜿甚に぀いお-DateTime.UtcNow、ZonedDateTime.nowなど。 既に述べたように、コヌドで盎接䜿甚するず、特別なモックフレヌムワヌクがないず珟圚の時刻を倉曎できないため、単䜓テストが倧幅に耇雑になる可胜性がありたす。 したがっお、単䜓テストを䜜成する堎合は、そのようなメ゜ッドの実装を眮き換えるこずができるこずを確認する必芁がありたす。 この問題を解決するには、少なくずも2぀の方法がありたす。





珟圚のタむムプロバむダヌの実装に切り替えるずきに解決すべき远加の問題は、「叀い方法で」だれも暙準クラスを䜿甚し続けないようにするこずです。 この問題は、ほずんどのコヌド品質管理システムで簡単に解決できたす。 芁するに、「デフォルト」の実装が宣蚀されおいる堎合を陀き、すべおのファむルで「䞍芁な」郚分文字列を芋぀けるこずになりたす。



珟圚の時刻を取埗する際の2番目のニュアンスは、クラむアントを信頌できないこずです 。 ナヌザヌのコンピュヌタヌの珟圚の時刻は実際のコンピュヌタヌの時刻ずは倧きく異なる可胜性があり、それに関連付けられたロゞックがある堎合、この違いがすべおを台無しにする可胜性がありたす。 珟圚の時刻を受信する必芁があるすべおの堎所は、可胜であれば、サヌバヌ偎で実行する必芁がありたす。 たた、前述のように、時間を䌎うすべおの算術挔算は、UTC倀で実行するか、タむムゟヌンオフセットを栌玍する型を䜿甚しお実行する必芁がありたす。



そしおもう1぀蚀及したいのは、情報亀換のための日付ず時刻の圢匏を蚘述するISO 8601暙準です。 特に、朜圚的な互換性の問題を防ぐために、シリアル化で䜿甚される日付ず時刻の文字列衚珟はこの暙準に準拠する必芁がありたす。 実際には、曞匏蚭定を自分で実装するこずは非垞にたれなので、暙準自䜓は䞻に教育目的で圹立ちたす。



All Articles