Delete files older than last 14 days in windows IIS server - ruby

I want to write a recipe in Chef to delete all files mentioned in C:\inetpub\logs\LogFiles\W3SVC1 which are older than 14 days.
So at any given day I should not have files older than 2 weeks.
Dir['C:\inetpub\logs\LogFiles\W3SVC1\*.log'].each do |path|
file path do
action :delete
backup false
only_if { ###not sure how to include the timestamp### }
end
end

I thing that you can do something like this:
For getting the time in a file
[7] pry(main)> ::File.stat("/Users/toni/certs/openconnect_mac_scripts/openConnectMac.sh").ctime
=> 2020-11-22 07:13:57.367508716 +0100
Now time:
[8] pry(main)> Time.now
=> 2021-01-13 18:27:31.472653 +0100
calculating date (60 * 60 * 24 * 14) seconds, minutes, hours, days
[2] pry(main)> (Time.now - (60 * 60 * 24 * 14))
=> 2020-12-30 18:17:18.1294 +0100
Then in ruby you can compare times mith < and > so:
you will get:
Dir['C:\inetpub\logs\LogFiles\W3SVC1\*.log'].each do |path|
file path do
action :delete
only_if { ::File.stat(path).ctime < (Time.now - (60 * 60 * 24 * 14) ) }
end
end

Related

Wrong time difference value in Ruby

I'm trying to add a countdown and I need to calculate the remaining time in millisecond.
Basically I have a button that user can press 24 hours after the last press.
I have
last_press
# => Mon, 10 Jan 2022 10:31:25.000000000 UTC +00:00
And the time difference.
I add 1 day to the last press and I remove the current time
Time.now
# => 2022-01-10 11:50:59 +0100
time_diff = last_press + 1.day - Time.now
If I parse the result is
Time.at(time_diff.to_i.abs).utc.strftime "%H:%M:%S"
# => "00:09:24"
The issue is that time_diff is a float
time_diff = last_meditation + 1.day - Time.now
# => 85180.960988
Basically the calculation is wrong... and I cannot understand why.

Get time in seconds from string and add to current time?

timestr = '15h 37m 5s'
I want to get the hours minutes and seconds from the above string and add it to current time.
def next_run
timestr = '15h 37m 5s'
timearr = timestr.split(' ').map { |t| t.to_i }
case timearr.count
when 3
next_ = (timearr[0] * 3600) + (timearr[1] * 60) + timearr[2]
when 2
next_ = (timearr[1] * 60) + timearr[2]
when 1
next_ = timearr[2]
else
raise 'Unknown length for timestr'
end
time_to_run_in_secs = next_
end
Now I get the total seconds. I want to make it into hours minutes and seconds, then add it to current time to get next run time. Is there any easy way to do this?
The following method can be used to compute the the numbers of seconds from the string.
def seconds(str)
3600 * str[/\d+h/].to_i + 60 * str[/\d+m/].to_i + str[/\d+s/].to_i
end
Note nil.to_i #=>0. A slight variant would be to write 3600 * (str[/\d+h/] || 0) +....
Then
Time.now + seconds(str)
Examples of possible values of str are as follows: ”3h 26m 41s”, ”3h 26m”, ”3h 41s”, ”41s 3h”, ”3h”,”41s” and ””.
One could instead write the operative line of the method as follows.
%w| s m h |.each_with_index.sum { |s,i| 60**i * str[/\d+#{s}/].to_i }
Though DRYer, I find that less readable.
DateTime#+ accepts Rational instance as days to be added. All you need as you have seconds would be to convert it to a number of days and plain add to the current timestamp:
DateTime.now.tap do |dt|
break [dt, dt + Rational(100, 3600 * 24) ]
end
#⇒ [
# [0] #<DateTime: 2018-05-27T11:13:00+02:00 ((2458266j,33180s,662475814n),+7200s,2299161j)>,
# [1] #<DateTime: 2018-05-27T11:14:40+02:00 ((2458266j,33280s,662475814n),+7200s,2299161j)>
# ]
you can convert your string into seconds from this method
def seconds(str)
(3600 * str[/\d+(h|H)/].to_i) + (60 * str[/\d+(m|M)/].to_i) + (str[/\d+(s|S)/].to_i)
end
and then convert current time to seconds using method
next_run_time = Time.now.to_i + seconds(<Your Time String>)
now get next run time using
Time.at(next_run_time)
get desired format of time by using strftime method, in your case
Time.at(next_run_time).strftime("%Hh %Mm %Ss")
If you don't need to parse the duration of time, and just want to define it in your code, use ActiveSupport::Duration for readability . (add the gem to your Gemfile, and read the guide on how to use it)
Then you can use it like this:
require 'active_support'
require 'active_support/core_ext/integer'
DURATION = 15.hours + 37.minutes + 5.seconds
# use DURATION.seconds or DURATION.to_i to get the seconds
def next_run
Time.now + DURATION
end
See the API documentation of ActiveSupport::Duration
If you need to define the next run by a user input, it's a good practice to use ISO 8601 to define a duration of time: https://en.wikipedia.org/wiki/ISO_8601#Durations
ISO 8601 durations are parseable:
ActiveSupport::Duration.parse('PT15H37M5S') # => 15 hours, 37 minutes, and 5 seconds (duration)
Firstly instead of spliting the string, you can use Time#parse method. Make sure you have required the library as well.
require 'time'
=> true
Time.parse('15h 37m 5s')
=> 2018-05-27 15:37:05 +0300
This returns a new object of class Time and it has some really useful methods for you - #sec, #min, #hour.
time = Time.parse('15h 37m 5s')
time.sec #=> 5
time.min #=> 37
time.hour #=> 15
Adding adding one Time object to another is pretty straightforward since you can do it only by seconds. A simple solution for the current problem would be:
def next_run
time = Time.parse('15h 37m 5s')
seconds_to_add = time.hour * 3600 + time.min * 60 + time.sec
Time.now + seconds_to_add
end
Hopefully this will answer your question! :)

How do I add two weeks to Time.now?

How can I add two weeks to the current Time.now in Ruby? I have a small Sinatra project that uses DataMapper and before saving, I have a field populated with the current time PLUS two weeks, but is not working as needed. Any help is greatly appreciated! I get the following error:
NoMethodError at /
undefined method `weeks' for 2:Fixnum
Here is the code for the Model:
class Job
include DataMapper::Resource
property :id, Serial
property :position, String
property :location, String
property :email, String
property :phone, String
property :description, Text
property :expires_on, Date
property :status, Boolean
property :created_on, DateTime
property :updated_at, DateTime
before :save do
t = Time.now
self.expires_on = t + 2.week
self.status = '0'
end
end
You don't have such nice helpers in plain Ruby. You can add seconds:
Time.now + (2*7*24*60*60)
But, fortunately, there are many date helper libraries out there (or build your own ;) )
Ruby Date class has methods to add days and months in addition to seconds in Time.
An example:
require 'date'
t = DateTime.now
puts t # => 2011-05-06T11:42:26+03:00
# Add 14 days
puts t + 14 # => 2011-05-20T11:42:26+03:00
# Add 2 months
puts t >> 2 # => 2011-07-06T11:42:26+03:00
# And if needed, make Time object out of it
(t + 14).to_time # => 2011-05-20 11:42:26 +0300
require 'rubygems'
require 'active_support/core_ext/numeric/time'
self.expires = 2.weeks.from_now
You have to use seconds to do calculation between dates, but you can use the Time class as a helper to get the seconds from the date part elements.
Time.now + 2.week.to_i
EDIT: As mentioned by #iain you will need Active Support to accomplish usign 2.week.to_i, if you can't (or don't want to) have this dependency you can always use the + operator to add seconds to a Time instance (time + numeric → time docs here)
Time.now + (60 * 60 * 24 * 7 * 2)
I think week/weeks is defined in the active support numeric extension
$ ruby -e 'p Time.now'
2011-05-05 22:27:04 -0400
$ ruby -r active_support/core_ext/numeric -e 'p Time.now + 2.weeks'
2011-05-19 22:27:07 -0400
You can use these 3 patterns
# you have NoMethod Error undefined method
require 'active_support/all'
# Tue, 28 Nov 2017 11:46:37 +0900
Time.now + 2.weeks
# Tue, 28 Nov 2017 11:46:37 +0900
Time.now + 2.week
# Tue Nov 28 11:48:24 +0900 2017
2.weeks.from_now
<%current_time=Time.now
current_time_s=current_time.strftime('%Y-%m-%d %H:%M:%S').to_s #show currrent date time
current_time= Time.now + (60 * 60 * 24 * 7 * 250)
current_time_e=current_time.strftime('%Y-%m-%d %H:%M:%S').to_s #show datetime after week
%>
I like mine too :)
def minor?(dob)
n = DateTime.now
a = DateTime.parse(dob)
a >> 12*18 > n
end
Saves you the trouble of thinking about leap years and seconds. Just works out of the box.

range based on date when not within a month doesn't work (ruby)

I want to find out files that are older than x days (time and weekends don't count for the purpose of calculating a file's age). I need to use only weekdays.
My script is working but only if the date from the range are within the same month. Otherwise the range size is 0.
I run the script via ruby 1.8.7 (2008-08-11 patchlevel 72) [x86_64-linux]
Dir['*.gdb'].each { |db|
puts db
puts ((Date.strptime(File.mtime(db).strftime("%Y-%m-%d")))..(Date.today)).select {|d| (1..5).include?(d.wday) }.size
}
any idea how I can make it work?
To find files older than X days eg 7 days
x=7
t=Time.now
days=t - (x * 86400)
Dir["*.gdb"].each do |db|
if File.mtime(db) < days
puts db
end
end
To exclude weekends
t=Time.now # get current date
days=t - (7 * 86400) # get date 7 days before
Dir["*.gdb"].each do |db|
wd=File.mtime(db).wday # get the wday of file. 1 (monday), ... 5 (friday)
if File.mtime(db) < days and wd.between?(1,5)
# File.mtime(db) < days means get files older than 7 days
# at the same time check the wday of the file whether they are in 1..5 range
# using wd.between?(1,5)
puts db
end
end
so the final code that deletes all files from
settings['path']
that are older than settings['days'] - weekend days are not counted
and are not in settings['exclude'] array
-
require 'date'
settings = {
'radek' => { 'path' => '/var/lib/firebird/data/radek*.gdb','days' => '3','exclude'=>['radek_rft.gdb','radek_tmp.gdb','radek_test.gdb','radek_cmapping.gdb'] }
}
settings.each_value { |user|
user['exclude'].collect! {|file| file.downcase }
Dir[user['path']].each { |db|
old = ( (Date.strptime(File.mtime(db).strftime("%Y-%m-%d")))..(Date.today)).select {|d| (1..5).include?(d.wday) }.size - 1
if (old.to_i >= user['days'].to_i) and not(user['exclude'].include?(File.basename(db))) then output= %x[rm #{db}] end
}
}

Ruby: Convert time to seconds?

How can I convert a time like 10:30 to seconds? Is there some sort of built in Ruby function to handle that?
Basically trying to figure out the number of seconds from midnight (00:00) to a specific time in the day (such as 10:30, or 18:45).
You can use DateTime#parse to turn a string into a DateTime object, and then multiply the hour by 3600 and the minute by 60 to get the number of seconds:
require 'date'
# DateTime.parse throws ArgumentError if it can't parse the string
if dt = DateTime.parse("10:30") rescue false
seconds = dt.hour * 3600 + dt.min * 60 #=> 37800
end
As jleedev pointed out in the comments, you could also use Time#seconds_since_midnight if you have ActiveSupport:
require 'active_support'
Time.parse("10:30").seconds_since_midnight #=> 37800.0
Yet another implementation:
Time.now.to_i - Date.today.to_time.to_i # seconds since midnight
The built in time library extends the Time class to parse strings, so you could use that. They're ultimately represented as seconds since the UNIX epoch, so converting to integers and subtracting should get you what you want.
require 'time'
m = Time.parse('00:00')
t = Time.parse('10:30')
(t.to_i - m.to_i)
=> 37800
There's also some sugar in ActiveSupport to handle these types of things.
Perhaps there is a more succinct way, but:
t = Time.parse("18:35")
s = t.hour * 60 * 60 + t.min * 60 + t.sec
would do the trick.
You can simply use
Time.parse("10:30").seconds_since_midnight
I like these answers very much, especially Teddy's for its tidyness.
There's one thing to note. Teddy's answer gives second of day in current region and I haven't been able to convert Date.today.to_time to UTC. I ended up with this workaround:
Time.now.to_i % 86400
It's based on the fact that Time.now.to_i gives seconds since Unix Epoch which is always 1970-01-01T00:00:00Z, regardless of your current time zone. And the fact that there's 86400 seconds in a day as well. So this solution will always give you seconds since last UTC midnight.
require 'time'
def seconds_since_midnight(time)
Time.parse(time).hour * 3600 + Time.parse(time).min * 60 + Time.parse(time).sec
end
puts seconds_since_midnight("18:46")
All great answers, this is what I ended up using.
In plain ruby the fastest is the sum of time parts:
require 'benchmark'
require 'time'
Benchmark.bm do |x|
x.report('date') { 100_000.times { Time.now.to_i - Date.today.to_time.to_i } }
x.report('parse') { 100_000.times { Time.now.to_i - Time.parse('00:00').to_i } }
x.report('sum') { 100_000.times { Time.now.hour * 3600 + Time.now.min * 60 + Time.now.sec } }
end
user system total real
date 0.820000 0.000000 0.820000 ( 0.822578)
parse 1.510000 0.000000 1.510000 ( 1.516117)
sum 0.270000 0.000000 0.270000 ( 0.268540)
So, here is a method that takes timezone into account, if needed
def seconds_since_midnight(time: Time.now, utc: true)
time = time.utc if utc
time.hour * 3600 + time.min * 60 + time.sec
end

Resources