How do I count the number of days between these two dates?
start_date = Date.parse "2012-03-02 14:46:21 +0100"
end_date = Date.parse "2012-04-02 14:46:21 +0200"
With the Date (and DateTime) classes you can do (end_date - start_date).to_i to get the number of days difference.
Assuming that end_date and start_date are both of class ActiveSupport::TimeWithZone in Rails, then you can use:
(end_date.to_date - start_date.to_date).to_i
Rails has some built in helpers that might solve this for you. One thing to keep in mind is that this is part of the Actionview Helpers, so they wont be available directly from the console.
Try this
<% start_time = "2012-03-02 14:46:21 +0100" %>
<% end_time = "2012-04-02 14:46:21 +0200" %>
<%= distance_of_time_in_words(start_time, end_time) %>
"about 1 month"
I kept getting results in seconds, so this worked for me:
(Time.now - self.created_at) / 86400
to get the number of days in a time range (just a count of all days)
(start_date..end_date).count
(start_date..end_date).to_a.size
#=> 32
to get the number of days between 2 dates
(start_date...end_date).count
(start_date...end_date).to_a.size
#=> 31
None of the previous answers (to this date) gives the correct difference in days between two dates.
The one that comes closest is by thatdankent. A full answer would convert to_i and then divide:
(Time.now.to_i - 23.hours.ago.to_i) / 86400
>> 0
(Time.now.to_i - 25.hours.ago.to_i) / 86400
>> 1
(Time.now.to_i - 1.day.ago.to_i) / 86400
>> 1
In the question's specific example, one should not parse to Date if the time passed is relevant. Use Time.parse instead.
Very late, but it may help others:
end_date.mjd - start_date.mjd
https://apidock.com/ruby/Date/mjd
Hint: This works only for Date objects, not Time objects.
To have the number of whole days between two dates (DateTime objects):
((end_at - start_at).to_f / 1.day).floor
The best solution currently that I've seen work consistently well is using the following pattern:
(end_date.beginning_of_day - Time.now.utc.beginning_of_day).seconds.in_days
To get the number of days difference by two dates:
(start.to_date...end.to_date).count - 1
or
(end.to_date - start.to_date).to_i
(end_date - start_date)/1000/60/60/24
any one have best practice please comment below
def business_days_between(date1, date2)
business_days = 0
date = date2
while date > date1
business_days = business_days + 1 unless date.saturday? or date.sunday?
date = date - 1.day
end
business_days
end
Related
I tried using answers for this question but was not able to get something that worked.
I want to be able to loop through days, starting today and going up to a target date set for an object.
The target date is of type Date.
I have tried a few things, all variations on the answers above, this was last attempt.
count = 0
Time.now..goal.target_date do
count += 1
end
This does not loop through anything and returns 0 as the count. Right now this is only in dev, with one object, so I know there are many days between now and the target (which is set for December 31 of this year).
I also tried this.
count = 0
Date.new(Time.now)..goal.target_date do |date|
count += 1
end
Which returns the error undefined method 'div' for 2018-10-06 17:23:41 -0500:Time. (Same error if I use Date.today just with :DATE instead of :Time at the end).
Can anyone help me get this to run the loop for each day between now and the target date?
Thanks!
Just wrote this one using de Date.upto() method and it worked... you just gotta make sure that 'goal.target_date' is also a valid instance of Date
require 'date'
from = Date.today
goto = from + 3
from.upto(goto) do |date|
puts date
end
Do you need a loop? If not, try this:
count = (goal.target_date - Date.current).to_i
I hope it useful for you. :)
Objective
I am trying to calculate the distance in weeks since a given date without jumping through hoops. I'd prefer to do it in plain Ruby, but ActiveSupport is certainly an acceptable alternative.
My Code
I wrote the following, which seems to work but looks like the long way around to me.
require 'date'
DAYS_IN_WEEK = 7.0
def weeks_since date_string
date = Date.parse date_string
days = Date.today - date
weeks = days / DAYS_IN_WEEK
weeks.round 2
end
weeks_since '2015-06-15'
#=> 32.57
ActiveSupport's #weeks_since takes a number of weeks as its argument, so it doesn't fit this use case. Ruby's Date class doesn't seem to have anything relevant, either.
Alternatives?
Is there a better built-in solution or well-known algorithm for calculating the number of weeks separating a pair of dates? I'm not trying to code-golf this, as readability trumps brevity, but simply to learn whether Ruby natively supports the type of date arithmetic I've coded by hand.
require 'date'
str = '2015-06-15'
Date.parse(str).step(Date.today, 7).count # => 33
Date.parse(str).upto(Date.today).count.fdiv(7).round(2) # => 32.71
Might be easier to convert the dates to time and then divide the time difference by a week. You can round it however you want or ceil.
def weeks_since(date_string)
time_in_past = Date.parse(date_string).to_time
now = Time.now
time_difference = now - time_in_past
(time_difference / 1.week).round(2)
end
in_weeks (Rails 6.1+)
Rails 6.1 introduces new ActiveSupport::Duration conversion methods like in_seconds, in_minutes, in_hours, in_days, in_weeks, in_months, and in_years.
As a result, now, your problem can be solved as:
date_1 = Time.parse('2020-10-18 00:00:00 UTC')
date_2 = Time.parse('2020-08-13 03:35:38 UTC')
(date_2 - date_1).seconds.in_weeks.to_i.abs
# => 9
Here is a link to the corresponding PR.
Can anyone help me make sense of this, please?
I am getting a very weird behaviour (reverse logic), when I am trying to use the following code.
require 'active_support/all'
c = {
id: 5,
years_of_experience: 4,
github_points: 293,
languages: ['C', 'Ruby', 'Python', 'Clojure'],
date_applied: 5.days.ago.to_date,
age: 26
}
c["date_applied"] > 15.days.ago.to_date - #works
c["date_applied"] < 15.days.ago.to_date - #doesnt work
c["date_applied"] gives a date value stored in a hash.
The latter makes more logical sense, but the first returns the right answer.
The code's behavior is correct, but I think I understand the confusion.
You're reading
c["date_applied"] > 15.days.ago
as:
Is the date applied more than 15 days ago?
and
c["date_applied"] < 15.days.ago
as:
Is the date applied less than 15 days ago?
and it's giving you the reverse of the answer you expect, right?
If that's the case, you should take a moment to understand how time comparisons operate. When you type date1 > date2, you're actually saying,
If I plot date1 and date2 on a number line with time increasing from left to right,
is date1 to the right of date2?
This is the same as when you type 2 > 1. It means,
If I plot 1 and 2 on a number line with the numbers increasing from left to right,
is 2 to the right of 1?
Given that this is how time comparisons operate, let's reexamine your code.
require 'active_support/all'
c = { date_applied: 5.days.ago.to_date }
c[:date_applied] > 15.days.ago.to_date
Correctly interpreted, this says
Is the date 5 days ago further rightward on a left-to-right timeline than the date 15 days ago?
and the answer is yes, or true.
If, on the other hand, you were to incorrectly interpret this as
Is 5 days ago more than 15 days ago?
you would get (or expect to get) the mistaken answer of no, or false.
The correct way to think about the task in English is to reframe the question of
Is date d more than n days ago?
and instead think of it as
Is date d earlier than the date n days ago?
and the correct code becomes apparent:
d.to_date < n.days.ago.to_date
If I understood your question correctly, this should explain it.
irb ## ruby-1.9.3-p448
require 'active_support/time'
c = {
id: 5,
years_of_experience: 4,
github_points: 293,
languages: ['C', 'Ruby', 'Python', 'Clojure'],
date_applied: 5.days.ago.to_date,
age: 26
}
(c[:date_applied] > 15.days.ago.to_date) - #true
(c[:date_applied] < 15.days.ago.to_date) - #false
###or you can try it by adding your own private methods###
class Fixnum
def days
self * 60 * 60 * 24 # we store seconds in a day
end
def ago
Time.now - self
end
end
I need to loop through all of the days and months for the past couple decades numerically as well as to have the name of the month and day for each date. Obviously a few series of loops can accomplish this, but I wanted to know the most concise ruby-like way to accomplish this.
Essentially I'd need output like this for each day over the past X years:
3 January 2011 and 1/3/2011
What's the cleanest approach?
Dates can work as a range, so it's fairly easy to iterate over a range. The only real trick is how to output them as a formatted string, which can be found in the Date#strftime method, which is documented here.
from_date = Date.new(2011, 1, 1)
to_date = Date.new(2011, 1, 10)
(from_date..to_date).each { |d| puts d.strftime("%-d %B %Y and %-m/%-d/%Y") }
# => 1 January 2011 and 1/1/2011
# => 2 January 2011 and 1/2/2011
# => ...
# => 9 January 2011 and 1/9/2011
# => 10 January 2011 and 1/10/2011
(Note: I recall having some bad luck a ways back with unpadded percent formats like %-d in Windows, but if the above doesn't work and you want them unpadded in that environment you can remove the dash and employ your own workarounds.)
Given start_date & end_date:
(start_date..end_date).each do |date|
# do things with date
end
as David said, this is possible because of Date#succ. You can use Date#strftime to get the date in any format you'd like.
See if you can construct a Range where the min and max are Date objects, then call .each on the range. If the Date object supports the succ method this should work.
I'm a bit confused between Date, Datetime, and Time in Ruby. What's more, my application is sensitive to timezones, and I'm not sure how to convert between these three while being timezone-robust.
How can I check if two unix timestamps (seconds since epoch) represent the same day? (I don't actually mind if it uses local time or UTC; while I'd prefer local time, as long as it's consistent, I can design around that).
Using the standard library, convert a Time object to a Date.
require 'date'
Time.at(x).to_date === Time.at(y).to_date
Date has the === method that will be true if two date objects represent the same day.
ActiveSupport defines nice to_date method for Time class. That's how it looks like:
class Time
def to_date
::Date.new(year, month, day)
end
end
Using it you can compare timestamps like that:
Time.at(ts1).to_date === Time.at(ts2).to_date
And here is less controversial way without extending Time class:
t1 = Time.at(ts1) # local time corresponding to given unix timestamp ts1
t2 = Time.at(ts2)
Date.new(t1.year, t1.month, t1.day) === Date.new(t2.year, t2.month, t2.day)
Time.at(ts1).day == Time.at(ts2).day && (ts1 - ts2).abs <= 86400
Or
t1 = Time.at(ts1)
t2 = Time.at(ts2)
t1.yday == t2.yday && t1.year == t2.year
In the first case we make sure that timestamps are no more than day apart (because #day returns day of month and without this additional check Apr 1 would be equal to May 1)
An alternative is to take day of year and make sure that they are of the same year.
These methods work equally well in both 1.8 and 1.9.
We can use beginning_of_day of the time and compare them:
t1.beginning_of_day == t2.beginning_of_day
This way the timezones won't be affected.