Odd time store behaviour in ActiveRecord - ruby-on-rails

I have the following entry in my database:
t.time :my_time_stamp
In my controller I update it like this:
model.update_attributes(:my_time_stamp => Time.now.utc)
I can see that I'm writing:
Mon 9 November, 8:54.54 UTC 2009
However, when I later read this value I get:
Sat Jan 01 08:54:54 UTC 2000
It seems that the time part has been stored but not the date part. I'd expect that because it's a time field, but why do I end up storing and retrieving a date? I guess I must be misunderstanding how this works in some fundamental way.... what am I doing wrong?
What I need to do is calculate the time in seconds since the update to the database.... is there an easier way to do this?
Thanks!

A "time" field is storing only the time. Not the date.
So it's logic for you to get only a valid time and not a valid date.
If you wish to store date and time in the database, you should have the following migration :
t.datetime :my_time_stamp

Ruby does not have a dateless time object, so it converts the dateless time field in your database to that time on some arbitrary day. Ruby's Time objects encode a number of seconds since the unix epoch, so they include the date. The correct way to store them in the database is with a datetime field, or if you prefer, you could use an integer field and store Time.now.to_i.

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.

rails - Store DateTime objects in same time zone as timestamps

When i save a DateTime schedule_time to the DB, it saves according to my local time, but the timestamps (created_at) are saved apparently in UTC (7 hours ahead of my pacific time)
So if i submit the form setting my schedule_time for right now it will be 7 hours different than my created_at.
i need to show many users their times in their own selected zone, and i also need to compare times against each other, so i want all db entries to be in the same zone. Testing on my machine, my user has his zone saved as Pacific (-7:00), but its saving schedule_time in local time, not really UTC, so when i try to display the time back like this:
#item.schedule_time.in_time_zone(#user.time_zone)
it actually takes the stored datetime and subtracts seven hours from it giving me 7 hours before i wanted. i think the best thing is to just store all the datetimes in a uniform way so i can compare them easily.
changing this value config.time_zone = 'UTC' does nothing to change the stored format of my datetime. it stores in my local time regardless, while storing the timepstamps in real UTC.
ive also tried to reformat the datetime before storing it, with in_time_zone(#user.time_zone) but it had no effect on the stored time.
if i can just get schedule_time stored in UTC just like my timestamps are stored i could make this work! any ideas?
If you want to store schedule_time converted to UTC before storing it in the database, you can include a before_save callback in your Item model to convert it as follows:
before_save { |item| item.schedule_time = item.schedule_time.utc }
sorry i was totally on the wrong track.
the issue was with the jquery date picker i was using (will_pickdate). it returns a date and time but with a +0000 time zone offset. by default, the picker autofills with the current local time, but when i submitted that, rails basically thought it was receiving a time in UTC and added it as my local time but with +0000.
in order to store the date properly i have to keep the time and date from the picker intact, but just shift the +0000 part to something appropriate:
my_time.change(offset: user_time_zone_offset)

In Ruby on Rails, what's the difference between DateTime, Timestamp, Time and Date?

In my experience, getting dates/times right when programming is always fraught with danger and difficulity.
Ruby and Rails have always eluded me on this one, if only due to the overwhelming number of options; I never have any idea which I should pick.
When I'm using Rails and looking at ActiveRecord datatypes I can find the following
:datetime, :timestamp, :time, and :date
and have no idea what the differences are or where the gotchas lurk.
What's the difference? What do you use them for?
(P.S. I'm using Rails3)
The difference between different date/time formats in ActiveRecord has little to do with Rails and everything to do with whatever database you're using.
Using MySQL as an example (if for no other reason because it's most popular), you have DATE, DATETIME, TIME and TIMESTAMP column data types; just as you have CHAR, VARCHAR, FLOAT and INTEGER.
So, you ask, what's the difference? Well, some of them are self-explanatory. DATE only stores a date, TIME only stores a time of day, while DATETIME stores both.
The difference between DATETIME and TIMESTAMP is a bit more subtle: DATETIME is formatted as YYYY-MM-DD HH:MM:SS. Valid ranges go from the year 1000 to the year 9999 (and everything in between. While TIMESTAMP looks similar when you fetch it from the database, it's really a just a front for a unix timestamp. Its valid range goes from 1970 to 2038. The difference here, aside from the various built-in functions within the database engine, is storage space. Because DATETIME stores every digit in the year, month day, hour, minute and second, it uses up a total of 8 bytes. As TIMESTAMP only stores the number of seconds since 1970-01-01, it uses 4 bytes.
You can read more about the differences between time formats in MySQL here.
In the end, it comes down to what you need your date/time column to do:
Do you need to store dates and times before 1970 or after 2038? => Use DATETIME.
Do you need to worry about database size and you're within that timerange? => Use TIMESTAMP.
Do you only need to store a date? => Use DATE.
Do you only need to store a time? => Use TIME.
Having said all of this, Rails actually makes some of these decisions for you. Both :timestamp and :datetime will default to DATETIME, while :date and :time corresponds to DATE and TIME, respectively.
This means that within Rails, you only have to decide whether you need to store date, time or both.
:datetime (8 bytes)
Stores Date and Time formatted YYYY-MM-DD HH:MM:SS
Useful for columns like birth_date
:timestamp (4 bytes)
Stores number of seconds since 1970-01-01
Useful for columns like updated_at, created_at
:date (3 bytes)
Stores Date
:time (3 bytes)
Stores Time
Here is an awesome and precise explanation I found.
TIMESTAMP used to track changes of records, and update every time when
the record is changed. DATETIME used to store specific and static
value which is not affected by any changes in records.
TIMESTAMP also affected by different TIME ZONE related setting.
DATETIME is constant.
TIMESTAMP internally converted a current time zone to UTC for storage,
and during retrieval convert the back to the current time zone.
DATETIME can not do this.
TIMESTAMP is 4 bytes and DATETIME is 8 bytes.
TIMESTAMP supported range: ‘1970-01-01 00:00:01′ UTC to ‘2038-01-19
03:14:07′ UTC DATETIME supported range: ‘1000-01-01 00:00:00′ to
‘9999-12-31 23:59:59′
source: https://www.dbrnd.com/2015/09/difference-between-datetime-and-timestamp-in-mysql/#:~:text=DATETIME%20vs%20TIMESTAMP%3A,DATETIME%20is%20constant.
Also...
table with different column "date" types and corresponding rails migration types depending on the database

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

Why does Rails always display a datetime as 1/1/2000 - with the correct time

This one is driving me nuts!! The data is getting stored into the db (sqlite3) correctly. However, when I display the date from the record, Rails appears to coerce it to 1/1/2000 - with the correct time. In other words, if I specify this as the date time: December 31, 2009 6:00 PM, sqllite3 will in fact show 2009-12-31 18:00:00. But.... Rails will display the value has January 1, 2000 06:00 PM (keeping the correct time).
I have created virtual attributes to handle date formatting (which appear to work correctly). And, I have set my time zone to:
config.time_zone = 'Eastern Time (US & Canada)'
I have to believe this is something simple...It is totally driving me nuts!!
Thanks!
John
Well... I found the problem. As it turned out, when rails created the table, it did so using the Time data type. While the date portion of a datetime value will be stored in a time field, it would appear that when reading a time field, rails only considers the time portion.
The fix.. In desperation, I modified the column to be of datetime type. That fixed it.
John
I had the same problem, using postgres, and thanks user145110 for the suggestion to use the DateTime class instead of Time. That worked for me. I would only add that though I had to change my migration to use DateTime, I was still able to use Time and its methods in tests that compared against DateTime values. In other words, with this original migration:
t.time :start_time
...and sample assignment using Time:
start_time = Time.now.beginning_of_day
...it saved ok, but upon reading it later, the year was changed to 2000. Maybe it's an old Y2K bug. LOL. Instead, I simply changed the migration:
t.datetime :start_time
..and all my code worked. Even assignments like this work:
start_time = Time.zone.now.beginning_of_year.beginning_of_day
I can't help feeling like I missing something, though. Do others use Time to manipulate dates?
I was having this problem too. To add some information about the problem:
- In a debug tag (<%= debug object%>), the time and the date was correct, but when using without debug (<%= object.year %>), the year was 2000.
One can expect one of two things:
attribute:time have only the time (hours,minutes,seconds, etc.), and expect to see that information in the database (without date (year,month and day))
xor
attribute:time have time and date and that information go to the database (including the casting to the object).
Actually, rails take the two options. IMHO, this is a bug.
Am i correct? or i don't see some point of the rails design?

Resources