Uptime Since... (#174)

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… :smiley:

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 :slight_smile:

On 8/23/08, 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.

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 Q.

-Adam S.

(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)]

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.

On Thu, Aug 28, 2008 at 11:01 AM, Matthew M. [email protected]
wrote:

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.

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

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"

On Thu, Aug 28, 2008 at 11:31 AM, Michael G. [email protected]
wrote:

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…