Ruby - 如何将 Unix 时间戳(纪元)四舍五入到最近的月份
Ruby - How to round Unix Timestamp (Epoch) to nearest month
我试图将 Ruby 中的 UNIX 时间戳四舍五入到最接近的整月。我有以下 UNIX 时间戳,我想如图所示进行转换——基本上,如果该月的第 15 天及以后,它应该四舍五入到下个月(例如,2 月 23 日四舍五入到 3 月 1 日;2 月 9 日四舍五入到 2 月 1 日)。
这是我的时间戳和我需要帮助实现的结果:
1455846925 (Feburary 19th, 2016) => 1456790400 (March 1st, 2016)
1447476352 (November 14th, 2015) => 1446336000 (November 1st, 2015)
1242487963 (May 16th, 2009) => 1243814400 (June 1st, 2009).
我完全依靠 1-14(向下舍入)/15+(向上舍入)的逻辑就可以了。我意识到这并不总是考虑到一个月中的天数,如果需要我可以接受 (尽管总是考虑到给定月份中的天数的解决方案是一种奖励).
Ruby 的 DateTime 模块也许可以结合一个月的秒数取模来完成,但我不太确定如何将它们组合在一起。如果我可以直接转换 UNIX 时间戳而不先将其转换为 Ruby 日期,那也很好。
提前感谢您的帮助。
如果您在 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
很容易将其转换为 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
这四舍五入到最接近的秒数。
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
我不知道这是否与@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
如果您希望它成为 return UNIX 时间戳,只需将 .to_i
添加到方法的最后一行即可。
我试图将 Ruby 中的 UNIX 时间戳四舍五入到最接近的整月。我有以下 UNIX 时间戳,我想如图所示进行转换——基本上,如果该月的第 15 天及以后,它应该四舍五入到下个月(例如,2 月 23 日四舍五入到 3 月 1 日;2 月 9 日四舍五入到 2 月 1 日)。
这是我的时间戳和我需要帮助实现的结果:
1455846925 (Feburary 19th, 2016) => 1456790400 (March 1st, 2016)
1447476352 (November 14th, 2015) => 1446336000 (November 1st, 2015)
1242487963 (May 16th, 2009) => 1243814400 (June 1st, 2009).
我完全依靠 1-14(向下舍入)/15+(向上舍入)的逻辑就可以了。我意识到这并不总是考虑到一个月中的天数,如果需要我可以接受 (尽管总是考虑到给定月份中的天数的解决方案是一种奖励).
Ruby 的 DateTime 模块也许可以结合一个月的秒数取模来完成,但我不太确定如何将它们组合在一起。如果我可以直接转换 UNIX 时间戳而不先将其转换为 Ruby 日期,那也很好。
提前感谢您的帮助。
如果您在 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
很容易将其转换为 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
这四舍五入到最接近的秒数。
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
我不知道这是否与@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
如果您希望它成为 return UNIX 时间戳,只需将 .to_i
添加到方法的最后一行即可。