11
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ClassiAdvent Calendar 2019

Day 18

Rails: exifにタイムゾーンがないからどんな感じで保存しようかなと思った話

Posted at

Classi Advent Calendar 2019 の18日目、Railsアプリケーションエンジニアをやっている@HokotaMisakiです。

今回書くお話はClassiではなく、自宅で作っている野鳥観察記録サービスで体験したものなのですが、マニアックでピンポイントなケースだと思ったので紹介します(テーマ的にRails絡んでるからセーフだと思ってる)。

主に、exifにタイムゾーンの有り無しを確認することになった経緯についての話になります。

※ なおexifとは、画像の中に埋め込まれているメタデータのことです。位置情報や時刻、撮影カメラの設定情報などが保存されています。

まずは結論から

この2つのあわせ技で行くことにしました。

  1. ユーザに自身のタイムゾーンを登録してもらう
  2. アプリケーションはユーザ毎のタイムゾーンで動き、時刻をそのままアプリケーションのタイムゾーンで保存する

「えっ、exifらしさもないし、なんか普通・・・」

って感じなんですが、ではなぜこれに行き着いたのか、なぜこれをしなければならなかったのか、を以下に記載します。

前提

自宅で作っている野鳥観察記録サービス「ZooPicker」は、世界中で撮った野鳥の写真とフィールドノート(観察場所や時間、観察種類などを記録するもの)を投稿していくサービスです。
投稿したものは公開されるので、野鳥情報の共有サービスとも言えます。
ゆくゆくは海外展開もしていきたいので、I18n系の対応も徐々に進めています。

ことの発端

バーダー(野鳥を追いかけている人たちのこと)にとって、野鳥が「どこで」「いつ」出たのか、は大事な情報です。
なので素敵な野鳥写真が投稿されると、「これ!!!!どうやったら見れるの???」となります。

撮った写真の場所を登録する機能はあったので(exifの位置情報は捨ててるので手入力なんですが)、
撮った写真の時刻(⇒ 「撮影現地時刻」)も登録できるようにしよう!と思いました。

なお、写真の投稿はだいたい帰宅後に行うので、投稿日時は使えません。

やりたいこと: 世界の誰が見ても、撮った現地の時刻で表示させたい

ご存知のとおり、時刻およびデータベースの時刻系カラムにはタイムゾーンがあり、
かつ、ActiveRecordはそれをアプリケーションのタイムゾーンに応じて出してくれるという便利機能を持っています。

加えて、写真にはexif情報があるので、
このexifにきっと時刻情報あるだろうから、それ保存すればいいじゃーんと思いました。

下の絵のように、「撮影現地時刻」がアプリケーションのタイムゾーンに自動変換されちゃう事態は避けたかったわけです。
スクリーンショット 2019-12-18 11.25.54.png

つまづいた点

exifに時刻はあるけどタイムゾーンは無い

はい。タイトルのとおりなのですが。おおよそ無いようです。
Wikipediaより:
Exchangeable image file format

撮影日時の情報は、UTCとタイムゾーンを組み合わせたものではなく、機種依存のローカルタイム(現地時刻)のみで記録され、タイムゾーン情報が記録されていないので、海外旅行や出張などタイムゾーンをまたいで移動、生活する際に問題となることもある。なお、タイムゾーン情報が記録できるカメラなどもあるが機種依存の機能であって、Exif共通の仕様ではタイムゾーン情報の付加には対応していない。

言われてみればそうかーという感じです。カメラがWebに繋がんないとですもんね・・・

なお、時刻情報はOriginalTimeという項目で存在します。

「投稿日時」は時差計算されてもいいけど、「撮影時刻」は現在地の時刻を出したい

ActiveRecordは、アプリケーションのタイムゾーンに応じて時刻を表示してくれますね。
ところが、「撮影現地時刻」だけは自動変換されてほしくありません。
じゃあどこのタイムゾーンで表示するの!カメラに現地時刻入ってないのに!となりました。

カメラのOriginalTimeがどこのタイムゾーンかの判定方法がわからない

わかれば、場所と照らし合わせて撮影時刻算出できるのになぁ。

結果

とりあえず ユーザのタイムゾーン≒カメラのタイムゾーン ってことにしよう

今回のケースを実現するロジックは、

1. 何らかでタイムゾーンを保存(exifの位置情報でタイムゾーンを算出 or ユーザにタイムゾーンを設定してもらう)
2. カメラのOriginalTimeから時差計算して「撮影現地時刻」を算出
3. 保存
4. 表示するときに「保存したタイムゾーンで出す」をやる

と思っています。

exifからの算出は、もっとタイムゾーン付きカメラが普及してからにしよう・・・と思いました。
それまでは、多少そぐわないケースもあるかもしれないけど、だいたい一致する「ユーザの希望タイムゾーン」で。

現在は、時刻が取れたらそのまま自動入力、修正がある場合は手入力可、としています。

ちなみに1度**「文字列で時刻保存する・・・?」**と思ったです。

できあがったコード

datetime =
  if v[:exif][:dateTimeOriginal]
    # exifにはタイムゾーン情報が基本ない
    # とりあえずtimezone設定を使う
    timezone = Time.current.strftime('%z')
    DateTime.strptime(
      v[:exif][:dateTimeOriginal].gsub('-', ':') + " #{timezone}",
      '%Y:%m:%d %H:%M:%S' + " %z"
    )
  end

何も解決してない

実は「ユーザ自身のタイムゾーンを登録する機能」は未実装なので、サービス的にはまだ何も解決してません!

参考: システム的なこと

  • Rails5.1(当時)
  • 画像投稿するときは、フロントでバイナリからexifを取り出してサーバにリクエストしている
    • exifは保存してない
    • exif-jsを使ってる

おわりに

おおよそのケースではRailsはタイムゾーンのことをほとんど意識せずに済むような仕組みが整っていると思います。
今までの業務でも海外展開しているサービスは触ったことがなかったので、今回改めて勉強になったなぁと思いました。

明日は @hakshu さんです!

11
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?