このコードには日付と時刻の変換に問題がありますか?
概要
if picture[:latitude] && picture[:longitude]
parsed_date_time = DateTime.rfc3339(picture[:picture_timestamp]).to_s(:db)
timezone = Timezone.lookup(picture[:latitude], picture[:longitude])
date_obj = ActiveSupport::TimeZone[timezone.name].parse(parsed_date_time)
date_with_offset = DateTime.new(date_obj.year, date_obj.month, date_obj.day, date_obj.hour, date_obj.min, date_obj.sec, date_obj.zone).to_s
@dailypost.picture_timestamp = Time.zone.parse(date_with_offset)
end
次のような状況があります。クライアント側は写真のEXIFデータをサーバーに送信します。さらに、任意の日付 (originalDateTime、dateTime、または digitalizedDateTime) は、オフセットがゼロの rfc3339 形式で送信されます (例: 2017-20-10T12:50:30 + 00:00、なぜこのようになり、そうでないのか、別の質問) 。今は変更できません)。
(そして、オフセットが 0 の dateTime を取得した場合、それは単にクライアント側がオフセットを 0 にして、オフセットが 0 の日付と時刻を単に連結しているだけです。ただ連結しているだけです。そして、それが日付を解析するだけの理由です。 rfc3339 から時刻を取得し、特定の timeZone を使用して dateTime オブジェクトを作成します)
サーバー側では、およそ次のことが起こります。座標に基づいて timeZone を計算し、必要なオフセットを使用して日時オブジェクトを作成し、この日付をサーバーのデフォルトのタイムゾーン (中部夏時間) に合わせてデータベースに保存します。日付を受信してデータベースに保存する形式を変更することはできません。さらにデータベースからこの日付が取り出され、再度 rfc3339 形式に変換されてクライアント側に送信されます。
ここで日付と時刻の変換に間違いがあると思いますが、今は確認できません。問題は、間違った日付でアップロードされている写真があると言われたことです。これらすべての行動に、何か有効なものはあるのでしょうか?
解決策
DateTime は、時刻とタイムゾーンを含む日付と考えてください。DateTime.rfc3339(picture[:picture_timestamp]) を実行することで、EXIF が +00:00 を含むすべての日付を返す場合、RFC 日付はすでにタイムゾーン付きの日付時刻に変換されています。は、ゼロ化されたオフセットで登録されていることを意味します。これは、時間が正しいか、他のタイムゾーンで表示されているだけであるか、最悪の場合は登録されていないことを意味します。 この場合、元の値で新しい DateTime を作成し、タイムゾーンを追加する必要があります。
offset = ActiveSupport::TimeZone[timezone.name].formatted_offset
date_with_offset = DateTime.new(parsed_date_time.year, parsed_date_time.month, parsed_date_time.day, parsed_date_time.hour, parsed_date_time.min, parsed_date_time.sec, offset)
一方、Rails は config/application.rb ファイル内のアプリのデフォルトのタイムゾーンを使用して、データベースからの日付を表示および変換します。そのため、アプリが CDT で構成されている場合は、正しい datetime オブジェクトを渡すだけで済みます。日付にはすでに解析時のタイムゾーンがあるため、db と Rails が保存のための変換を処理します。心配する必要はありません (ユーザーに日付を要求しており、それを理解するためにタイムゾーンが必要な場合は異なります) )、データベースによっては、これらは日時オブジェクトまたは整数のタイムスタンプとして処理されますが、タイムゾーン (+0) がない可能性が最も高くなります。ユーザーに日付を提示する部分で、ユーザーごとに異なるタイムゾーンを使用したい場合は、データベースにこのフィールドを用意し、Time.at(@dailypost.picture_timestamp) のようにプレゼンテーション部分で使用する必要があります。 in_time_zone(current_user.timezone)、Time.at はタイムスタンプ以降の日時 (epoc からの秒数)、current_user.timezone はタイムゾーンの名前です (例: ‘Sidney’)、または、あなたの例のように緯度と経度。
参照: