[英]Rails Upgrade makes default Time format change. How to revert?
我正在升級 Rails 應用程序
在各個步驟中。 由於 Rails 升級需要 Postgres 升級,因此我無法以合理的方式將升級分開。
目前,我正在為 Rails 5.2 中處理“時間”對象的方式而苦苦掙扎。 AR 對象中的“時間”列現在作為ActiveSupport::TimeWithZone
返回,即使數據庫列沒有時區。 以前它是一個普通的Time
對象,它具有不同的默認 JSON 表示。
這使得許多 API 測試失敗,而這些測試以前都返回 UTC 時間。
用於PhoneNumber
對象的 Rails 4.2、Ruby 2.2、PG 9.1 示例:
2.2.6 :002 > p.time_weekdays_from
=> 2000-01-01 07:00:00 UTC
2.2.6 :003 > p.time_weekdays_from.class
=> Time
Rails 5.2、Ruby 2.5、PG 10 的示例:
irb(main):016:0> p.time_weekdays_from
=> Sat, 01 Jan 2000 11:15:00 CET +01:00
irb(main):018:0> p.time_weekdays_from.class
=> ActiveSupport::TimeWithZone
我已經添加了一個初始化程序來暫時覆蓋它,這似乎工作正常,但我仍然想了解為什么進行了這種更改,以及為什么即使“沒有時區的時間”DB 列也被 Rails 視為如果他們有時區。
# This works, but why is it necessary?
module ActiveSupport
class TimeWithZone
def as_json(options = nil)
self.utc.iso8601
end
end
end
PS:我並不總是想要 UTC,我只是想要它用於 API,因為這是我們的 API 客戶所期望的。
目前,我正在為 Rails 5.2 中處理“時間”對象的方式而苦苦掙扎。 AR 對象中的“時間”列現在作為 ActiveSupport::TimeWithZone 返回,即使數據庫列沒有時區。 以前它是一個普通的 Time 對象,它具有不同的默認 JSON 表示。
盡管如此,我還是想了解為什么進行了這種更改,以及為什么即使是“沒有時區的時間”DB 列也被 Rails 視為有時區。
進行此更改是因為 Ruby 的默認Time
不了解時區。 ActiveSupport::TimeWithZone
可以。 這在處理時間、時區和數據庫時解決了很多問題。
例如,假設您的應用程序的時區是America/Chicago
。 以前,您必須決定是否要存儲帶時區或不帶時區的時間。 如果您選擇沒有時區,您是將其存儲為 UTC 還是 America/Chicago? 如果您將其存儲為 UTC,您是否在加載或顯示時將其轉換為美國/紐約? 轉換意味着從Time
添加和減去小時。 當您保存Time
對象時,您必須小心記住Time
被轉換為哪個時區並將其轉換回數據庫的時區。 協調所有這些會導致許多錯誤。
Rails 5 引入了ActiveSupport::TimeWithZone
。 這將時間存儲為 UTC 和所需的時區來表示它。現在處理時間更簡單:將其存儲為 UTC(即timestamp
)並在加載時添加應用程序的時區。 不需要轉換。 Rails 會為您處理這個問題。
更改現在是timestamp
列,默認情況下,將在應用程序的時區中格式化。 這需要一些時間來適應,但最終將使您對時間和時區的處理更加穩健。
> Time.zone.tzinfo.name
=> "America/Chicago"
> Time.zone.utc_offset
=> -21600
# Displayed in the application time zone
> Foo.last.created_at
=> Tue, 31 Dec 2019 17:16:14 CST -06:00
# Stored as UTC
> Foo.last.created_at.utc
=> 2019-12-31 23:16:14 UTC
如果您有手動執行時區轉換的代碼,請刪除它。 在 UTC 工作。 時區現在只是格式化。
越多越好...
def get_api_time
'2000-01-01 07:00:00 UTC'
end
# bad: downgrading to strings, implicit formatting
expected_time = Time.utc(2000, 1, 1, 7)
expect( get_api_time ).to eq expected_time
# good: upgrading to objects, format is irrelevant
expected_time = Time.zone.parse('2000-01-01 07:00:00 UTC')
expect(
Time.zone.parse(get_api_time)
).to eq expected_time
# better: refactor method to return ActiveSupport::TimeWithZone
def get_api_time
Time.zone.parse('2000-01-01 07:00:00 UTC')
end
expected_time = Time.zone.parse('2000-01-01 07:00:00 UTC')
expect( get_api_time ).to eq expected_time
我建議閱讀這些文章,它們可以解決問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.