1
0

前提

使用フレームワーク: Ruby on Rals

作成したもの: railsを使ったごく単純な掲示版風アプリ(今回詳細は省きます)

使用するDBエンジン: SQLite3(新規アプリ立ち上げ時のデフォルトのまま)

やりたいこと: デフォルトではレコードの作成日時と更新日時がUTC表記になっているので、テーブル上の表記をJSTに変更したい

以下が作成したDBのスキーマ(後述のオチを知る前に作成したもの)

## Table:posts
| Column Name | Data Type | Nullable |
|-------------|-----------|----------|
| title       | string    |          |
| content     | text      |          |
| created_at  | datetime  |   false  |
| updated_at  | datetime  |   false  |

画像だと判別できませんが、created_atとupdated_at内のレコードがUTCとなっています。(実際に作成した時間はレコード内表記の時間+9)

スクリーンショット 2024-04-03 16.19.04.png

始めに申し上げておきますと、SQLiteにはDB内タイムスタンプの表示形式を変更するための直接的な方法はありません。それをひたすらJST表記に直そうと悪戦苦闘したわけですが、そもそもSQLiteは日付/時刻型のデータ型を持っていないという間抜けなオチがありまして…。お恥ずかしながらスキーマ書いてた時は存じ上げませんでした。

今回初めて知ったのですが、Date型に見える上記のタイムスタンプはテキスト型で保持しているだけだそうです。最初に公式リファレンス等で確認しておくべきでしたね。
スクリーンショット 2024-04-03 19.12.31.png

試したこと (供養も兼ねて書かせていただきます)

その1

application.rbの編集。(コメントアウトを外す)

#

require_relative "boot"

require "rails/all"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module RubydemoBbs
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 7.0

    # Configuration for the application, engines, and railties goes here.
    #
    # These settings can be overridden in specific environments using the files
    # in config/environments, which are processed later.
    #
    # config.time_zone = "Central Time (US & Canada)"
    # config.eager_load_paths << Rails.root.join("extras")
  end
end

調べてみるとこのファイルにRailsのタイムゾーン設定が記述されているようなので、


# config.time_zone = "Central Time (US & Canada)"のコメントアウトを外す
config.time_zone = "Central Time (US & Canada)"
# time_zoneを"Tokyo"へ修正
 config.time_zone = "Tokyo"

上記の状態でDBを再度確認。
が、DBの表記は変わらず。
ですが、以下画像のようにブラウザ側の表示が
スクリーンショット 2024-04-03 18.07.45.png
から
スクリーンショット 2024-04-03 18.10.17.png
アプリ側はJTS表記へ変わるようです。

その2

再びapplication.rbの編集。(オプションを追加する)

require_relative "boot"

require "rails/all"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module RubydemoBbs
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 7.0

    # Configuration for the application, engines, and railties goes here.
    #
    # These settings can be overridden in specific environments using the files
    # in config/environments, which are processed later.
    #
    config.time_zone = "Tokyo"
    
    # オプション追加
    config.active_record.time_zone_aware_types = [:datetime, :time]
    # config.eager_load_paths << Rails.root.join("extras")
  end
end

上記のオプションを追加しました。

config.active_record.time_zone_aware_types = [:datetime, :time]について

Active Recordがタイムゾーンを含む値を処理する際に、データ型を指定して渡すことのできるオプションです。
保存・取得を行う際に指定したデータ型に変換してねという設定です。指定するデータ型はハッシュの形式で書きます。この場合はタイムゾーン(datetime)、時刻(time)それぞれのデータ型のカラムに対して変換しているような理解です。
※注意※  
アプリケーション全体の挙動に影響を及ぼす設定変更になるので、試す際はくれぐれも慎重に、かつ自己責任で行ってください。

こちらはDB、ブラウザ表示ともに変化なし。

ならもうSQLでなんとかできない??

できません。
ですが、SELECT文で取得した作成日時と更新日時をJTC表記風に変換することは可能です。
試したことではあるので一応書いておきます。

SELECT datetime(created_at, 'localtime') AS local_created_at
FROM posts;

スクリーンショット 2024-04-03 18.42.57.png

datetime 関数を使用して created_at 列の値をローカルタイムゾーンに変換しています。
新たに「local_created_at」というカラムが出来てそれを取得することはできました。
でもやりたいのはそういうことじゃない・・・。

最終的に

答えはapplication.rbにありました。

require_relative "boot"

require "rails/all"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module RubydemoBbs
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 7.0

    # Configuration for the application, engines, and railties goes here.
    #
    # These settings can be overridden in specific environments using the files
    # in config/environments, which are processed later.
    #
    config.time_zone = "Tokyo"
    
    #オプションをここに再度追加
    config.active_record.default_timezone = :local
    # config.eager_load_paths << Rails.root.join("extras")
  end
end

config.active_record.default_timezone = :local

最初にconfig.time_zoneを編集していたのがここで活きました。
タイムゾーンを考慮したデータをDBに保存する場合に、ローカルのタイムゾーンに変換するという設定のようです。

スクリーンショット 2024-04-03 18.49.47.png

すると、当初やりたかったことが形にできました。
3行目が編集前に投稿したデータ、4行目が編集後に投稿したデータになります。編集前にすでに格納済みだった日時データには反映されないみたいですね~。
ちなみに今回スキーマは変更していないので再度マイグレーションは行なっておりません。
が、今のところ問題は起きていませんでした。

終わり

読んでいただきありがとうございました。
まだ知らないことばかりですね。日々痛感します。

参考
意外と知らないTimestamp
SQLiteで日付時刻を扱う際のポイント

1
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
1
0