-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
The three rules of Ruby Q. 2:
-
Please do not post any solutions or spoiler discussion for this
quiz until 48 hours have passed from the time on this message.
-
Support Ruby Q. 2 by submitting ideas as often as you can! (A
permanent, new website is in the works for Ruby Q. 2. Until then,
please visit the temporary website at
http://splatbang.com/rubyquiz/.
-
Enjoy!
Suggestion: A [QUIZ] in the subject of emails about the problem
helps everyone on Ruby T. follow the discussion. Please reply to
the original quiz message, if you can.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Uptime Since… (#174)
Nice and easy one this week. Your task is to write a Ruby script that
reports the date and time of your last reboot, making use of the
uptime
command.
While uptime
is available on the various Unixes and Mac OS X,
Windows users might need to do a little extra work. Here are two
options for Windows users.
My own solution:
require ‘date’
(now, _, dd, _, _, dhm) = uptime
.split(/ +|,/)
(dd, dh, dm) = dd.to_i, *dhm.split(’:’).map { |x| x.to_i }
dh += (dm / 60.0)
dd += (dh / 24.0)
last = DateTime.parse(now) - dd
puts “Last reboot: #{last.year} #{Date::ABBR_MONTHNAMES[last.mon]}
#{last.day} at #{last.hour}:#{last.min}”
On Sat, Aug 23, 2008 at 9:35 AM, Matthew M. [email protected]
wrote:
Uptime Since… (#174)
A windows solution.
require ‘rubygems’
require ‘ruby-wmi’
require ‘date’
str = WMI::Win32_OperatingSystem.find(:first).LastBootupTime
boot = DateTime.strptime(str, “%Y%m%d%H%M”)
boot_date = boot.strftime("%Y %b")
boot_time = boot.strftime("%I:%M")
puts “Last reboot: #{boot_date} at #{boot_time}”
And my try at this:
coeff = [60,3600]; i = 0; offset = 0
s = %x{uptime}
coeff.push 86400 if s =~ /day/
s.scan(/\d+/) do #I don’t know how to stop scanning when I’ve had
enough ^^;;
|text|
i = i + 1
offset = offset + text.to_i*(coeff.pop||0) if (3…5) === i
end
puts (Time.now - offset).strftime(“System booted at %H:%M of %A, %B %d
(%Y)”)
(I don’t know anything about regexp, and it shows)
My solution:
====
SecsPerMinute = 60
SecsPerHour = 60SecsPerMinute
SecsPerDay = 24SecsPerHour
match = /up (\d+) days, (\d+):(\d+),/.match %x{uptime}
extract data from reg. exp. and convert to integers
days, hours, minutes = *((1…3).map { |index| match[index].to_i })
now = Time.now
now -= now.sec # normalize to 0 seconds into the current minute
boot_time = now - daysSecsPerDay - hoursSecsPerHour -
minutes*SecsPerMinute
boot_time_s = boot_time.strftime("%a %b %e %l:%M %p")
puts “Machine last booted: #{boot_time_s} (+/- 1 minute).”
====
Eric
====
On-site, hands-on Ruby and Ruby on Rails training is
available from http://LearnRuby.com !
On Sat, Aug 23, 2008 at 4:35 PM, Matthew M. [email protected]
wrote:
Uptime Since… (#174)
Nice and easy one this week. Your task is to write a Ruby script that
reports the date and time of your last reboot, making use of the
uptime
command.
My solution, tested in Ubuntu 8.04 and Fedora Core 2:
uptime = (uptime
.match /up (.*),.*user/)[1].delete(" ")
captures = (uptime.match /((\d+)days,)?(\d+):(\d+)/).captures[1…-1]
elapsed_seconds = captures.zip([86440, 3600, 60]).inject(0) do |total,
(x,y)|
total + (x.nil? ? 0 : x.to_i * y)
end
puts “Last reboot was on #{Time.now - elapsed_seconds}”
Nice quiz !!!
Jesus.
Here’s a one-liner using /proc/uptime:
puts Time.now - File.read(’/proc/uptime’).match(/^(\d+.\d+) /)[1].to_f
Mine (Only tested on a couple of Linux boxes):
if uptime
.include? “day”
puts(Time.now - ((uptime
.split[2].to_i * 1440) +
(uptime
.split[4].split(":")[0].to_i * 60) +
(uptime
.split[4].split(":")[1].to_i)) * 60)
elsif uptime
.include? “min”
puts(Time.now - uptime
.split[2].split(":")[0].to_i * 60)
else
puts(Time.now - (uptime
.split[2].split(":")[0].to_i * 60) +
(uptime
.split[2].split(":")[1].to_i))
end
On Tue, Aug 26, 2008 at 01:30:50AM +0900, Eric I. wrote:
extract data from reg. exp. and convert to integers
====
Eric
====
On-site, hands-on Ruby and Ruby on Rails training is
available from http://LearnRuby.com !
–
nathan
nathan_at_nathanpowell_dot_org
To give anything less than your best is to sacrifice the gift.
~ Steve Prefontaine
On Aug 23, 8:35 am, “Matthew M.” [email protected] wrote:
Uptime Since… (#174)
Nice and easy one this week. Your task is to write a Ruby script that
reports the date and time of your last reboot, making use of the
uptime
command.
require ‘sys/uptime’
p Sys::Uptime.uptime

Regards,
Dan
PS - No parsing involved. Uses sysctl/times/wmi, depending on platform.
Nathan Powell wrote:
Mine (Only tested on a couple of Linux boxes):
if uptime
.include? “day”
puts(Time.now - ((uptime
.split[2].to_i * 1440) + (uptime
.split[4].split(":")[0].to_i * 60) + (uptime
.split[4].split(":")[1].to_i)) * 60)
elsif uptime
.include? “min”
puts(Time.now - uptime
.split[2].split(":")[0].to_i * 60)
else
puts(Time.now - (uptime
.split[2].split(":")[0].to_i * 60) + (uptime
.split[2].split(":")[1].to_i))
end
I may be wrong, but won’t the results from this be skewed because you
are
running uptime several times (and presumably the resulting data will be
different each time you run it)?
It’s not like that couldn’t be fixed very easily by just assigning a
variable.
Nice solution, though!
-Dana
Matthew M. wrote:
Nice and easy one this week. Your task is to write a Ruby script that
reports the date and time of your last reboot, making use of the
uptime
command.
While uptime
is available on the various Unixes and Mac OS X,
Windows users might need to do a little extra work. Here are [two][1]
[options][2] for Windows users.
last | grep reboot | head -1
Am I doing it right? 
-Erik
Matthew M. wrote:
Nice and easy one this week. Your task is to write a Ruby script that
reports the date and time of your last reboot, making use of the
uptime
command.
Why use uptime
when there’s who -b
?
Here is my solution. It should run out of the box (i.e. no gems needed)
on all major platforms.
require ‘time’
methods = [
lambda { # Windows
require ‘Win32API’
getTickCount = Win32API.new(“kernel32”, “GetTickCount”, nil, ‘L’)
Time.now - getTickCount.call() / 1000.0
},
lambda { # *BSD, including Mac OS
Time.at(sysctl -b kern.boottime 2>/dev/null
.unpack(‘L’).first)
},
lambda { # Some other form of *nix
Time.parse(who -b 2>/dev/null
)
}
]
begin
unless methods.empty?
boot_time = methods.shift.call
else
puts “Unable to determine time of last reboot. Sorry!”
exit!(1)
end
rescue Exception
retry
end
puts “Last reboot: #{boot_time.asctime}”
Regards,
Matthias
On Mon, Aug 25, 2008 at 6:12 PM, Erik H. [email protected]
wrote:
last | grep reboot | head -1
Am I doing it right? 
This works for me on OS X.
require ‘time’
Time.parse last | tail -1
Michael G.
Jesús Gabriel y Galán wrote:
I realized that there was a case I wasn’t taking into account: a machine
booted
less than 1 hour ago.
And I missed the case of an uptime between 24 and 25 hours. (On OSX, at
least). Which makes my solution fail quite badly in that time bracket.
On Mon, Aug 25, 2008 at 7:30 PM, Jesús Gabriel y
Galán[email protected] wrote:
uptime = (uptime
.match /up (.*),.*user/)[1].delete(" ")
captures = (uptime.match /((\d+)days,)?(\d+):(\d+)/).captures[1…-1]
elapsed_seconds = captures.zip([86440, 3600, 60]).inject(0) do |total, (x,y)|
total + (x.nil? ? 0 : x.to_i * y)
end
puts “Last reboot was on #{Time.now - elapsed_seconds}”
I realized that there was a case I wasn’t taking into account: a machine
booted
less than 1 hour ago. So here is my revised solution, also compacting a
little
bit things, using only one regexp:
captures = (uptime
.match /up (?:(?:(\d+) days,)?\s+(\d+):(\d+)|(\d+)
min)/).captures
elapsed_seconds = captures.zip([86440, 3600, 60, 60]).inject(0) do
|total, (x,y)|
total + (x.nil? ? 0 : x.to_i * y)
end
puts “Last reboot was on #{Time.now - elapsed_seconds}”
Anybody knows what’s the format for a machine that’s been up more than
a day, but less than two?
Is it “up 1 day” or “up 1 days”? Anyway I’m thinking changing that
part of the regexp to “day(?:s)?”
should suffice to take into account both cases, but I can’t test it
right now.
Jesus.
Le 23 août 2008 à 16:35, Matthew M. a écrit :
A solution tested with windows uptime.exe, FreeBSD and Linux. It should
work with most of the others and in most of the edge cases, I think.
#! /usr/local/bin/ruby
def startup(t)
u = (t.downcase.match(/up(.?)(?:\d+ user.)?$/)[1])
lu = u.split(/([0-9:]+)/).map { |e| e.strip.gsub(/,/, ‘’) }.reject {
|e| e == ‘’ }
count = 0
lu.each_index do |i|
count += case lu[i]
when /(\d+):(\d+)(?::(\d+))?/
$1.to_i * 3600 + $2.to_i * 60 + ($3 ? $3.to_i : 0)
when /(\d+)/
n = lu[i].to_i
case lu[i + 1]
when nil then raise “Unknown format”
when /^day/ then n * 86400
when /^hour/ then n * 3600
when /^min/ then n * 60
when /^sec/ then n
else raise “Unknown modifier (#{lu[i + 1]})”
end
else
0
end
end
Time.now - count
end
[ uptime
,
‘11:40:08 up 15 days, 16:08, 1 user,2 load average: 0.06, 0.04,
0.01’,
‘\LAPHROAIG has been up for: 25 day(s), 13 hour(s), 46 minute(s), 10
second(s)’
].each { |c| puts startup©.strftime(’%c’) }
12:09 [email protected]:~/ruby> ./uptime.rb
Wed Jun 25 07:05:41 2008
Sun Aug 10 20:01:41 2008
Thu Jul 31 22:23:31 2008
Fred
Jesús Gabriel y Galán wrote:
Anybody knows what’s the format for a machine that’s been up more than
a day, but less than two?
Is it “up 1 day” or “up 1 days”? Anyway I’m thinking changing that
part of the regexp to “day(?:s)?”
should suffice to take into account both cases, but I can’t test it
right now.
On the machines I know (several *nixes) it is neither “up 1 day” nor “up
1 days”, but “up 1 day(s)”. To make matters worse some versions of
uptime
yield a localized message:
1:49pm in Betrieb 6 Tag(e), 9:12, 12 Benutzer, Durchschnittslast:
3,11, 3,13, 3,19
Maybe a more general approach is needed to account for these corner
cases.
Matthew M. wrote:
On Aug 25, 11:20�pm, Matthias R. [email protected] wrote:
Matthew M. wrote:
Nice and easy one this week. Your task is to write a Ruby script that
reports the date and time of your last reboot, making use of �the
uptime
command.
Why use uptime
when there’s who -b
?
Because uptime
is what I requested… 
Sometimes it’s not about the final result, but about the process.
Yep, this is a “count backwards in time” exercise slightly obfuscated.
My “solution” was a bit of a joke, and I apologize for the mess I’ve
caused.
On Aug 25, 11:20 pm, Matthias R. [email protected] wrote:
Matthew M. wrote:
Nice and easy one this week. Your task is to write a Ruby script that
reports the date and time of your last reboot, making use of the
uptime
command.
Why use uptime
when there’s who -b
?
Because uptime
is what I requested… 
Sometimes it’s not about the final result, but about the process.
On Aug 26, 10:44 am, Matthias R. [email protected] wrote:
Sometimes it’s not about the final result, but about the process.
I know, I know. I guess I just wanted to make my life a bit easier
there 
No worries. I’m not deducting any points this week. 