从数组中计算时间并转换为时区

3

我有一个数组 bed_times,其中包含以 UTC 格式表示的 Time 实例:

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

这也是不正确的。

2个回答

2
你需要计算从午夜开始的间隔时间的平均值。
一个不太优雅(但快速)的解决方案可能是:
# 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"
]

平均值为:

  • UTC时区为05:26:57
  • PST时区为21:26:57

另一个类似的数组如下:

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

平均时间为:

  • 世界标准时间 (UTC) 22:00:00
  • 太平洋标准时间 (PST) 14:00:00

注意: .in_time_zone 是来自 ActiveSupport::TimeWithZone 的帮助程序, http://api.rubyonrails.org/classes/ActiveSupport/TimeWithZone.html


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_timesbed_times = sleeps[1].map{|el| el['startTime']}.map{|el| Time.zone.parse(el.to_s) }; - user2974739
尝试在末尾添加.to_s。.map{|el| Time.zone.parse(el.to_s).to_s } - NickGnd
谢谢。最后一个问题。平均时间05:26是UTC时间。我想转换成PST时间。我尝试了Time.zone = 'Pacific Time (US & Canada)'; Time.zone.parse(avg) 2015-12-11 05:26:57 -0800,但好像没有将其转换为PST时间。 - user2974739
@user2974739 我添加了从UTC到PST时区的转换。 - NickGnd
@CarySwoveland 抱歉,Cary,我无法理解你的意思。我刚刚才看到了你的回答。 - NickGnd
显示剩余3条评论

0

据我理解,您有一个包含PST时间区域的睡觉时间UTC时间的数组arr。您希望计算平均睡眠时间。

代码

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]

回想一下,太平洋标准时间比协调世界时晚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 的第一个元素是晚睡时间,而其他所有元素都是早睡时间。

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接