【问题标题】:Calculate time from an array and convert to time zone从数组计算时间并转换为时区
【发布时间】:2016-03-18 00:05:27
【问题描述】:

我有一个数组bed_timesTime UTC 格式的实例:

bed_times = [
  Time.utc(2015, 12, 10,  5, 58, 24),
  Time.utc(2015, 12,  9,  3, 35, 28),
  Time.utc(2015, 12,  8,  6, 32, 26),
  Time.utc(2015, 12,  7,  1, 43, 28),
  Time.utc(2015, 12,  5,  7, 49, 30),
  Time.utc(2015, 12, 04,  7,  2, 30)
]
#=> [2015-12-10 05:58:24 UTC,
#    2015-12-09 03:35:28 UTC,
#    2015-12-08 06:32:26 UTC,
#    2015-12-07 01:43:28 UTC,
#    2015-12-05 07:49:30 UTC,
#    2015-12-04 07:02:30 UTC]

我正在尝试获取平均就寝时间,但我没有得到正确的结果

ave = Time.at(bed_times.map(&:to_f).inject(:+) / bed_times.size)

结果是

2015-12-07 01:26:57 -0800

这是不正确的。另外,我想将平均时间转换为不同的时区

我试过了

Time.zone = 'Pacific Time (US & Canada)'
Time.zone.parse(ave.to_s)
2015-12-07 01:26:57 -0800

这也不对。

【问题讨论】:

    标签: ruby-on-rails arrays ruby time average


    【解决方案1】:

    您必须计算与午夜的差距的平均值

    一个不优雅(但快速)的解决方案可能是:

    # Keep only time    
    bed_times.map! { |bt| Time.parse(bt.split(" ")[1]) }
    
    # calculate the gap from 00:00:00
    gap_from_midnight = bed_times.map do |bt|
      if bt > Time.parse("12:00:00")
        gap = (bt.to_f - Time.parse("24:00:00").to_f)
      else
        gap = (bt.to_f - Time.parse("00:00:00").to_f)
      end
      gap.to_i
    end
    
    # average in sec
    avg_in_sec = gap_from_midnight.inject(:+) / bed_times.size
    
    # average in UTC time zone 
    avg = Time.at(avg_in_sec).utc # => 1970-01-01 05:26:57 UTC (result for bed_times array)
    
    # average in PST time zone (see note)
    avg_pst = Time.parse(avg.to_s).in_time_zone("Pacific Time (US & Canada)") # => Wed, 31 Dec 1969 21:26:57 PST -08:00 (result for bed_times array)
    
    # Keep only time
    avg_pst.strftime("%H:%M:%S") # => "21:26:57" (result for bed_times array)
    

    使用您的bed_times 数组(将值作为字符串)

    bed_times = [
      "2015-12-10 05:58:24 UTC",
      "2015-12-09 03:35:28 UTC",
      "2015-12-08 06:32:26 UTC",
      "2015-12-07 01:43:28 UTC",
      "2015-12-05 07:49:30 UTC",
      "2015-12-04 07:02:30 UTC"
    ]
    

    平均值为:

    • 05:26:57 UTC 时区
    • 21:26:57 在 PST 区域

    用另一个这样的数组

    bed_times = [
      "2015-12-10 01:00:00 UTC",
      "2015-12-09 23:00:00 UTC",
      "2015-10-19 18:00:00 UTC",
    ]
    

    平均值为:

    • 22:00:00 UTC 时区
    • 14:00:00 在 PST 区域

    注意: .in_time_zone 是来自 ActiveSupport::TimeWithZone 的助手 http://api.rubyonrails.org/classes/ActiveSupport/TimeWithZone.html

    【讨论】:

    • 次 = bed_times.map! { |BT| Time.parse(bt.split(" ")[1]) } *** NoMethodError Exception: undefined method `split' for 2015-12-11 05:58:24 -0800:Time 然后我尝试了 bt.to_s.split ...但它没有分裂。
    • 我以为那是一个字符串数组。 [“2015-12-10 05:58:24 UTC”,“..”,]。如果我尝试从您的值创建一个 Time 对象,我会给出一个错误: Time.new(2015-12-10 05:58:24 UTC) SyntaxError: (irb):1: syntax error, unexpected tINTEGER, expecting ') ' Time.new(2015-12-10 05:58:24 UTC) 你如何解析时间?
    • sleeps[1] 是一个包含这些项目的数组 {"startTime"=>"2015-12-10T05:58:24.000Z", "endTime"=>"2015-12-10T13:33 :24.000Z"} {"startTime"=>"2015-12-09T03:35:28.000Z", "endTime"=>"2015-12-09T13:04:28.000Z"} 然后我得到 bed_times 这样的 bed_times = 睡眠[1].map{|el| el['startTime']}.map{|el| Time.zone.parse(el.to_s) };
    • 尝试在末尾添加 .to_s .map{|el| Time.zone.parse(el.to_s).to_s }
    • 谢谢。最后一件事。平均时间 05:26 采用 UTC。我想将其转换为 PST。我试过 Time.zone = 'Pacific Time (US & Canada)'; Time.zone.parse(avg) 2015-12-11 05:26:57 -0800 它似乎没有将其转换为 PST
    【解决方案2】:

    据我了解,您将获得一个数组arr,其中包含太平洋标准时间区域内就寝时间的 UTC 时间。您希望计算平均就寝时间。

    代码

    def avg_bedtime(arr)
      avg = Time.at(arr.reduce(0) do |t,s|
        lt = Time.parse(s).localtime("-08:00")
        t + Time.new(2000, 1, (lt.hour < 12) ? 2 : 1, lt.hour, lt.min, lt.sec, "-08:00").to_f
      end/arr.size)
      "%d:%d:%d" % [avg.hour, avg.min, avg.sec]
    end
    

    示例

    arr = ["2015-12-10 08:58:24 UTC", "2015-12-09 03:35:28 UTC",
           "2015-12-08 06:32:26 UTC", "2015-12-07 01:43:28 UTC",
           "2015-12-05 07:49:30 UTC", "2015-12-04 07:02:30 UTC"]
    

    我第一次改变了这个数组,让它更有趣。

    avg_bedtime(arr)
      #=> "21:56:57"
    

    说明

    让我们首先将这些字符串转换为时间对象:

    utc = arr.map { |s| Time.parse(s) }
      #=> [2015-12-10 08:58:24 UTC, 2015-12-09 03:35:28 UTC, 2015-12-08 06:32:26 UTC,
      #    2015-12-07 01:43:28 UTC, 2015-12-05 07:49:30 UTC, 2015-12-04 07:02:30 UTC]
    

    回顾 PST 比 UTC 晚 8 小时,我们可以使用 Time.localtime 转换为 PST:

    pst = utc.map { |t| t.localtime("-08:00") }
      #=> [2015-12-10 00:58:24 -0800, 2015-12-08 19:35:28 -0800,
      #    2015-12-07 22:32:26 -0800, 2015-12-06 17:43:28 -0800,
      #    2015-12-04 23:49:30 -0800, 2015-12-03 23:02:30 -0800] 
    

    我将把中午之前的就寝时间称为“晚”就寝时间,将当天晚些时候的就寝时间称为“早”就寝时间。 (这当然是任意的。例如,如果其中一些人是轮班工人,这可能是一个问题。)如您所见,pst 的第一个元素是晚睡时间,所有其他人都是早睡时间。

    我现在将这些时间对象转换为具有相同时间但日期不同的时间对象。早睡对象将被分配一个任意日期(例如,January 1, 2000),晚睡对象将被分配一天后(January 2, 2000):

    adj = pst.map { |t| Time.new(2000, 1, (t.hour < 12) ? 2 : 1, t.hour, t.min, t.sec, "-08:00") }
      #=> [2000-01-02 00:58:24 -0800, 2000-01-01 19:35:28 -0800, 2000-01-01 22:32:26 -0800,
     #     2000-01-01 17:43:28 -0800, 2000-01-01 23:49:30 -0800, 2000-01-01 23:02:30 -0800]
    

    我们现在可以将时间对象转换为自纪元以来的秒数:

    secs = adj.map { |t| t.to_f }
      #=> [946803504.0, 946784128.0, 946794746.0, 946777408.0, 946799370.0, 946796550.0]
    

    计算平均值:

    avg = secs.reduce(:+)/arr.size
      #=> 946792617.6666666
    

    转换回 PST 区域的时间对象:

    tavg = Time.at(avg)
      #=> 2000-01-01 21:56:57 -0800 
    

    最后,提取一天中的时间:

    "%d:%d:%d" % [tavg.hour, tavg.min, tavg.sec]
      # "21:56:57
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-04
      • 2021-02-04
      相关资源
      最近更新 更多