Date saved 1 day earlier than in form - ruby-on-rails

I have a form with a booking_date and when I fill in the form with a date of 1 March 2016, these are the parameters sent:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"[FILTERED]", "pturnover"=>{"booking_date(3i)"=>"1", "booking_date(2i)"=>"3", "booking_date(1i)"=>"2016"}, "commit"=>"Opslaan", "id"=>"5"}
But when I look in the database after saving, it is saved as 29 february 2016:
=> #<Pturnover id: 5, booking_date: "2016-02-29 23:00:00"
How is this possible, is it related to timezone or something?

Rails saves datetimes in database with utc timezone by default. Datetime conversion from/to strings may take into account local timezone, either one of the OS or set manually. Conversion between local and utc is a probable reason of the discrepancy you are seeing.
As timezone handling in Rails is a sizeable topic, it's advisable to approach it in some depth. Here are some relevant resources:
RailsCasts #106 Time Zones (revised)
The Exhaustive Guide to Rails Time Zones
Working with time zones in Ruby on Rails
It's About Time (Zones)

You can convert the inputed time before saving or you can convert that time when showing in your show page.Conversion may looks like below :
ActiveSupport::TimeZone.new("Asia/Tokyo").local(your_inputed_time_here)
Hope that helps.

Related

How to store timezone info in rails

In my rails application,users can create questions and publish that, anybody from any country can response for that.
We are designing database structure for that. so planning to get user timezone using some js and while answering converting that time and to store in a separate column(tz_created_at).
so in created at the date will be stored in utc format, and in another column say tz_created_at the datetime will be stored as user's timezone converted time. (ie) in created_at column i have
irb(main):013:0> DateTime.now.utc => Sun, 30 Mar 2014 18:54:46 +0000
And in tz_created_at column i have
irb(main):015:0> DateTime.now
+ 6.hours(from user's timezone) => Mon, 31 Mar 2014 06:58:31 +0600
we are using sunspot solr to show some statistics in response over the time period.
so while querying for responses for a particular question i will search in tz_created_at column. is this approach is correct . please correct me if i am wrong
Instead of doing that, you probably want to store the datetime as UTC, then store the user's timezone in another column. By doing that you can always change the timezone if you need to without affecting the true time (e.g. the user moves country). When you display a time to the user you can easily convert the time to their zone to display it.
If you're a subscriber of railscasts there's a video on it there, but if you're not a subscriber there's an older one that's free to watch that will give you a general idea of best practices.

Accounting for daylight savings in rails webapp and iCal

Right, this is a bit confusing for me, so I'm going to try and explain from the top!
I have a rails web app. It's an internal company app and will only be used in the UK.
One of the things the app does is manage meetings.
Meetings have a date & time when they start. There's a date/time picker on the form which allows the user to pick the date & time the meeting is for. I save this date AS IS into the database. All meetings last 2 hours, so the end time is simply start + 2 hours.
Example:
2013-06-23 6:45PM in the form is stored in the db as 2013-06-23 18:45:00
2013-12-23 6.45pm in the form is stored in the db as 2013-12-23 18:45:00
Note that the first date is during Daylight Savings (BST) and the second is during GMT. I don't actually care whether it is GMT or BST: the meeting happens at that time, absolutely.
Inside the rails webapp, I simply print out the exact date & time from the DB - formatted nicely, of course!
Now, at some point I send an email to the organiser of the meeting, and the person they're meeting with. This email tells them the the date & time of the meeting etc, and also includes an iCal (.ics) file for them to put into their (Outlook usually, but also Apple or gmail) calendar.
The issue I am having is that (using the above examples) Outlook shows the meetings like this:
Meeting #1: Start: 23/06/2013 7:45pm, End: 23/06/2013 9:45pm
Meeting #2: Start: 23/12/2013 6:45pm, End: 23/12/2013 8:45pm
Note that it has adjusted the first one because of the BST/GMT thing.
The text of the .ics file contains this code:
Meeting #1:
BEGIN:VCALENDAR
...
DTEND:20130623T204500Z
DTSTART:20130623T184500Z
...
END:VCALENDAR
Meeting #2:
BEGIN:VCALENDAR
...
DTEND:20131223T204500Z
DTSTART:20131223T184500Z
...
END:VCALENDAR
So I am encoding the dates/times using the Z timezone (UTC). I understand this is why Outlook mis converting the UTC time into the BST time for #1 and leaving #2 alone (because GMT == UTC)
My question is: how do I stop this happening? I want the time the meeting is scheduled for to be the absolute, actual time, regardless of GMT/BST: 6:45pm
Should I be storing the date-times as UTC in the DB? How would this be done (I assume it would apply to all dates, not just meeting start dates). And how to re-convert them back into the actual datetime when I display them in the webapp?
Extra:
I have an entry in my initializers/time_formats.rb like this:
:ical => "%Y%m%dT%H%M00Z"
So dates come out like "20130623T184500Z". I use this when building the ics. And this I think is the issue - if the date/time is during BST I don't want to be using Z, but something else?
Your problem is your date/time format. You have:
DTSTART:20130623T184500Z
in your .ics file and this corresponds to 19:45 BST (as British summer time is UTC+1).
There are a few things you should do. First, you can simply remove the 'Z' from the end of your dates. This means that the times inherit the timezone of the calendar, or the underlying application.
This will work assuming that the machines which are running Outlook are all in the Europe/London timezone. If not, or if you want to be a bit safer, you should also specify the following after your BEGIN: VCALENDAR line:
X-WR-TIMEZONE:Europe/London
This specifies the default timezone for all dates which are not specified explicitly.
Finally, if this does not work for any reason then you need to define your datetimes explicitly. First you need to add a timezone definition for Europe/London to the calendar. The info you need is available at http://www.tzurl.org/zoneinfo-outlook/Europe/London.ics. Then you need to ensure that all datetimes are of the format:
DTSTART;TZID=Europe/London:20130623T184500
This last approach is the best, as it means that if your requirements expand to other timezones you will be able to handle them relatively easily.
Sorry to answer this myself, but in case anyone else runs into this here's what I found was the cause of my particular issue. Note that the answer above re timezones also makes sense!
My rails app is storing UTC datetimes in the DB (as is default)
But, it also thought it's own timezone was UTC, which also seems to be the default.
The upshot of that is essentially it was storing local dates, local to UTC anyway. Changing the app to know it was sitting in Europe/London made it so the dates in the DB are all now accurately UTC (meaning, they're an hour off if I'm currently in BST)
I can now use the Z datetime format in iCals, and outlook and the rails app both convert the UTC date back into the actual datetime for the viewing-user's locale (Europe/London for everyone at the moment). This is what I wanted.

How to deal with UTC times and Rails/ActiveRecord

I'm using Rails 3.2.8. When I generate a scaffold with a time field or datetime field. The HTML form field gets pre-populated with the current date/time in UTC. Great that it's pre-populated with the current date/time, but because it's in UTC, we have to change the time back 7 hours every time (which will sometimes require setting the day back 1 also, possibly month and year too). And then it seems the UTC time gets stored in the database, so I'll have issues displaying/editing it as well if I recorded it in our local time.
I looked at the Ruby documentation for the form helpers to deal with local time better, but I don't see anything relevant.
What's the best way to deal with editing and displaying dates and times in Rails?
UPDATE: To clarify, I like the idea that UTC time is stored in the database. I just want the time_select and datetime_select form helpers to edit the times in the user's local timezone. And, of course, I want to easily display the time in the user's local timezone.
You have to set the time zone to display on a per-user basis somewhere in a before/around_filter. This has to be done like:
Time.zone = "Kyiv"
An example can be found in its API: http://api.rubyonrails.org/classes/Time.html#method-c-zone-3D.
Run the rake time:zones:all to see all of them.
All the conversions has to be handled for you behind the scene.
This has helped me in the past. You can do things like:
Time.now.in_time_zone("Central Time (US & Canada)")
See Rails: convert UTC DateTime to another time zone

Rails time type and time zones

I have a Rails app that stores time values, and I have set a time zone in config/application.rb.
This works correctly on datetime columns, but time columns show the time in UTC, not the specified time zone.
The time on these two examples are both stored as 20:50 (UTC) in the database, but when I show it in a view the time column shows as UTC and the datetime column is correctly shown in the chosen time zone.
time2: 2000-01-01 20:50:00 UTC
datetime2: 2012-02-09 21:50:00 +0100
Is this expected behavior? Shouldn't time types also use the configured time zone?
ActiveRecord uses TimeWithZone, where methods like localtime, utc, utc? may help you.
Yes, this is expected behavior. Rails (ActiveRecord) stores times in UTC, then coverts them to whatever time zone Time.zone is set to upon rendering in the view.
I give up this, Rails seems to totally ignore config.time_zone with time attributes and just uses it for datetime attributes for reasons I don't understand. And as it seems, not many others understand it as well.
I will change the time attributes to type string and parse it to a time object when I need to work with it as a time object. If this is fixed in a later Rails release I can always change back to using time attributes, but now I need to go on, this has been holding me back for days.
But thanks for trying to help :)

Problem with Time Comparison in Rails AR Query

I'm running Rails 3.0.4 with a PostgreSQL Database and i created a DateTime field called ordered_at.
I set it by creation with Time.now and i want to query the ordered_at field with something like where("ordered_at > ?", params[:later_than], but if I put later than with something like 1.minute.from_now, I'm getting results where no results should be.
In Detail: ordered_at is 2011-03-08 11:11:49 and params[:later_than] is 2011-03-08 11:09:58 UTC.
I think that is because of the time zone in the Time object, which doesn't exists in the database (The ordered_At field is a timestamp without time zone Datatype).
Does anyone had the same problem and can help me?
Fixed it.
The root of evil was in my fixtures.
You have to set times in your fixtures like that:
ordered_at: <%= (30.minutes.ago).iso8601 %>
otherwise you will get the timezone of the database/server
The thing you have to remember is Rails store the time in your database in UTC. Rails convert the time into UTC and sets it as the standard to look at in the database. So if you have params[:later_than] as 2011-03-08 11:11:49 UTC or any time for that matter with any time zone, Rails will convert it into UTC time zone before inserting into the SQL query. If you are saving Time.now into the database, Time.now will be the server time or local machine time with the time zone in which the machine is set. Before saving to database, Rails will convert it to UTC and save it. So, at database level everything will be converted to UTC and then will be compared so avoiding confusion.

Resources