[QUIZ] Uptime Since... (#174)

A

Adam Shelly

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
## 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.
Here's my Windows solution. I offer it as an object lesson about why
you should always check the built-in library documentation first. I
knew that Windows could report the dates in several different formats
based on user settings. I wanted to be able to handle all of them, so
I rolled my own parser based on checking the registry to see what
format to expect. Then I discovered Time#parse....

-Adam
##########################
## Windows-uptime.rb
## Ruby Quiz #
## -Adam Shelly
## (The hard way)

#find out what form windows is going to report the date in
dateform = `reg query "HKCU\\Control Panel\\International" /v sShortDate`.chomp
dateform = /REG_SZ\t(.*)$/m.match(dateform)[1].chomp
timeform = `reg query "HKCU\\Control Panel\\International" /v
sTimeFormat`.chomp
timeform = /REG_SZ\t(.*)$/m.match(timeform)[1].chomp
timeform.gsub!(/:[sS]+/,'')
is_PM = `reg query "HKCU\\Control Panel\\International" /v s2359`.chomp
is_PM = /REG_SZ\t(.*)$/m.match(is_PM)[1].chomp

#these are the format characters it may use (sorted in descending
order by size: year -> minute)
$special="yYmMdDhHmMtT"

#build a regexp that matches the format string,
# record which order the result groups are returned in
# Assumes that there is sone separator character
# won't work if the format is something like DDMMYY
def buildQuery formatstr, indexes
idx=1
formatstr.each_byte{|b|
if $special.include?(b.chr)
indexes[b.chr.upcase]=idx
else
idx+=1
end
}
#replace all the format chars with word matchers
f = formatstr.gsub(Regexp.new("[#{$special}]"),'\w')
#make groups
f = f.gsub(/(\\w)+/,'(\w+)')
return f
end

#storage for regexp group indexes
dateidx,timeidx={},{}

#build regexp to match result
regexp = Regexp.new "since "+buildQuery(dateform, dateidx)+'
'+buildQuery(timeform, timeidx)

#since we are combining 2 regexps, the second set of groups are offset
by the number of groups in the first
timeidx.each_key{|k| timeidx[k]+=dateidx.values.max}

#do the match
datematch = regexp.match(`net stats srv`)

a=[]
idxset=dateidx
#build an array with the results of the match, in descending order,
$special.upcase.squeeze.each_byte{|b|
idxset = timeidx if b==?H #switch to time indexes when we get to Hours
a<<datematch[idxset[b.chr]]
}

#add 12 if string contains this locale's version of 'PM'
a[3]=a[3].to_i+12 if datematch[timeidx['T']]==is_PM

#convert month names to integers, if needed
# ??Question: Does strftime return names in the current locale??
(1..12).each{|m|
a[1]=m if datematch[dateidx['M']].include?(Time.utc(0,m).strftime("%b"))
}

#construct the start time, calculate seconds elapsed until now
starttime = Time.local(*a)
s=(Time.now-starttime).to_i;

#show results
print datematch[0].gsub("since", "Last reboot at")
puts ".\n #{s} seconds ago."

#expand seconds into normalized units. (Is there a library function
to do this?)
puts 'uptime = '+
[['%d seconds',60],['%d minutes',60],['%d hours',24],['%d
days',365],['%d years',1000]].map{|w,v|
s,rem=s.divmod v;
w%rem if rem>0
}.compact.reverse*' '

####################################
## Now, the Easy way
require 'Time'

datematch = /since (.*)$/.match(`net stats srv`)
s= Time.now - Time.parse(datematch[1])
print "\n"+datematch[0].gsub("since", "Last reboot at")
puts ".\n #{s.to_i} seconds ago."
puts "uptime = %.2f days."%[s/(60*60*24.0)]
 
M

Matthew Moss

require 'sys/uptime'
p Sys::Uptime.uptime

I installed rb-sys-uptime on Mac OS X, couldn't get this to work. It
recognizes Sys::Uptime, but when I try to call method 'uptime', I get:

"Sys::UptimeError: failed to extract uptime"
 
M

Matthew Moss

This works for me on OS X.
require 'time'
Time.parse `last | tail -1`

That doesn't come close to working for me on OSX. There are many more
timestamps in that file than just the reboots. The version Erik
provided works correctly.
 
M

Michael Guterl

That doesn't come close to working for me on OSX. There are many more
timestamps in that file than just the reboots. The version Erik
provided works correctly.

FWIW, `last | grep reboot` returns nothing for me on my MacBook.
 
M

Michael Guterl

FWIW, `last | grep reboot` returns nothing for me on my MacBook.
Doh, clicked send too quickly.

Also, you're right, my version doesn't seem to be working right either...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,163
Latest member
Sasha15427
Top