「決しお蚀わない」たたはタむムゟヌンを正しく操䜜する

この蚘事では、プログラマヌがタむムゟヌンで䜜業するのを埅぀問題に぀いお説明したす。 理論的には、すべおが玠晎らしく、シンプルで明確なように芋えたすが、人生は耇雑なものであり、実際には、時には完党に予期しない状況が発生したす。



TL; DRタむムゟヌンの操䜜は痛みず屈蟱です。 タむムゟヌンを䜿甚しないでください



そのため、 呚りの人 は 、ナヌザヌから時間を取埗したら、すぐにUTCに転送する必芁があり、時間をUTCで凊理するだけで、時間を厳密にUTCで保存する必芁があるこずを䌝えたす。 アドバむスは䞀芋合理的であり、それに埓うこずで生掻が楜になりたす...プログラムに日付の耇雑な䜜業が含たれおいない限り。 サむトのナヌザヌ登録の日付ず時刻をデヌタベヌスに蚘録したすか オンラむンストアにメッセヌゞの送信時間たたは泚文䜜成日を保存したすか 日時を瀺すメッセヌゞをログに衚瀺したすか UTCを䜿甚するず、すべお正垞になりたす。この蚘事をさらに読むこずはできたせん。 珟圚の時刻はすべおUTCに完党に倉換でき、問題を忘れるこずができたす。 しかし、将来、時間ずずもに働きたいずしたらどうでしょうか たたは過去に たずえば、カレンダヌサヌビス、たたはメッセヌゞの遅延送信サヌビスを䜜成する堎合はどうでしょうか



UTCは䞇胜薬ではありたせん

䟋で説明したす。 同じ保留䞭のメッセヌゞサヌビスを䜜成したずしたす。 私たちのサむトを蚪れたナヌザヌは、メヌルたたはSMSでい぀でももちろん、将来的に自分のリマむンダヌを䜜成できたす。 私たちのサむトは非垞にシンプルです日付、時刻を蚭定し、リマむンダヌテキストず通信チャネル電子メヌルアドレスたたは電話番号を入力し、ナヌザヌから受信したデヌタをデヌタベヌスに入れおから、定期的に遞択しおメッセヌゞを送信したす。 感謝する人々のすべお、利益ず敬意



いいえ、すべおではありたせん。 すべおの堎所を垞にUTCで保存するずいうアドバむスに埓っお、ナヌザヌから受け取った日付ず時刻をUTCに倉換し、デヌタベヌスに栌玍したした。 2014幎3月2日にモスクワのナヌザヌがサむトにアクセスし、2014幎11月3日の午前9時にリマむンダヌを䜜成できるようにしたす。 したがっお、2014幎3月2日の2014幎11月3日のペヌロッパ/モスクワタむムゟヌンのオフセットは「UTC + 4」であったため、デヌタベヌスに倀「2014-11-03 05:00:00」を蚭定したした。



私が埗おいるものを参照しおください



はい、2014幎7月21日、ロシア連邊䞋院は倏時間を廃止する法案を採択したした。 この法埋によるず、2014幎10月26日から、ペヌロッパ/モスクワのタむムゟヌンぞの移行は、「UTC + 4」ではなく「UTC + 3」になりたした倏時間も取り消されたしたが、珟圚はそうではありたせん。 したがっお、ナヌザヌに11月3日午前5時にUTCに通知を送信するず、ナヌザヌはモスクワの午前8時にその通知を受け取りたす。



結論は簡単です。時間をUTCで保存できたすが、珟圚および最近の過去のむベント、぀たり、タむムゟヌンが倉曎されない日付のむベントのみを保存できたす。 将来の日付にUTCで時間を保存するのは危険です。なぜなら、どの囜の政府が他の法埋を採甚し、10幎、5幎、さらには1幎でタむムゟヌンに䜕が起こるかわからないからです。



䞀方、ナヌザヌのロヌカル時間ずナヌザヌのタむムゟヌンをデヌタベヌスに保存するず、そのようなデヌタを操䜜するこずは事実䞊䞍可胜になりたす。 通知サヌビスの䟋に戻りたす通知によっお䜜成された2人のナヌザヌ。 モスクワの最初のナヌザヌは、2014幎12月15日15:00にSMSを送信するように芁求したしたデヌタベヌスにロヌカル時間「2014-12-15 15:00:00」ずタむムゟヌン「ペヌロッパ/モスクワ」を曞き蟌みたす。 ニュヌペヌクの2番目のナヌザヌは、2015幎12月15日午埌7時に電子メヌルを送信するように芁求したしたデヌタベヌスに圌の珟地時間「2014-12-15 19:00:00」ずタむムゟヌン「America / New_York」を蚘述したす  これたでのずころ、ナヌザヌが通知を受け取りたい珟地時間を蚘録しおおり、これらの囜の政府がこれらのタむムゟヌンオフセット、倏時間、䜕でも。



送信するデヌタベヌスから通知を遞択するスクリプトを䜜成するず、問題が始たりたす。 すべおの日付がUTCで蚘録されおいる堎合、すべおが単玔になりたす-送信するメッセヌゞを毎分遞択したす。

SELECT * FROM reminders WHERE remind_time < NOW();
      
      





「SELECT NOW;」は、UTCで時刻を返したす。 しかし、ナヌザヌの珟地時間ずナヌザヌのタむムゟヌンをデヌタベヌスに蚘録したした。どうすればよいでしょうか。 苊しむ:-)結局のずころ、UTCによる「NOW」はモスクワでは「+3」時間メッセヌゞはすでに遅れおいたす、ニュヌペヌクでは「-5」時間メッセヌゞを送信するには早すぎたすです。



いいえ、もちろん、デヌタベヌスから送信する通知を遞択する倚くの方法を考えるこずができたすが、倚かれ少なかれ負荷のかかったサヌビスでそれらすべおがパフォヌマンスの問題に぀ながりたす。



オプションは䜕ですか それらの倚くがありたすが、デヌタベヌスに3぀の倀を保存するために、倚かれ少なかれ受け入れられるオプションが1぀しかありたせんUTCの時間このフィヌルドによるサンプリング甚、ナヌザヌの珟地時間、およびタむムゟヌンタむムゟヌン。 はい、冗長なデヌタを保存したすが、デヌタの非正芏化に頌らない単䞀のロヌドされたサヌビスは知りたせん。 珟実の䞖界では、これは正垞です。 埗られる利点は䜕ですか タむムゟヌンが倉曎された堎合、特別なスクリプトを䜿甚しお倉曎されたタむムゟヌンの゚ントリを調べ、タむムゟヌンの曎新の結果ずしお倉曎された堎合はUTCで時刻を曎新できたす。 私の謙虚な意芋では、これは良い劥協案です。



思ったよりもさらに悪い

すべおのように、ハァッ いいえ、始めたばかりです:-)政府はタむムゟヌンの構成を倉曎できるだけでなく、新しいタむムゟヌンを远加しお叀いタむムゟヌンを砎棄するこずもできたす。 そのため、たずえば、ロシアの郜垂チタの居䜏者およびそれだけではなく、珟圚ではないに぀いおは、2014幎10月26日に、「タむムゟヌンが存圚しない前に」新しいタむムゟヌン「アゞア/チタ」が導入されたしたアゞア/ダクヌツク」。 前のタむムゟヌン「アゞア/ダクヌツク」のUTCずの差は「+0900」であり、新しいタむムゟヌン「アゞア/チタ」ではこの差は「+0800」です。 問題は、デヌタベヌスにナヌザヌの時間ずタむムゟヌンのみを保存し、地理的な堎所は保存しないこずです。 たた、「アゞア/ダクヌツク」タむムゟヌンの゚ントリの堎合、ナヌザヌが知倚かダクヌツクのどちらであるかを知るこずはできず、メッセヌゞがナヌザヌに送信された時刻を確実に刀断するこずはできたせん。 チェックしおチェックメむト 友人を苊しめるこずを忘れないでください。



ナヌザヌの地理的䜍眮を確認する機䌚があり、ナヌザヌが次にサむトにアクセスしたずきに、ナヌザヌがタむムゟヌンが倉曎された地域䞊蚘の堎合はChitaにいるず刀断した堎合、ナヌザヌに正しいタむムゟヌンを尋ねるこずができたす。 たた、すべおのむベントのタむムゟヌンを曎新するこず各むベントのUTCでの時間の再蚈算を提案するこずもできたすが、この蚘事の範囲を超える萜ずし穎ずニュアンスもここで発生する可胜性がありたす。 ちなみに、䞀郚にはこの理由で、 mail.ruカレンダヌ蚭定で、他のサヌビスが行うように、タむムゟヌンではなく地理的な堎所郜垂を遞択するようにナヌザヌに求めたす:-)それでも、時々問題があるず正盎に蚀いたす。



過去の時間を保存するこずも簡単ではありたせん。 この過去が比范的最近の堎合たずえば、21䞖玀に぀いお話しおいる堎合、UTCでの時間の保存に問題はないはずですもちろん、だれも保蚌したせん。 20䞖玀たたはああ、ホラヌより叀い時代に぀いお話しおいる堎合、問題は保蚌されたす。 そもそも、前䞖玀の歎史の倚くの期間においお、時蚈の翻蚳に関する情報は今日に至るたで絶えず倉化しおいたす。 そのため、たずえば、2014幎8月30日付のタむムゟヌンデヌタベヌスtzdataバヌゞョン2014gの曎新では、゜連の倚くのタむムゟヌンで、1926幎たでの日付に察しお数秒たたは数分倉曎が加えられたした。 誰かが矛盟に気づき、これに぀いおtzdataコンパむラヌに通知したした。 たたは、近い時期の別の䟋を次に瀺したす。2014幎3月9日の曎新tzdataバヌゞョン2014aでは、りクラむナのモスクワ時間から東ペヌロッパ時間ぞの移行日に関する情報が倉曎されたした。この移行は1992幎1月1日に発生したせんでしたが、 1990幎7月1日



タむムゟヌンのデヌタベヌスは幎に数回曎新され、新しいタむムゟヌンが䞖界䞭に衚瀺され、既存のタむムゟヌンのルヌルが倉曎され、過去の時間に関する情報が曎新され、䞀郚の倉曎が垞に発生するため、それらを垞に考慮する必芁がありたす。



それでは、どのように時間を正しく保぀のですか

では、どのようにしおデヌタベヌスに時間を正しく保存するこずができたすか もちろん、これを行わない方が良いですが、本圓に必芁な堎合は、個人的な掚奚事項がありたす批刀や提案を聞いおうれしいです

  1. 発生したむベントの時刻、特定のアクションの埌の珟圚時刻を保存する必芁がある堎合は、UTCで保存したす。 これらは、ログ゚ントリ、ナヌザヌ登録の時間、手玙の泚文たたは送信です。
  2. 時刻がナヌザヌたたはナヌザヌのタむムゟヌンに関連付けられおいない堎合は、UTCで保存したす。 これは、たずえば、次の日食の時間かもしれたせん。
  3. 過去たたは未来の時間を保存する必芁がある堎合は、ナヌザヌの珟地時間を保存し、タむムゟヌンを近くに保存したす。 そしおさらに良いので、確かに、ナヌザヌの地理的な䜍眮を保持したす。 この時間のサンプルを䜜成する必芁がある堎合は、時間を近くのUTCで保存し、タむムゟヌン情報を倉曎するずきにこの時間を曎新したす。
  4. 特定の地理的䜍眮の任意の日付の時刻を正確に知る必芁がある堎合たずえば、倩文蚈算の堎合-ナヌザヌのタむムゟヌンではなく、ナヌザヌの正確な座暙を保存したす。 ただし、そのようなタスクに盎面しおいる堎合は、正しい方法をすでに知っおいたす。


最初のオプションは、プログラムの99の可胜なナヌスケヌスをカバヌしおおり、おそらく、これで十分です。 ただし、アクションの1぀たたは別のバヌゞョンの遞択を明確に理解し、認識する必芁がありたす。



時間ずずもに働く

時間の保存、䞊べ替え、敎理。 ただし、「垞にUTCの時間で動䜜する」ずいうアドバむスを聞くこずができたす。 ナヌザヌから時間を受け取るずすぐに、それをすぐにUTCに転送し、UTCの時間でのみ動䜜する必芁があるこずが理解されおいたす。 論理的に聞こえたすか



違いたす。 少なくずもすべおの堎合ではなく、ここに具䜓的な䟋を瀺したす。



遅延メッセヌゞのサヌビスを䜿甚しお䟋に戻りたしょう。 すべおは順調で、サヌビスは開発䞭です。ナヌザヌは満足しおいたすが、繰り返し通知の機胜を远加するよう求めおいたす。 たた、繰り返しは単玔「毎日」、「隔日」、「毎月」だけでなく、非垞に耇雑です「毎週火曜日の週」、「毎月最埌の金曜日の毎月」など。 これらの繰り返しのために自転車を曞かないために、既補の゜リュヌションを研究したす。 「定期的なむベント」などがありたす。 繰り返しの芏則を蚘述するための特別な圢匏がありたす。もちろん、すべおの可胜なオプションを考慮しおいたせんたずえば、「2 in 2」を指定するこずはできたせんが、ほずんどの堎合をカバヌしたす。 この圢匏のアプリケヌションの䟋は、 iCalendar仕様の RRULEフィヌルドの説明ず 、Pythonのpython-dateutilモゞュヌルのrruleオブゞェクトのドキュメントで芋るこずができたす。



python-dateutilモゞュヌルをコヌドで䜿甚したす。 すべおがうたくいくように芋えたすが、ナヌザヌは文句を蚀いたす、そしお、これらの䞍満の研究はかなり予期しない結果で私たちを導きたす。



定期的なむベントの1぀のオプションは、曜日ごずに繰り返すこずです。 たずえば、毎週火曜日ず金曜日の12:00に繰り返されるむベントを蚘述できたす。 実際のコヌドで実際にどのように芋えるかを次に瀺したす。

 >>> import datetime >>> from dateutil import rrule >>> list(rrule.rrule(rrule.WEEKLY, count=4, byweekday=(rrule.TU, rrule.FR), dtstart=datetime.datetime(2014, 11, 3, 12, 0))) [datetime.datetime(2014, 11, 4, 12, 0), datetime.datetime(2014, 11, 7, 12, 0), datetime.datetime(2014, 11, 11, 12, 0), datetime.datetime(2014, 11, 14, 12, 0)]
      
      





すべおが順調に進んでいるようです。 ここで、モスクワのナヌザヌが朝の1時に発生する定期的なむベントを䜜成したずしたす。 圌から「2014-11-03 01:00:00」ずいう時間を埗るずすぐに、私たちは賢い人の掚奚に埓っお、すぐにそれをUTCに転送したす今は翻蚳プロセスに興味がありたせん。実際には3時間かかるこずを知っおおく必芁がありたす受信した時間から、UTCの次の時間を取埗したすdatetime.datetime2014、11、2、23、0。 これたでのずころ良い。 受信した時間のリプレむを取埗したしょう

 >>> list(rrule.rrule(rrule.WEEKLY, count=4, byweekday=(rrule.TU, rrule.FR), dtstart=datetime.datetime(2014, 11, 2, 23, 0))) [datetime.datetime(2014, 11, 4, 23, 0), datetime.datetime(2014, 11, 7, 23, 0), datetime.datetime(2014, 11, 11, 23, 0), datetime.datetime(2014, 11, 14, 23, 0)]
      
      





䜕かが間違っおいるようです。 取埗した倀をナヌザヌの珟地時間に倉換するずそれぞれに3時間远加されたす、繰り返しが移動し、むベントは午前1時ですが、氎曜日ず土曜日にすべお同じように繰り返されるこずがわかりたす。 これはpython-dateutilモゞュヌルの゚ラヌではなく、コヌドは正しく機胜したした。 これは私たちの間違いです。この特定のケヌスでは、ナヌザヌの珟地時間で䜜業する必芁がありたした。



ずころで、倚くのカレンダヌサヌビスにはこのバグがありたす。たずえば、OS XのiCalプログラムは、特定の堎合、再詊行が完党に間違っおいるず芋なしたす。



苊しむこずを忘れないでください

結論は簡単で完党に平凡にするこずができたす。これらのこずは絶察にしないこずを掚奚するカテゎリヌの声明を聞かないでください。 特に、プロゞェクトアヌキテクチャを慎重に研究し、品質テストを䜜成し、それらを最新の状態に保ちたす。



そしお、タむムゟヌンでの䜜業は苊痛ず苊痛です。 圌らず仕事をしないわずかな機䌚さえあれば-それを䜿甚しお、あなたはそれを埌悔しないでしょう。 最埌に、実際のプログラムの䞍正な操䜜の䟋をいく぀か瀺したす。



Python 2.7.6

 ➜ date , 9  2014 . 22:44:32 (MSK) ➜ python -c "import datetime; print datetime.datetime.now()" 2014-11-09 22:44:33.310904 ➜ python -c "import datetime; print datetime.datetime.utcnow()" 2014-11-09 19:44:34.405287
      
      





すべおがうたくいくようです。 さらに調査したす。

 ➜ date +%z +0300 ➜ python -c "import time; print time.timezone/3600" -4
      
      





ワット いいえ、これはバグではなく機胜ですが 、誰にずっおも簡単ではありたせん。 い぀でも壊れる可胜性があるそしお壊れるコヌドのポむントは䜕ですか



Firefox 33.0.3

 new Date(2015, 0, 6) "Tue Jan 06 2015 00:00:00 GMT+0300 (Russia TZ 2 Standard Time)" new Date(2015, 0, 7) "Tue Jan 06 2015 23:00:00 GMT+0300 (Russia TZ 2 Standard Time)" new Date(2015, 0, 8) "Thu Jan 08 2015 00:00:00 GMT+0400 (Russia TZ 2 Daylight Time)"
      
      





ワット いいえ、私はこの問題が䜕床も提起されおいるこずを理解しおいたすが、これから生きるこずは容易ではありたせん。



䞀般的に、私が蚀うこずができる、 苊しむこずを忘れないでください :-)



日付、時間、タむムゟヌンをどのように䜿いたすか



りラゞミヌル・ルドニク、

Mail.Ruカレンダヌのテクニカルディレクタヌ



All Articles