fix: parse timezones as JSON

- Updated timezone parsing to handle JSON format.
- Modified how timezones are fetched in multiple models.
- Added a migration to convert existing timezones data.
- Modified the country model to format timezones.

This commit fixes an issue where the timezone data was not
being correctly parsed, leading to potential errors in time
calculations.  The changes ensure the application correctly
handles and displays timezone information, improving the
accuracy of time-related features.
This commit is contained in:
songtianlun 2025-02-15 17:21:02 +08:00
parent 2ffb1a4248
commit 5e716a46d9
6 changed files with 22 additions and 48 deletions

View File

@ -218,7 +218,7 @@ class City < ApplicationRecord
def formatted_current_time(type = :date, use_local_timezone = true)
# 获取时区
timezone_info = self.country&.timezones.present? ?
country&.timezones&.first :
JSON.parse(country.timezones)&.first :
{ "zoneName" => "UTC", "gmtOffsetName" => "UTC+00:00" }
# 设置时区对象

View File

@ -2,6 +2,8 @@ class Country < ApplicationRecord
extend FriendlyId
friendly_id :name, use: :slugged
before_save :format_timezones
belongs_to :region, optional: true
belongs_to :subregion, optional: true
has_many :cities, dependent: :restrict_with_error
@ -11,7 +13,6 @@ class Country < ApplicationRecord
validates :code, presence: true, uniqueness: true
validates :iso2, uniqueness: true, allow_blank: true
attribute :timezones, :jsonb
def to_s
name
@ -28,4 +29,15 @@ class Country < ApplicationRecord
def self.ransackable_associations(auth_object = nil)
[ "cities", "region" ]
end
private
def format_timezones
if timezones.is_a?(String)
# 先尝试转换成 Ruby 对象
ruby_obj = eval(timezones)
# 然后转换成标准 JSON
self.timezones = ruby_obj.to_json
end
end
end

View File

@ -71,7 +71,7 @@ class WeatherArt < ApplicationRecord
def formatted_time(type = :date, use_local_timezone = false)
# 获取时区
timezone_info = self.city&.country&.timezones.present? ?
self.city.country&.timezones&.first :
JSON.parse(self.city.country.timezones)&.first :
{ "zoneName" => "UTC", "gmtOffsetName" => "UTC+00:00" }
# 设置时区对象

View File

@ -62,7 +62,11 @@ class BatchGenerateWeatherArtsWorker
def get_local_time(city)
return Time.current unless city
timezone_info = city.country&.timezones&.first
timezone_info =
city.country&.timezones.present? ?
JSON.parse(city.country.timezones)&.first :
{ "zoneName": "UTC" }
return Time.current unless timezone_info
timezone = ActiveSupport::TimeZone[timezone_info["zoneName"]] ||

View File

@ -1,42 +0,0 @@
class ConvertCountryTimezonesToJson < ActiveRecord::Migration[8.0]
def up
# 1. 首先添加一个临时列
add_column :countries, :timezones_json, :jsonb
# 2. 转换现有数据
Country.find_each do |country|
if country.timezones.present?
begin
# 尝试解析现有的 timezones 字符串
parsed_timezones = eval(country.timezones) # 这里使用 eval 是为了处理历史数据
country.update_column(:timezones_json, parsed_timezones)
rescue => e
puts "Error converting timezones for country #{country.id}: #{e.message}"
# 设置默认值
country.update_column(:timezones_json, [ { "zoneName" => "UTC", "gmtOffsetName" => "UTC+00:00" } ])
end
else
# 设置默认值
country.update_column(:timezones_json, [ { "zoneName" => "UTC", "gmtOffsetName" => "UTC+00:00" } ])
end
end
# 3. 删除旧列并重命名新列
remove_column :countries, :timezones
rename_column :countries, :timezones_json, :timezones
end
def down
# 回滚操作
add_column :countries, :timezones_string, :text
Country.find_each do |country|
if country.timezones.present?
country.update_column(:timezones_string, country.timezones.to_s)
end
end
remove_column :countries, :timezones
rename_column :countries, :timezones_string, :timezones
end
end

4
db/schema.rb generated
View File

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[8.0].define(version: 2025_02_15_084540) do
ActiveRecord::Schema[8.0].define(version: 2025_02_11_035423) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_catalog.plpgsql"
@ -158,7 +158,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_02_15_084540) do
t.boolean "flag", default: true
t.string "wiki_data_id"
t.bigint "subregion_id"
t.jsonb "timezones"
t.text "timezones"
t.index ["code"], name: "index_countries_on_code", unique: true
t.index ["region_id"], name: "index_countries_on_region_id"
t.index ["slug"], name: "index_countries_on_slug", unique: true