besukosan
@besukosan

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

【heroku】現地時刻を取得したい

解決したいこと

Railsで動くアプリで現在地の時刻を表示したい。
この度作っているアプリは特定の国だけでなく全世界に展開するサービスで、DBへ保存する時間データはUTCで統一し、そのデータを現地のタイムゾーンに合わせ表示したいと考えております。

発生している問題・エラー

開発環境と本番環境では挙動が変わるようで、その解決方法が見つけられずにいます。
例えばTime.now.zoneを実行すると、ローカル環境ではタイムゾーンは現在地であるJSTが出力されますが、本番環境(heroku)ではUTCとなります。

irb(main):014:0> Time.now.zone
=> "JST"
irb(main):001:0> Time.now.zone
=> "UTC"

自分で試したこと

ローカル環境では各UTCで保存されたデータを例えば「@user.created_at.localtime」とすれば現地時間に自動変換されますが、本番環境(heroku)では同様の動きにはならないようです。
各都市に合わせて「.in_time_zone('Moscow') 」などとすれば当然対処出来ますが、スマートな方法とは言い難いところです。。
もし対処方法をご存知でしたら、お力を貸して頂けますと幸いです。

0

2Answer

Time.now のタイムゾーンは Rails を実行する OS の設定によって決まります。ユーザーのタイムゾーンにするには @atm-snag さんのおっしゃるとおり #in_time_zone で変える必要があります。

ユーザーのタイムゾーンを得るにはいくつか方法があります。

  • ユーザーに明示的に選択してもらう
  • JavaScript でタイムゾーンを推測して cookie にセットする
    • JavaScript では new Date().getTimezoneOffset() で UTC からのオフセットを取得できるが地域名は推測になる
  • ユーザーの IP アドレスや Accept-Language ヘッダから推測する

なお、 Rails のタイムゾーンは OS の設定以外にも Rails 自身の設定や DB の設定に影響を受けるため、ハマりどころが多いです。以下のまとめをよく確認してみてください。

2Like

Comments

  1. @besukosan

    Questioner

    ご回答いただき有難うございます。

    なるほど、、こういった問題はRailsでは定番なのですね。
    もっとシンプルに解決出来る方法があると考えておりましたので、危うくそれを見つけることに何日も費やすところでした。
    ご指示頂きました方法はどれも魅力的ではありますが、あくまで推測で、正確なタイムゾーンを得ることが難しいということでしたら、残念ながら今回提供するサービスとしては成立しませんので、現地時刻の表示は諦めて他の手段を使おうと思います。
    貴重な情報を下さり心より感謝いたします。

現地の時刻を表示したいという意味と考えています.

現地と定義しているのは,ユーザの現地だと考えています.
それは,ユーザのタイムゾーンがわかれば表示可能かと思います.

それを指定して表示する.ということは,
created_at.in_time_zone( ユーザのタイムゾーン ) をするのと同じだと思います.

1Like

Comments

  1. @besukosan

    Questioner

    ご回答いただき有難うございます。
    なるほど、、そういった方法があるのですね。
    早速確認しましたが私の場合ローカル環境、本番環境ともCreated_atのタイムゾーンはUTCとして保存されておりました。
    Userは日本国内でCreateしましたがJTSにはなっていないようです。

    ```
    irb(main):006:0> User.find(1).created_at.in_time_zone
    User Load (6.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
    => Sun, 04 Oct 2020 15:58:01 UTC +00:00
    ```

    ```
    irb(main):004:0> User.find(1).created_at.in_time_zone
    User Load (1.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
    => Sat, 03 Oct 2020 23:42:30 UTC +00:00
    ```
  2. うまく伝わってないようですみません.

    `User.find(1).created_at.in_time_zone("ユーザのタイムゾーン")`
    のように,`created_at` などを表示(確認) する際に,
    ユーザのタイムゾーンをなんらかの方法で取得して指定すると良いのではないか.
    ということをお伝えしようと考えていました.

    そのユーザのタイムゾーンが `JST` なら `JST` であるというのを別の方法,
    @uasi さんの方法などで決定する必要があると思います.

    例えば,以下のエントリーのように何か類推するも一つの方法ではないかと思います.
    - https://qiita.com/oohira/items/24346474e326ade5cbcc
  3. @besukosan

    Questioner

    お礼が遅れてしまい申し訳ございません。

    なるほど、別途JS等でタイムゾーンを取得してcreated_atに盛り込むのですね。
    世にある多くのWebアプリケーションやプラットフォームには現地時刻が表示または反映されているので、同様の方法が使われてるものか気になるところです。。
    貴重な情報を頂き有難うございます^^

Your answer might help someone💌