I'm looking for a concise way to get a Ruby Time
object representing the top of the next minute (and hour/day/month/year, if possible). I want this to work in a pure Ruby environment, so the Rails function Time.change
or similar doesn't fit the bill.
At first this seems simple - just add 1 to Time.now
, but there are edge cases where if, for example, you try to instantiate a Time
object with Time.now.min + 1
when the current minute is 59, you get an ArgumentError: min out of range
. This goes for hour, day, and month as well.
I have some lengthy code that does the job. It's ugly, but I'm just experimenting:
def add_minute
now = Time.local
year = now.year
month = now.month
day = now.day
hour = now.hour
min = now.min
if now.min == 59
if now.hour == 23
if now.day == Date.civil(now.year, now.month, -1).day
if month == 12
year = year + 1
month = 1
day = 1
hour = 0
min = 0
else
month = now.month + 1
day = 1
hour = 0
min = 0
end
else
day = now.day + 1
hour = 0
min = 0
end
else
hour = now.hour + 1
min = 0
end
else
min = now.min + 1
end
Time.local year, month, day, hour, min, 0
end
This seems absurdly verbose for what seems like it should be a simple or built-in task, but I haven't found a native Ruby solution. Does one exist?
You could convert the Time
object to UNIX epoch time (seconds since 1970) using #to_i
, add 60 s, and then convert back to a Time
object.
time_unix = Time.now.to_i
time_unix_one_min_later = time_unix + 60
time_one_min_later = t = Time.at(time_unix_one_min_later)
time_one_min_later_rounded_down = Time.new(t.year, t.month, t.day, t.hour, t.min)
EDIT: Even shorter - you can just add integer seconds to Time.now
directly:
time_one_min_later = t = Time.now + 60
time_one_min_later_rounded_down = Time.new(t.year, t.month, t.day, t.hour, t.min)
EDIT 2: One-liner - just subtract Time.now.sec
:
time_one_min_later_rounded_down = Time.now + 60 - Time.now.sec