Configuring Ruby-on-rails created_at and updated_at dates time_zone - ruby-on-rails

Rails stores created_at and updated_at timestamps in UTC time.
But I am using these fields to filter and store (and do a lot of other stuff with the records) based on these fields, so it's important that when I call created_at and updated_at attributes, I get timestamps in my time zone.
As told by the following two SO questions, I can do that by configuring the time zone in the environment.rb file.
However, that's now working for me.
Because I am fetching the records from the database, based on created_at fields (which are in UTC) so naturally wrong ones are coming out, and then I am displaying them, so the dates are displayed in UTC, again, not what I want.
Is there a way to change in what time-zones the rails stores the dates?
OR
Is there a workaround for how I can achieve the database-fetching and displaying, without making a call to Rails object.created_at attribute?
Rails and timezone in created_at
Rails Time zone issue

I wonder why I even asked the question on this forum, because the workaround seemed to be pretty simple. But it did take me eight hours to reach it :)
1) While fetching records from the database and displaying them, I could simply do
select CONVERT_TZ(date) as date from table;
instead of doing
select date from table;
CONVERT_TZ() is a mysql specific function, so it worked for me. Not a universal solution though.
2) Secondly, when I had to fetch the records from a date range given in any other time-zone, I could do one of the two things.
One - I could replace [user-entered-date] 00:00:00 with [user-entered-date] 07:00:00 for the date-range's starting point and [user-entered-date] 59:59:59 with [user-entered-date + 1.day] 07:00:00 for the range's ending point. Note this would require me to use DateTime objects instead of using Date objects.
Two - In the where clause, I could do
CONVERT_TZ(registrations.created_at) <= [user/entered/date]
instead of
(registrations.created_at) <= [user/entered/date]

Related

TypeORM: Dates in SQLite Not Getting Returned Correctly

I'm using SQLIte3 v5.0.2 and TypeORM v0.2.38. I created a date column on a SQLIte table using date DATETIME DEFAULT CURRENT_TIMESTAMP.
When I search the database for rows between dates, it wasn't pickup up rows on the last day so I added a time to my BETWEEN query: WHERE date BETWEEN '2021-01-01 00:00:00' AND '2021-01-31 11:59:59' to include rows on last day.
As soon as I add the time part for the Between query for the date/time, it appears to load the field into entities using the local timezone. Without the time part it doesn't do this but also doesn't find the last days rows. I looked in the database and saw the date times are being stored with my local timezone (-7hrs) instead of UTC as I've seen is meant to be the case on several Github issues for TypeORM.
How can I ensure the dates are saved and loaded only as UTC so they don't change when I query rows in TypeORM? I'm considering writing a custom transformer for the entity field but if its supposed to be UTC by default then is this a bug or am I doing something wrong?

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.

Rails: why time datatype start at 1/1/2000

I have a column that I only want to store time (hour, minute, second). for example here is one migration:
add_column :products, :start_hour, :time
When I insert to database start_hour always start with 1/1/2000 for example: 2000-01-01 01:19:00 +0700. Please explain for me why.
There is no time-of-day class in Ruby or Rails so ActiveRecord represents time columns with datetime/timestamp classes.
If you look inside the database without any of the ActiveRecord, Rails, or Ruby noise in the way, you'll see an HH:MM:SS time-of-day value. But when ActiveRecord pulls a time out of the database, it sets the date component to 2000-01-01 because a datetime has to have a date and AR picks that one.
Any time you work with a start_hour in Ruby you'll have to ignore the date component.
The difference between formats stored in your DB have nothing to do with Rails and everything to do with your database. Date or Time formats are only 'valid' within your application, not within the database -more simply they are only responsible for the way time objects are displayed to your users and will not affect the way data is stored. Your best bet is to save the records as time objects and then use rails helpers to present the data to your users in a meaningful way with such methods as strptime etc.

Finding records created 10 days ago

My initial thought was:
user.humans.where("created_at = ?", 10.days.ago)
Though, this seems to be looking for the record created 10 days ago at the exact time when the statement is called. I want to collect the records created on that day, regardless of their time.
Is anyone aware of a convenient way to do this? Let me know if I need to elaborate.
Thanks.
You'll probably want to use a range here, as I assume this is a datetime column.
User.humans.where("? <= created_at AND created_at <= ?", 10.days.ago.beginning_of_day, 10.days.ago.end_of_day)
You'll also want to make sure you're setting the time zone of your Rails application so that you're explicit about which time period you consider to be the 10th day.
Whichever DBMS you are using will have a method to convert a datetime to a date. You should then compare this to a date in ruby. For example, if your DBMS is MySQL you could say
user.humans.where("date(created_at) = ?", 10.days.ago.to_date)
If you're not using MySQL then you should be able to google converting a datetime to a date in your DBMS of choice.

Ruby on Rails Time.now

I'm having trouble working with Time.now. For some reason when I save an object to the DB it saves it for the year 2000. I'm trying to make a comparison to the object I saved in the DB to Time.now to check if it is greater, but it always returns false because of the year 2000. Does anyone know of a way I can work around this?
I just need to check to make sure 10 minutes has passed since I created a time object compared to Time.now
It sounds like your database column is of type time rather than datetime or timestamp. This will only store the time and when it is converted to a Time instance in ruby (which does support day, month, year, etc) the default values are used for day, month, year which is why you're seeing the year 2000.
You probably need to update your database column to be datetime or timestamp if that is the problem as it sounds like you'll want the day, month, year parts of the time anyway. In which case you're comparisons will work.
created_at < 10.minutes.ago should work

Resources