From: Adam Shelly Date: 2008-08-27T05:11:02+09:00 Subject: Re: [QUIZ] Uptime Since... (#174) On 8/23/08, Matthew Moss 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 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<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)]