こんにちは、あらいです。 「言の葉の庭」のBDを買ったので雨の日に社内シアタールームでゲリラ上映会をしてやろうと企んでいます。
先日、と言っても連休前ですが「タスク〆切時間」機能をリリースしました。 その中でいくつか知見を得たので共有したいと思います。
日付と時刻のデータ特性の違い
このリリース以前では、Chatworkのタスクは「日付」の単位で期限を指定することができました。 日付は主観的なデータです。地球上には時差があり、ある地点の日付が5/1だった時に 隣の地点での日付は4/30かもしれませんし5/2かもしれません。 どこの地点を基準に考えるかによって「日付がいつか」が決まります。 日付は相対的で、幅を持ったデータだとも言えます。
「時刻」も同様に相対的なデータです。例えば「夜の8時」がいつの時点かは、基準とする地点によって変わります。 しかし、我々プログラマーにはUNIX時間があります。 これを使うと「UTCを基準にする」という情報をデータフォーマット仕様として埋め込むことができ、日付時刻の絶対的なポイントを表せます。 「1234567890」という値で表された時点を「イギリス時間2009/2/13 23:31:30」や「日本時間2009/2/14 8:31:30」と表示できるようになります。
仕様を考える上で 相対 <-> 絶対 の違いを把握しておくことは必須でした。
いろんなタイムゾーン
タスクの時間は30分単位で入力できます。 じゃあタスクの〆切時間データは必ず30分(1800秒)刻みになるか? というとそうはなりません。 世の中には15分の時差のあるタイムゾーンがあります。2019/5現在では以下の3つがあります。
場所 | タイムゾーン | UTCオフセット |
---|---|---|
ニュージーランドのチャタム諸島 | Pacific/Chatham |
UTC+12:45 |
ネパール | Asia/Kathmandu |
UTC+05:45 |
オーストラリアの一部 | Australia/Eucla |
UTC+08:45 |
仮にネパールで12:00〆切のタスクを作ったとすると、日本では15:15〆切であるようにデータ上は見えることになります。
では、内部的には15分(900秒)刻みのデータを持つことにしよう。と一瞬考えましたがこれも良くありません。 歴史的には20分単位であったり秒単位のオフセットを持つタイムゾーンが過去には存在していました。 Chatworkのタスクではそのような過去の時間を扱う必要はありませんが、これから先の未来において 30分15分以外のオフセットを持つタイムゾーンが新たに発生しない、という保証はどこにもありません。
今回はどのようなオフセットのタイムゾーンでも動作するよう設計することにしました。
クライアントとローカル時間
ChatworkはWebブラウザ版、iOSアプリ、Androidアプリ、デスクトップアプリがあります。 これらのクライアントプログラムはローカル時間を考慮して動作し、内部用のAPIを使います。
一方で社外に公開しているChatwork APIは、ユーザーが作成したプログラムや連携先の外部システムから利用されます。 これら外部のクライアントプログラムについて、時間をどのように扱っているか基本的に不明です。 サーバプログラムからするとクライアントから送信された値がどのような時間に基づいて計算されたものか分かりませんし、 仮に1分なり5分で切り上げて、編集した値を保存したとすると、外部から入力された情報が欠落することになります。 人が手作業で入力&閲覧する値であればまだしも、システム間連携では予想のつかない影響を及ぼす可能性があります。
以上のことから、今回はクライアントから入力された日付時刻は編集を行わずに 秒単位までそのまま保存する方針としました。
このしわ寄せは各クライアントアプリに行っており「期限の時間は直近30分刻みの時間に前倒して表示する」というロジックを 各クライアントが実装することになりました。 前倒しとは、例えば「データ上15:15〆切のタスクは15:00〆切として表示する」ということです。 これは「本来の時間を過ぎてしまうよりも、時間前にタスクを完了してもらった方が良い」という考えに基づきます。 手間がかかりましたが、クライアントチームはすばらしい仕事をしてくれたと思います。
まとめ
ここ数ヶ月ずっと日付と時間帯のことを考えていた気がします。 Wikipediaの暦関連の記事は面白いものがたくさんありました。 *1 こういう知見を仕様面に活かせたので良かったかなと思っています。
この知見が誰かの役に立てば幸いです。
Chatworkでは自分で仕様を考えてコードを書き、サービスを作っていくエンジニアを募集しています。 ScalaだけでなくPHPも募集中ですのでぜひよろしくお願いします。
*1:英語の「o'clock」は「of the clock(機械時計の)」が由来で、対義語となるのは「sundial(日時計=地方時)」だそうです