Rails: Difference between timezones in hours - ruby-on-rails

I'd like to be able to say user1 is 4 hours ahead of user2, calculated based on the time zones the users specify in their account.
Using the following code:
time1 = Time.zone.now.in_time_zone(user1.time_zone)
time2 = Time.zone.now.in_time_zone(user2.time_zone)
distance_of_time_in_words time1,time2
...gives a difference of less than a minute - similarly subtracting the two times gives 0. Rails obviously still sees these two times as the same.
Any idea how I can calculate this difference between two time zones?

If you take your time1 instance and call utc_offset on it, you will get the amount of time offset from UTC in seconds. Combine this with the utc_offset of time2, throw in some subtraction, and you should get the time difference in seconds. From there you can do the conversation to whatever unit of time you like.
irb(main):020:0> time1 = Time.zone.now.in_time_zone("EST")
=> Sun, 09 Jun 2013 07:11:46 EST -05:00
irb(main):021:0> time2 = Time.zone.now.in_time_zone("MST")
=> Sun, 09 Jun 2013 05:11:49 MST -07:00
irb(main):022:0> time_difference_in_seconds = time2.utc_offset - time1.utc_offset
=> -7200
irb(main):025:0> (time_difference_in_seconds/60/60).abs
=> 2

Related

Ruby Rails Time zone rush hour

The last developer is using time in our app like this.
:timestamp_requested => Time.now.utc
I want to check if :timestamp_requested is between 4:15PM and 6:00PM CST.
I saw another post that uses in_time_zone but not sure how to check for between two times?
t = foo.start_time
#⇒ 2000-01-01 14:20:00 UTC
t.zone
#⇒ "UTC"
t.in_time_zone("America/Chicago")
#⇒ Sat, 01 Jan 2000 09:20:00 EST -05:00
You might want to try the use_zone method
Time.use_zone("America/Chicago") { (16..18).cover?(time.hour) && time.min >= 15 }
The easiest way to check the time is in the specific range would be to compare hours and minutes:
cst = time.in_time_zone("America/Guatemala") # CST whole year
(16..18).cover?(cst.hour) && cst.min >= 15

Given a timestamp, how to determine how many weeks ago?

I'm looking to return the number of weeks since a user was created in my app..
My model is User.rb (id, created_at)
Given user.created_at:
2.4.0 :008 > user.created_at
=> Mon, 14 Aug 2017 15:51:23 UTC +00:00
How can I do something like: user.created_at.weeks_ago where it returns some integer which represents the number of weeks since the user was created?
If you just want to build a human-friendly string, I believe time_ago_in_words is what you are after.
https://apidock.com/rails/ActionView/Helpers/DateHelper/time_ago_in_words
Otherwise, I would resort to something like the following:
(Time.new - user.created_at) / 1.week
If you want a more elegant solution, Subtract dates in Ruby and get the difference in minutes mentions the Time Difference gem for Ruby.
e.g.
TimeDifference.between(user.created_at.to_time, Time.now).in_weeks
I would use:
Time.current
=> Wed, 20 Sep 2017 03:56:15 UTC +00:00
Then
((Time.current - person.created_at)/604800).to_i
the subtraction gives you the number of seconds then divide it by 604800 which is the number of seconds in a week.

Why does adding and subtracting 2 months to a date not give back the same date?

I'm a bit confused about this outcome, taking today's date minus 2 months, and then taking that date again and adding two months, does not give me today's date when assign the dates to a variable.
Time.zone
"Eastern Time (US & Canada)"
> today = Date.today.in_time_zone
=> Thu, 31 Aug 2017 00:00:00 EDT -04:00
> a = today - 2.months # This is persisted to the db
=> Fri, 30 Jun 2017 00:00:00 EDT -04:00
> b = a + 2.months
=> Wed, 30 Aug 2017 00:00:00 EDT -04:00
If I however, just use the same object, it moves back and forth properly:
> today = Date.today.in_time_zone
=> Thu, 31 Aug 2017 00:00:00 EDT -04:00
> today - 2.months
=> Fri, 30 Jun 2017 00:00:00 EDT -04:00
> today + 2.months
=> Tue, 31 Oct 2017 00:00:00 EDT -04:00
The problem is obviously when "a" gets saved to a database, and then retrieved later on, and calculated plus 2 months..., it should match today's date.
TL;DR
A month is not a fixed duration. Adding or taking a month does not give the same "time shift" depending on which day you are.
The usual algorithm
to add or take months is the following :
try to land on the same day number (4th, 30th, 31st) as you started, just by changing the month
if you would land on an impossible date (like 31th September, 30th February, 29th February for some years) then just go the maximum allowed day number of this month
This implies that adding some months then taking out the same number of months will not necessarily give you back the same date.
Examples :
31st of some month + 1 month --> One would want to get to the 31th of next month
But if there is no 31st of next month (like for 31th of August, no 31st of September), then what to do ?
Usual interpretation would say that you want to go to the end of the month, this is 30th September (for rent or other monthly subscription, for instance)
But usually, 30th of some month - 1 month --> One would want to get to the 30th of the previous month.
That would lead to .... 30th of August. Not 31th of August.
Hence: some date + 1 month - 1 month does not necessarily give the original date !
Another example :
Start at the 30th of August.
Take a month -> 30th of July
Add a month -> You want to get to 30th of August (same number, next month) or to the end of August ?
The default algorithm will try to give the same day number -> 30th of August (which is more logical now)
Also with days...
Note that the same problem happens with days,but much less often ! When some days don't have the same number of hours, for daylight saving days, when adding and taking same number of days you might not get back to the original date and time as you started from.

how to get time in totally in minutes in rails?

I am using DateTime.now and Time.now methods. And I store it in some variables. Now I want this time in minutes. Meaning, instead of hours and minutes I want to get time in minutes only.
2.2.2 :014 > datetime = DateTime.now
=> Fri, 11 Sep 2015 12:13:00 +0530
2.2.2 :015 > time = Time.now
=> 2015-09-11 12:13:06 +0530
2.2.2 :016 >
Now i want to calculate this time entirely in minutes. is there any method like to_minutes like below?
datetime_in_min = datetime.to_minutes
time_in_min = time.to_minutes
This must have already been done by now but just for anyone who's still looking for an answer, try doing something like below
lets assume the we wish to fetch the minutes and the hours from something like
s = Sat, 27 May 2017 02:30:00 UTC +00:00 (date time)
then,
hours = s.strftime("%H")
minutes = s.strftime("%M")
total_minutes((hours.to_i * 60) + minutes)
hence you'll get something like 150
Hope this helps.
You can use the following method from Time:
Time.now.to_i
to get number of seconds since the Epoch (January 1, 1970 00:00 UTC).
The strftime method can get you any piece of the time you want. The time in minutes (I'm assuming relative to the beginning of the day) you need to do some math:
hours = datetime.strftime('%k').to_i
hours_in_minutes = hours * 60
minutes = datetime.strftime('%M').to_i
minutes_since_start_of_day = hours_in_minutes + minutes
Same thing works for time.

How to subtract date and time out of date time object?

Here is what I am trying to achieve - I have set up a scheduler to execute midnight of every friday, which collects the data from a service for the start date of last friday at 00:00:00 hrs and end time of last thursday at 23:59:59 hrs. Since it has to work every friday, I cannot hard code the dates so I thought of trying out DateTime.
So as per my requirement, if I am running the job on this Friday midnight i.e at "2014-12-12T03:00:00Z", then my start date should be "2014-12-05T00:00:00Z" and my end date should be "2014-12-11T23:59:59Z".
So to get start and end dates, I am trying to subtract days out of my now object. This is what I tried:
now = DateTime.now
p now.new_offset(0).to_s
startDate = now - 7
p startDate.new_offset(0).to_s
endDate = now - 1
p endDate.new_offset(0).to_s
This gives me the right date, but the time is wrong i.e. instead of start date with 00:00:00 and end date with 23:59:59 this would be start date with 03:00:00 and end date with 03:00:00.
How do I modify the DateTime object to get the start date with time at beginning of the day and end date with time at end of the day?
Sorry I am very bad in dealing with dates. Thanks in advance!!
You can use he beginning_of_day and end_of_day methods
1.9.3-p448 :001 > DateTime.now.beginning_of_day
=> Tue, 09 Dec 2014 00:00:00 +0300
1.9.3-p448 :002 > DateTime.now.end_of_day
=> Tue, 09 Dec 2014 23:59:59 +0300
I think what you are trying to do is easier done with the Date class :
require 'date'
start_date = (Date.today - 7).to_time
end_date = Date.today.to_time - 1
Instead of doing this manually, I will suggest a gem called Whenever: https://github.com/javan/whenever
It's a simple DSL for Ruby cron jobs.
Also remember that DateTime has beginning_of_day and end_of_day methods.

Resources