如何用ActiveSupport::TimeWithZone实现UTC到用户时区对应UTC时间转换
解决Rake任务中UTC时间转用户时区午夜对应UTC时间的问题
需求说明
需要将给定的UTC午夜时间,转换为用户时区当天午夜对应的UTC时间。比如把UTC时间Wed, 01 Mar 2017 00:00:00 UTC +00:00,转换为美国东部夏令时(EDT)对应的UTC时间Wed, 01 Mar 2017 04:00:00 UTC +00:00。
原方法的问题
之前使用in_time_zone的方式只是将原UTC时间转换为用户时区的显示格式,底层的时间戳并没有改变:
zone = ActiveSupport::TimeZone.new("Eastern Time (US & Canada)") time = "Wed, 01 Mar 2017 00:00:00 UTC +00:00" time.in_time_zone(zone) # => Tue, 28 Feb 2017 19:00:00.000000000 EST -05:00
存入数据库后,Rails会自动将时间转回UTC,所以还是原来的Wed, 01 Mar 2017 00:00:00 UTC +00:00,这不符合需求。
正确解决方案
核心思路是:先在用户时区构造目标日期的午夜时间,再将其转换为UTC时间,这样得到的就是用户时区当天午夜对应的UTC时间戳。
代码示例
# 初始化用户时区 zone = ActiveSupport::TimeZone.new("Eastern Time (US & Canada)") # 解析原始UTC时间 original_utc_time = Time.parse("Wed, 01 Mar 2017 00:00:00 UTC +00:00") # 在用户时区创建目标日期的午夜时间(取原始UTC时间的年月日) user_zone_midnight = zone.local( original_utc_time.year, original_utc_time.month, original_utc_time.day, 0, 0, 0 # 时分秒设为午夜 ) # 转换为UTC时间 target_utc_time = user_zone_midnight.utc # 输出结果:Wed, 01 Mar 2017 04:00:00 UTC +00:00
说明
zone.local方法会根据用户时区的规则(包括夏令时)创建正确的时间点,自动处理时区偏移的变化- 转换为UTC后,得到的时间戳就是用户时区当天午夜对应的UTC时间,存入数据库后也会保留这个正确的UTC值
内容的提问来源于stack exchange,提问作者VegaStudios
相关产品推荐
相关产品推荐

