只是增加了关于时区和夏令时问题的数百万个问题。
我有一个带有单独日期和时间字段的表单,我将它们组合起来创建一个类似的DateTime
start_time = DateTime.parse("#{parse_date(form_date)} #{form_start_time} #{Time.zone}")
如果我在2012年8月21日和15:00之前填写表格,那么这些是我重新加载表格时看到的值。如果我查看模型中的start_time属性,它会正确设置为Tue, 21 Aug 2012 15:00:00 EST +10:00
。
如果我在今年晚些时候使用夏令时(我在澳大利亚),我就会遇到问题。如果我使用2012年12月21日和15:00,请检查start_time I see Fri, 21 Dec 2012 16:00:00 EST +11:00
。
我对这个问题的解释是,日期保存在我当前的时区(+10:00),因为这是我告诉DateTime.parse要做的。然而,当返回值时,Rails会查看日期并说"嘿,现在是12月的夏令时",然后返回+11:00时区的时间。
如果夏令时生效,我想告诉DateTime.parse将时间保存在+11:00时区。显然,将Time.zone传递到我的字符串中并不能实现这一点。有简单的方法吗?我可以看到使用Time#dst的方法?但我怀疑这会产生一些非常丑陋、复杂的代码。我想可能有一个内置的方式,我错过了。
(Rails 4.2.4的答案,没有检查旧版本或新版本)
我建议使用以时区名称为参数的in_time_zone
字符串方法:,而不是使用固定移位+01:00、+02:00等
夏季时间:
ruby :001 > "2016-07-02 00:00:00".in_time_zone('Paris')
=> Sat, 02 Jul 2016 00:00:00 CEST +02:00
冬季时间:
ruby :002 > "2016-11-02 00:00:00".in_time_zone('Paris')
=> Wed, 02 Nov 2016 00:00:00 CET +01:00
String#in_time_zone
相当于:
ruby :003 > Time.find_zone!("Paris").parse("2016-07-02 00:00:00")
=> Sat, 02 Jul 2016 00:00:00 CEST +02:00
ruby :004 > Time.find_zone!("Paris").parse("2016-11-02 00:00:00")
=> Wed, 02 Nov 2016 00:00:00 CET +01:00
您可以通过以下方式获取时区名称:
$ rake time:zones:all
或轨道控制台:
ruby :001 > ActiveSupport::TimeZone.all.map(&:name)
或者为选择标签构建集合:
ActiveSupport::TimeZone.all.map do |timezone|
formatted_offset = Time.now.in_time_zone(timezone.name).formatted_offset
[ "(GMT#{formatted_offset}) #{timezone.name}", timezone.name ]
end
并存储时区名称而不是班次。
注意:不要混淆String#in_time_zone
方法和Time#in_time_zone
方法。
考虑一下我的系统的时区是"巴黎"。
ruby :001 > Time.parse("2016-07-02 00:00:00")
=> 2016-07-02 00:00:00 +0200
ruby :002 > Time.parse("2016-07-02 00:00:00").in_time_zone("Nuku'alofa")
=> Sat, 02 Jul 2016 11:00:00 TOT +13:00
这是我迄今为止的解决方案。我希望有人有更好的。
start_time = DateTime.parse "#{date} #{(form_start_time || start_time)} #{Time.zone}"
start_time = start_time - 1.hour if start_time.dst? && !Time.now.dst?
start_time = start_time + 1.hour if Time.now.dst? && start_time.dst?
它似乎有效,但我还没有严格测试过。我怀疑它可以被美化和缩短,但我认为这是可读的和可以理解的。有什么改进吗?
我遇到了这个问题。我的应用程序允许用户查看即将举办的活动。在美国,11月2日是夏令时,当天及之后的所有活动都提前一小时显示时间。
我们要求有机会选择时区并将其存储到自己的字段中。在我使用以下内容存储我的约会时间之前:
timezone_offset = Time.now.in_time_zone(params[:opportunity][:time_zone]).strftime("%z") #-0700
DateTime.parse("#{params[:opportunity][:start_datetime]} #{timezone_offset}")
为了解决这个问题,我改为:
start_datetime = Time.zone.parse(params[:opportunity][:start_datetime])
要显示正确的时间,我们使用:
@opportunity.start_datetime.in_time_zone(@opportunity.time_zone)
有了Rails,我们可以使用ActiveSupport::TimeZone进行以下操作:
tz = ActiveSupport::TimeZone.new 'Pacific Time (US & Canada)'
tz.parse(date_str_without_zone).to_datetime
我使用TZip从邮政编码中获取时区字符串(例如"太平洋时间(美国和加拿大)")。
我会尝试使用
Australian Eastern Standard Time (AEST) (UTC +10).
Australian Central Standard Time (ACST) (UTC +9 ½).
Australian Western Standard Time (AWST) (UTC +8).
其针对夏令时进行调整。
如果您有不同于String#in_time_zone
支持的自定义日期/时间格式,您也可以使用(由于rails 5)strptime
,如:
Time.find_zone!('Auckland').strptime('2021-02-02 08.00.00', '%Y-%m-%d %H.%M.%S')