Generate date objects in hour steps between two given dates - ruby

Given are two timestamps in the format YYYYMMDDHH, which are perfectly parseable by DateTime.strptime.
What I want to create is a list of strings in the given format from above in one hour steps, starting from the first date up to the second date.
Example input: 2013011515 and 2013011822.
Expected output: ['2013011515','2013011516','2013011517','2013011518', ... , '2013011820', '2013011820', '2013011821', '2013011822']
Is there any ruby library or core functionality to accomplish this task?

You can use step with an hourly resolution if you use ruby 1.9:
date1 = DateTime.strptime('2013011522', '%Y%m%d%H')
date2 = DateTime.strptime('2013011622', '%Y%m%d%H')
date_range = date1.step(date2, 1.0/24).to_a
Alternatively, on ruby 1.8.7, use a loop
date1 = DateTime.strptime('2013011522', '%Y%m%d%H')
date2 = DateTime.strptime('2013011622', '%Y%m%d%H')
new_date = date1
date_range = [date1]
date_range << (new_date += 1.0/24) while new_date <= date2

#!/usr/bin/env ruby
dt_from = "2013011515"
dt_to = "2013011822"
require 'date'
date_from = Date.parse(dt_from[0,8])
date_to = Date.parse(dt_to[0,8])
res = []
date = date_from
while (date <= date_to)
if date == date_from
hours = (dt_from[8,2].to_i..23).to_a
elsif date == date_to
hours = (0..dt_to[8,2].to_i).to_a
else
hours = (0..23).to_a
end
hours.each {|h| res << "#{date.strftime('%Y%m%d')}#{"%02d" % h}"}
date += 1
end
puts res.inspect

Related

Ruby - How many days?

I need to calculate how many days lived on earth based on three parameters : day, month and year.
I don't know how to convert the input onto a date; and then how to convert the date onto number of days.
This is my code for the moment...
require 'date'
def age_in_days(day, month, year)
lived = (day+"-"+month+"-"+year).to_s
date_lived Date.parse(lived)
return (Date.today - date_lived).to_i
end
You can create a Date object directly with:
Date.new(year, month, day)
There's no need to convert it to a string and parse. Parsing could also be dangerous. Is 1982-04-02 the 4th of February or 2nd of April?
You cannot add a number and string like this, BTW. Should 1 + '2' be '12' or 3? Ruby cannot decide for you so you need to explicitly convert integers to string.
day.to_s + "-" + month.to_s + "-" + year.to_s
or simply
[day, month, year].join('-')
But you don't need it anyway:
require 'date'
def age_in_days(day, month, year)
birthdate = Date.new(year, month, day)
(Date.today - birthdate).to_i
end

ruby, date string between date string range

I have two date strings :
lower_limit = '1981-03-27'
upper_limit = '1981-04-27'
and a date string:
birth_date = '1981-03-29'
How to test if birth_date is between lower_limit and upper_limit
Thanks,
This way
(Date.parse(lower_limit)..Date.parse(upper_limit)).cover?(Date.parse(birth_date))

How to select mondays with sqlite/sequel?

In my SQLite-DB I want to select all entries on a monday.
How can I do it with Sequel?
A test example:
require 'sequel'
DB = Sequel.sqlite()#'test.db')
DB.create_table(:days) do
String :text
Date :start
end
Date.today.upto(Date.today + 30){|d|
DB[:days].insert( :text => d.strftime("%Y-%m-%d day %w in week %W"), :start => d)
}
How can I select all mondays?
In native SQL I can do:
select * from days where strftime("%w", start) = "1"
Using this, I can define a view and select for it:
DB.run('create view mondays as select * from days where strftime("%w", start) = "1"')
p DB[:mondays].all
But I would like to use it from Sequel.
I tried
sel = DB[:days].filter{ start.strftime("%w", :start) == '1' }
#NoMethodError
sel = DB[:days].filter{ Sequel::SQL::Function.new(:strftime, "%w", :start) == '1' }
#SELECT * FROM `days` WHERE (1 = 0)
but without success.
Are there any other solutions?
I'm looking also for a possibility to select items by hour of day (all items with a timestamp, and then from 12:00-13:00 ...) I think this is the same problem and a solution for the day of week-selection will also solve my other problem.
Here are the problems with your examples:
sel = DB[:days].filter{ start.strftime("%w", :start) == '1' }
#NoMethodError
This uses a virtual row, so calling start returns a Sequel::SQL::Identifier. The Sequel::SQL::Identifier#strftime method does not exist, hence the NoMethodError.
sel = DB[:days].filter{ Sequel::SQL::Function.new(:strftime, "%w", :start) == '1' }
#SELECT * FROM `days` WHERE (1 = 0)
This fails because you are using ==. Sequel doesn't override ==, and ruby's default == returns false. On SQLite, Sequel represents false as (1 = 0).
This should work:
sel = DB[:days].filter{{strftime("%w", :start) => '1'}}
# SELECT * FROM `days` WHERE (strftime('%w', `start`) = '1')
This uses a hash (the inner {}) inside a virtual row block (the outer {}). In Sequel, equality is represented by hashes.

Searching between two dates with Ruby IMAP

I am new to Ruby, I'm trying to return the number of emails between 9am and 11am.
For example.
#received_today = imap.search(["SINCE", #today.strftime("%d-%b-%Y-%H"):"BEFORE", #today.strftime("%d-%b-%Y-%H")]).count.to_s
I know this is wrong, but it's my closest guess on how to do this. Any help would be highly appreciated.
Maybe something like this:
require 'date'
start_time = Net::IMAP.format_datetime(DateTime.strptime("09:00", "%H:%M"))
end_time = Net::IMAP.format_datetime(DateTime.strptime("11:00", "%H:%M"))
#received_today = imap.search(["SINCE", start_time, "BEFORE", end_time ]).count
UPDATE:
Try #2 :)
Since imap SEARCH command ignores the time part in SINCE and BEFORE conditions this should work:
require 'date'
today = Net::IMAP.format_date(Date.today)
start_time = DateTime.strptime("09:00", "%H:%M")
end_time = DateTime.strptime("11:00", "%H:%M")
#received_today = imap.search(["ON", today]) # get sequence nums of todays emails
# fetch the INTERNALDATE-s and count the ones in the timeframe
count = imap.fetch(#received_today, "INTERNALDATE").count{ |data|
time = DateTime.parse(data.attr["INTERNALDATE"])
time.between? start_time, end_time
}

BETWEEN EQUIVALENT in LINQ

I am looking LINQ equivalent for the following query
Select * from ct_rate
WHERE
'2010-10-01 00:00:00'
BETWEEN start_date and end_date;
ANY IDEA?
You need to use two comparison operations:
DateTime date = new DateTime(2010, 10, 1);
var results = from rate in ct_rates
where rate.StartDate <= date && rate.EndDate >= date
select rate;
Just use ordinary comparison operators
var result = ct_rates
.Where(x => x.start_date <= myDate && x => x.endDate >= myDate);
In our case, Robert's answer was close to what I was looking for. In our data model, our 'end' or 'through' date columns are nullable.
Something like the following was needed:
Category.Where(
w => w.ValidFrom <= now &&
(w.ValidThru == null ? DateTime.MaxValue : w.ValidThru) >= now).Select(s => s).Dump();
I found this works when wanting only to compare the data part.
var results = from rate in ct_rates
where rate.StartDate.Date <= date && rate.EndDate.Date >= date
select rate;
something like this?
var result = from context.ct_rate.Where(d => d.start_date >= "2010-10-01 00:00:00" && d.end_date <= "2010-10-01 00:00:00")

Resources