Create a DateTime for tomorrow Ruby - ruby-on-rails

I know I can create Date.tomorrow and there are options like midnight, at_noon etc. I need a more specific time than this.
Specifically, I am looking to create a DateTime that is tomorrow at 11am. I don't see anything in the DateTime docs. Is there any simple way to accomplish this? Thanks!

In Rails you would probably use tomorrow, in_time_zone and change:
Date.tomorrow.in_time_zone.change(hour: 11)
#=> Sat, 08 Aug 2015 11:00:00 CEST +02:00
This returns a ActiveSupport::TimeWithZone instance, just like midnight, at_noon etc.

Pure Ruby:
(Date.today + 1).to_datetime + Rational(11, 24)
or equivalently,
Date.today.to_datetime + Rational(35, 24)

Related

Elegantly use multiple different time methods additively?

Is there a way to use multiple time methods in an additive way?
Example: if the desired result was the time 3 weeks and 2 days ago, is there anything like this?
3.weeks.and.2.days.ago
I also tried
3.weeks.2.days.ago
What's the most elegant/sensible way to do this?
The best way I could come up with was
(3 + 2/7.to_d).weeks.ago
or
23.days.ago
But is there a way to use multiple time methods (e.g. weeks, days, hours etc) in the same command to make it easier to read?
ActiveSupport::Duration does not have a and method or any other method defined that works like that.
But want you can do ist this:
(3.weeks + 2.days).ago
#=> 2021-02-12 11:06:40.087082 +0100
There's also advance which returns a new date / time object based on the given options:
Time.current
#=> Sun, 07 Mar 2021 12:14:29 CET +01:00
Time.current.advance(weeks: -3, days: -2)
#=> Fri, 12 Feb 2021 12:14:29 CET +01:00
Options are :years, :months, :weeks, :days, :hours, :minutes, and :seconds.

Rails compare Time with TimeWithZone

In my Rails app, I'm comparing a date from my database to Time.now:
Event.date_start >= Time.now
But Event.date_start is ActiveSupport::TimeWithZone
Everything works perfectly but I want to know if comparing a Time with a TimeWithZone is the proper way, and if this is not the case, how to do it?
The best practice is not to use Time.now in Rails apps. Use Time.current instead. It returns ActiveSupport::TimeWithZone too.
Time.now also works with TimeZone. Look at this:
Time.zone.now
#=> Mon, 12 Sep 2016 16:51:54 UTC +00:00
ExampleModel.date_start
#=> Tue, 28 Jun 2016 12:39:26 UTC +00:00
Time.zone
#=> #<ActiveSupport::TimeZone:0x0055de104e3ce0 #name="UTC", #utc_offset=nil, #tzinfo=#<TZInfo::TimezoneProxy: Etc/UTC>, #current_period=#<TZInfo::TimezonePeriod: nil,nil,#<TZInfo::TimezoneOffset: 0,0,UTC>>>>
You can compare this without restrictions :)

How do I add future dates to table?

I'm building a schedule in rails and I need to see if today's date matches the date of an event in the future. I have an event model with a date field and I know the dates of all the future events, but how do I add those dates to the table in a way rails will understand?
I'd like to do something like:
if Time.now is equal to next event
# do this
Time.now outputs
2014-03-18 11:05:14 -0500
How do I add that sort of format to the dates in the table so that I can compare Time.now to the date of the future event?
EDIT
Say I'm creating a new Event in the rails console, And I want the date of the Event to be April 1, 2014. I'm trying to figure out what syntax I need to enter the date in the console. For example, to create an Event in console I would do something like
Event.create(name: "Event1", date: ??)
What do I put in place of the question marks for the date of April 1, 2014 in syntax understood by the computer? I need April 1, 2014 in a datetime format, not a string.
Thank you!
seeds.rb is—as the file extension implies—just Ruby.
You can supply the date in any form that an available Ruby library can parse into a Time or Date object.
If you want to keep it human-readable, you can use Date.parse:
Event.create(name: 'Event1', date: Date.parse('Apr 1 2014'))
Event.create(name: 'Event2', date: Date.parse('April 1, 2014'))
Event.create(name: 'Event3', date: Date.parse('1-Apr-14'))
Or, if you need human-readable times as well, Time.parse:
Event.create(name: 'Event4', date: Time.parse('09:15 1 Apr 2014'))
Event.create(name: 'Event5', date: Time.parse('April 1, 2014, 9:15am'))
Event.create(name: 'Event6', date: Time.parse('1-Apr-14, 09:15 -0700'))
If you prefer to use UNIX timestamps, Time.at creates a new Time object from them (and offers a mild performance benefit over parsing textual dates):
Event.create(name: 'Event7', date: Time.at(1395166977))
If you have defined next_event as a datetime column in database, rails will automatically initialize it as a date_time object when you load it from database. All you need is this
if Time.now.to_date == next_event.to_date
For adding the future days, you can use days.from_now method
For eg
1.days.from_now #Wed, 19 Mar 2014 16:29:26 UTC +00:00
2.days_from_now #Thu, 20 Mar 2014 16:30:16 UTC +00:00
Or you can use normal addition
Time.now + 2.days
Time.now + 2.hours
Time.now + 10.minutes
Event.create(name: "Event1", date: (Time.now + 1.day))

Correcting time for daylight savings in rails DateTime.parse

Just adding to the million questions about time zone and DST issues out there.
I have a form with separate date and time fields that I combine to create a DateTime like so
start_time = DateTime.parse("#{parse_date(form_date)} #{form_start_time} #{Time.zone}")
If I fill out my form with 21 Aug 2012 and 15:00, then these are the values that I see when I reload my form. If I then look at my start_time attribute in my model it is correctly set to Tue, 21 Aug 2012 15:00:00 EST +10:00.
The problem I am having occurs if I use a date later this year once daylight savings kicks in (I am in Australia). If I use 21 Dec 2012 and 15:00 then check start_time I see Fri, 21 Dec 2012 16:00:00 EST +11:00.
My interpretation of the problem is that the date is being saved in my current time zone (+10:00) as this is what I have told DateTime.parse to do. However when the value is returned, Rails is looking at the date and saying 'hey, it's daylight savings time in December' and returning the time in the +11:00 time zone.
What I want to do is tell DateTime.parse to save the time in the +11:00 time zone if DST is in effect. Clearly passing Time.zone into my string doesn't achieve this. Is there a simple way of doing this? I can see ways of doing it using Time#dst? but I suspect that this is going to create some really ugly convoluted code. I thought there might be a built in way that I'm missing.
(Answer for Rails 4.2.4, didn't check for older or newer versions)
Instead of using fixed shift +01:00, +02:00, etc, I recommend to use the in_time_zone String method with time zone name as argument :
Summer time :
ruby :001 > "2016-07-02 00:00:00".in_time_zone('Paris')
=> Sat, 02 Jul 2016 00:00:00 CEST +02:00
Winter time :
ruby :002 > "2016-11-02 00:00:00".in_time_zone('Paris')
=> Wed, 02 Nov 2016 00:00:00 CET +01:00
String#in_time_zone is the equivalent of :
ruby :003 > Time.find_zone!("Paris").parse("2016-07-02 00:00:00")
=> Sat, 02 Jul 2016 00:00:00 CEST +02:00
ruby :004 > Time.find_zone!("Paris").parse("2016-11-02 00:00:00")
=> Wed, 02 Nov 2016 00:00:00 CET +01:00
You can get the time zone names by :
$ rake time:zones:all
Or in rails console :
ruby :001 > ActiveSupport::TimeZone.all.map(&:name)
Or build collection for select tag :
ActiveSupport::TimeZone.all.map do |timezone|
formatted_offset = Time.now.in_time_zone(timezone.name).formatted_offset
[ "(GMT#{formatted_offset}) #{timezone.name}", timezone.name ]
end
And store the time zone name instead of the shift.
Note : don't confuse String#in_time_zone method and the Time#in_time_zone method.
consider the time zone for my system is 'Paris'.
ruby :001 > Time.parse("2016-07-02 00:00:00")
=> 2016-07-02 00:00:00 +0200
ruby :002 > Time.parse("2016-07-02 00:00:00").in_time_zone("Nuku'alofa")
=> Sat, 02 Jul 2016 11:00:00 TOT +13:00
Here's my solution so far. I'm hoping someone has a better one.
start_time = DateTime.parse "#{date} #{(form_start_time || start_time)} #{Time.zone}"
start_time = start_time - 1.hour if start_time.dst? && !Time.now.dst?
start_time = start_time + 1.hour if Time.now.dst? && start_time.dst?
It seems to work but I haven't rigorously tested it. I suspect it could be prettied up and shortened but I think this is readable and understandable. Any improvements?
I ran into this exact issue. My app allows users to see upcoming events. In the US we fall of DST on November 2nd and all events on and after that date were showing times an hour early.
We require the opportunity to have the timezone selected and stored to its own field. Before I was using the following to store my datetime:
timezone_offset = Time.now.in_time_zone(params[:opportunity][:time_zone]).strftime("%z") #-0700
DateTime.parse("#{params[:opportunity][:start_datetime]} #{timezone_offset}")
To fix the issue I have changed to:
start_datetime = Time.zone.parse(params[:opportunity][:start_datetime])
To display the correct times we use:
#opportunity.start_datetime.in_time_zone(#opportunity.time_zone)
I wouuld try and use
Australian Eastern Standard Time (AEST) (UTC +10).
Australian Central Standard Time (ACST) (UTC +9 ½).
Australian Western Standard Time (AWST) (UTC +8).
which adjust for Daylight Savings.
With Rails, we can use ActiveSupport::TimeZone for this:
tz = ActiveSupport::TimeZone.new 'Pacific Time (US & Canada)'
tz.parse(date_str_without_zone).to_datetime
I use TZip to get TimeZone strings (e.g. "Pacific Time (US & Canada)") from zip codes.
In case you have a custom date/time format, different than the supported by String#in_time_zone, you could also use (since rails 5) strptime like:
Time.find_zone!('Auckland').strptime('2021-02-02 08.00.00', '%Y-%m-%d %H.%M.%S')

ROR + TodayDate in UTC Format

If I have #today = Date.today.to_s, how do I convert #today into UTC (with the appropriate date only)?
Here I need is only date for example 2011-03-08 ie 08 March 2011. Please suggest something ?
Acutally I am looking for Yesterday date ??
You'll need to convert it to a Time object (or just use Time anyway) and then call Time#utc:
irb > Time.now
=> Tue Mar 08 15:32:36 +1100 2011
irb > Time.now.utc
=> Tue Mar 08 04:32:40 UTC 2011
You can then format it however you need it:
irb > #today = Time.now.utc
=> Tue Mar 08 04:34:25 UTC 2011
irb > #today.strftime("%Y-%m-%d")
=> "2011-03-08"
If you want to convert #today into UTC.
Then try this
>> #today = Date.today.to_s
>> DateTime.parse(#today)
Try
1.day.ago.utc
or
1.day.ago.utc.strftime('%b %B, %Y')
The format below should give you the date format of Yesterday which you are looking for formatted as 07 March, 2011. Look into the ruby Time class manual for more information on strftime time formating function. Good luck!
I strongly recommend you to move towards time zones in rails. Its easier and lot more convenient to work with than Time.now. You should be able to set the time zone in environment.rb with config.time_zone = "Chennai" or your time zone. After doing this, you should be able to get the time with UTC information by Doing Time.zone.now. To find the UTC offset, you could type Time.zone.

Resources