Ruby - 如何将Unix时间戳(Epoch)舍入到最接近的月份

时间:2016-02-19 02:08:55

标签: ruby rounding unix-timestamp epoch datetimeoffset

我试图将Ruby中的UNIX时间戳舍入到最近的整月。我有以下UNIX时间戳,我想转换如图所示 - 基本上如果该月的日期是15日及以后,它应该舍入到下个月(例如2月23日轮到3月1日; 2月9日轮到2月1日)。

以下是我的时间戳以及我需要帮助实现的结果:

  

1455846925(2016年2月19日)=> 1456790400(2016年3月1日)

     

1447476352(2015年11月14日)=> 1446336000(2015年11月1日)

     

1242487963(2009年5月16日)=> 1243814400(2009年6月1日)。

我可以完全依赖1-14(向下舍入)/ 15+(向上舍入)的逻辑。我意识到这并不总是考虑到一个月内的日子,如果需要我可以接受(虽然总是考虑到给定月份的天数的解决方案是奖金)

Ruby的DateTime模块可能能够与一个月内的秒数模数结合使用,但我不太确定如何将它们放在一起。如果我可以直接转换UNIX时间戳而不先将其转换为Ruby Date,那也完全没问题。

提前感谢您的协助。

4 个答案:

答案 0 :(得分:3)

这一轮到最接近的秒数。

require 'time'

def round_to_month(secs)
  t1 = Time.at secs
  t2 = (t1.to_datetime >> 1).to_time
  s1 = Time.new(t1.year, month=t1.month)
  s2 = Time.new(t2.year, month=t2.month)
  (t1-s1) < (s2-t1) ? s1 : s2
end

round_to_month(1455846925) # round 2016-02-18 17:55:25 -0800 
  #=> 2016-03-01 00:00:00 -0800
round_to_month(1447476352) # round 2015-11-13 20:45:52 -0800
  #=> 2015-11-01 00:00:00 -0700 
round_to_month(1242487963) # round 2009-05-16 08:32:43 -0700 
  #=> 2009-05-01 00:00:00 -0700 

考虑

secs = 1455846925

计算如下:

 t1 = Time.at secs
   #=> 2016-02-18 17:55:25 -0800 
 dt = t1.to_datetime
   #=> #<DateTime: 2016-02-18T17:55:25-08:00 ((2457438j,6925s,0n),-28800s,2299161j)> 
 dt_next = dt >> 1
   #=> #<DateTime: 2016-03-18T17:55:25-08:00 ((2457467j,6925s,0n),-28800s,2299161j)> 
 t2 = dt_next.to_time 
   #=> 2016-03-18 18:55:25 -0700 
 s1 = Time.new(t1.year, month=t1.month)
   #=> Time.new(2016, month=2) 
   #=> 2016-02-01 00:00:00 -0800 
 s2 = Time.new(t2.year, month=t2.month)
   # Time.new(2016, month=3)
   #=> 2016-03-01 00:00:00 -0800 
 (t1-s1) < (s2-t1) ? s1 : s2
   #=> 1533325.0 < 972275.0 ? 2016-02-18 17:55:25 -0800 : 2016-03-01 00:00:00 -0800
   #=> 2016-03-01 00:00:00 -0800

答案 1 :(得分:1)

很容易将其转换为Time对象,然后将其转换回timestamp

如果你正在使用Rails,这个方法应该做你想要的:

def nearest_month(t)
  time = Time.at(t).utc
  time = time.next_month if time.day >= 15

  time.beginning_of_month.to_i
end

答案 2 :(得分:1)

我不知道这是否与@ CarySwoveland的解决方案一样准确,但我喜欢它:

require 'time'

FIFTEEN_DAYS = 15 * 24 * 60 * 60

def round_to_month(secs)
  t1 = Time.at(secs + FIFTEEN_DAYS)
  Time.new(t1.year, t1.month)
end

p round_to_month(1455846925) # round 2016-02-18 17:55:25 -0800 
# => 2016-03-01 00:00:00 -0800

p round_to_month(1447476352) # round 2015-11-13 20:45:52 -0800
# => 2015-11-01 00:00:00 -0700

p round_to_month(1242487963) # round 2009-05-16 08:32:43 -0700 
# => 2009-05-01 00:00:00 -0700

如果您希望它返回UNIX时间戳,而只是将.to_i添加到方法的最后一行。

答案 3 :(得分:0)

如果你在Rails中使用ActiveSupport,那么这样的东西会起作用:

require 'date'    

def round_to_nearest_month(timestamp)

  # Convert the unix timestamp into a Ruby DateTime object
  datetime = timestamp.to_datetime

  # Get the day of the month from the datetime object
  day_of_month = datetime.mday

  if day_of_month < 15
    datetime.at_beginning_of_month
  else 
    datetime.at_beginning_of_month.next_month
  end    

  return datetime

end