Problem with Time Comparison in Rails AR Query - ruby-on-rails

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.

Related

Rails messing up with my Postgres TIME columns

I am using postgres TIME type to represent a branch office opening hour.
I am aware Rails does not handle the TIME column alone, initializing the values with a default date: 01 Jan 2000.
I have no problem with that except for the fact that my user timezone is -03, so when the user picks a time, let's say 22:00:00, Rails actually changes it to 01:00:00 and stores that value instead. Then, when I load it from the db it might even load a different date (the day before or after 01 Jan, which is a headache when I am comparing times).
How can I tell Rails to not change the original input to the server timezone? Or is there any other better workaround?
Rails always have TZ associated with times, it also stores everything in utc in DB. Out of the box, it does correct encoding/decoding. My assumption is - you have done your own decoding when you retrieve values from the DB. In this case, what you can do is to write helper like this:
def strip_tz(time)
Time.new(time.year, time.month, time.day, time.hour, time.min, time.sec, "+00:00")
end
And use it when you pass time value to the model creation.

Postgresql date difference in table and on web

I have weird situation with my PostgreSQL db date value.
On my web site I have calendar for selecting a date and when I select some future date like "2018-09-23" in PostgreSQL table column it is saved as "2018-09-22 22:00:00"?
Obviously I am missing something. On web site all the time it shows okay time "2018-09-23" but at the table it is minus one day as you see above. Why?
Rails stores DateTime fields in UTC, but without marking their time zone as UTC. This corresponds to the timestamp without time zone type in postgres. So if your time zone is +2, it'll store the time as UTC (+0).
In Rails, Time.zone will return the current local timezone (you can add logic to change this by user, for example). When persisting a datetime, Rails will automatically convert the current Time.zone to UTC. However, it doesn't use the Postgres type that actually includes the time zone data, so it relies on convention to convert back and forth to the user's time zone.
If you really only care about the date, use the date type in your migration instead of Timestamp or DateTime.
Times and dates have a lot of subtle quirks and the "right" behavior depends on your use case. In some applications, you need to deal with "local" time when considering date transitions, and sometimes you need to finesse your application or database logic to think in terms of local time and sometimes you care about UTC time.

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 ActiveRecord not converting time to UTC but saving unconverted time as UTC

I am using Rails 2.3.3 with Postgresql.
In my application environment.rb file I have set config.time_zone = 'UTC' and in my before_filter I set Time.zone = current_user.time_zone.
The problem I face is the Time that gets saved is in the users time_zone but gets saved as UTC in the database.
For example if I select 12:00 am IST (i.e +530 IST) it gets stored as 12:00 am UTC. However locally the configurations seem to work as expected and while fetching the data the time gets converted to the users time_zone so it gains 530 hours.
Would appreciate some help on this.
Thanks
Do you use time or datetime as the database column type for your object?
This recent (and very similar) question to yours could be resolved by changing the type from time to datetime.

Ruby on Rails and Active Record standalone scripts disagree on database values for :timestamps

I posted a question earlier today when I'd not zeroed in quite so far on the problem. I'll be able to be more concise here.
I'm running RoR 2.1.2, on Windows, with MySQL. The SQL server's native time zone is UTC. My local timezone is Pacific (-0800)
I have a model with a :timestamp type column which I can do things like this with:
record = Record.find(:first)
record.the_time = Time.now()
When I do a "select * from records" in the database, the time shown is eight hours in advance of my local time, which is correct, given that the DB is on UTC. (I have verified that it is 'thinking in utc' with a simple 'select now()' and 'select utc_timestamp()')
This is where the trouble begins. If I display the time in a view:
<%= h record.the_time %>
...then I get back the correct time, displayed in UTC format. If I wrote to the database at 16:40:00 local time, the database showed 00:40:00.
HOWEVER, if I am running a standalone script:
record = Record.find(:first)
puts record.the_time
...then I get back the UTC time that I stored in the database (00:40:00,) but with the local timezone:
Wed Nov 26 00:40:00 (-0800) 2008
...an eight-hour time warp. Why is it that storing the time translates it correctly, but retrieving it does not? If I compare a stored time from the recent past in the DB and compare it to the current time, the current time is less - telling me this isn't just a string conversion issue.
Any ideas?
There is a setting in config/environment.rb that sets a time_zone. Possibly this is not set the same in your script:
# Make Time.zone default to the specified zone, and make Active Record store time values
# in the database in UTC, and return them converted to the specified local zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Uncomment to use default local time.
config.time_zone = 'UTC'
You can also try explicitly specifying the TZ and format:
require 'active_support/core_ext/date/conversions'
record.the_time.utc.to_s(:db)
(or cheat and grab the code fragment from there if you're not using active_support in your standalone script)
Try requiring active_support
Well, you did not comment on my last suggestion to restart your server or your console.
I had a similar problem and it got fixed when I did so.
Also you mention a stand-alone script, but in order to get the time-zone feature of Rails the code needs to run within Rails.
In the end, it was far easier to do this by storing times as an integer (Time.now().to_i()) and converting them back to a time when I needed to display them (Time.at(the_time_the_database_returned_to_me).) This is hardly the best solution, but it was the only one that worked.

Resources