I am using RoR with MSSQL server as database, in a table I am saving date with 'date' datatype.
RoR saving the date correctly e.g if I am saving 2012-10-20 then it is saving 2012-10-20 but when I display it on front-hand it display like 2012-10-02 for 2013-10-20, 2012-10-01 for 2013-10-10, 2012-10-01 for 2013-10-15 etc.
What is going wrong... I can't figure it out
Edit
I am not asking for date formating technique. The issue is that date not fetched correctly as it saved in database, if I used datatime datatype instead of date datatype then all goes right.
You should do:
<%= #user.created_at.strftime("%Y-%m-%d") %>
Or if you want it to be more readable then:
<%= #user.created_at.to_date %>
You can try both which ever you like
EDIT
You have to do like mentioned above otherwise you have to create a new attribute to store date only. created_at is default timestamp type See this link. You can use any of both ways either convert created_at to date or introduce new column to table
How are you displaying it on your view?
For example the following would show "January 2010"
<%= #user.created_at.strftime("%B %Y") %>
You probably want year, month, date? So %Y %m %d
According to the github page of the adapter:
Date/Time Data Type Hinting
SQL Server 2005 does not include a native data type for just date or
time, it only has datetime. To pass the ActiveRecord tests we
implemented two simple class methods that can teach your models to
coerce column information to be cast correctly. Simply pass a list of
symbols to either the coerce_sqlserver_date or coerce_sqlserver_time
methods that correspond to 'datetime' columns that need to be cast
correctly.
class Topic < ActiveRecord::Base
coerce_sqlserver_date :last_read
coerce_sqlserver_time :bonus_time
end
This should point you in the right direction
Related
I have a model with :birth_date of type date.
I've tried to put a string like 3 janvier 1968 (French language) into that field and somehow in database I saw that PostgreSQL or someone else converted it into a date!
I also tried some other dates like 3 février 1968 or like 3 fevrier 1968 which didn't work and turned out to be NULL in db.
I can't find information about this feature anywhere. How does this work?
Rails knows that attribute is a Date from the database definition, so it converts the string you give it to a Date. If you create a new instance of your model in the Rails console and assign to birth_date, you can show that it's already a Date even before you save it to the database:
m = Model.new # Use your model name
m.birth_date = "3 février 1968"
m.birth_date.class
The console should tell you that m.birth_date is a Date.
So the conversion to Date is done before you save the model to the database. Rails defines a String::to_date method that calls the Ruby ::Date.parse method, which converts various human-readable date strings into a Date (https://ruby-doc.org/stdlib-2.3.1/libdoc/date/rdoc/Date.html#method-c-parse). In the Rails source, you'll see that whatever you assign to a Date attribute is converted to a Date with the to_date method. So when you assign a String, it happens via String::to_date which calls Date.parse.
As you mentioned in your comment, Date.parse seems to take a fairly loose approach to the months when they're spelled out. I tried a variety of English, French, and Spanish months in Date.parse, and as long as the first three letters of the non-English month are the same as the English month, Date.parse will convert them. But if the first three letters are different, then Date.parse throws an error.
if you have a column in the database as type 'date', it will only save as a date. Rails does it's best to convert a string into a recognized date if possible. You should always pass the 'birth_date' data as a date (i.e. use a date_field). Otherwise, if you REALLY want to store it as a string, the birth_date column must be of type string in the database
I have a column called test_date, type datetime in General Exam table. I built a form to create and update GeneralExam, on form, I allow User choose a date and time throught jQuery UI Datepicker.
After user choose date and time, it will displayed in textfield, like:
25-11-2012 16:30
It is my current time. When I run in console, I see the test_date was saved in database is:
2012-11-25 09:30:00
And when I get object GeneralExam, and get test_date value, it is:
g = GeneralExam.last
g.test_date
=> Sun, 25 Nov 2012 16:30:00 ICT +07:00
I think test_date is converted, because I set up in application.rb is:
config.time_zone = 'Hanoi'
But when I update a General Exam on form, it still display the time was saved in database, not my local timezone, it means it display:
2012-11-25 09:30:00
But I want it is like what I chose on form:
25-11-2012 16:30:00
How can I set up for display datetime column in local time?
And I think the order of date was reversed, when I choose date, it is 25-11-2012, but when it displayed it was 2012-11-25, Why it reversed the order?
After few hours I search on google and stackoverflow, I think I found what I want. I have looked at this question and find some information about strftime method. This is what information I need to solve my problem.
First, How to display datetime was saved in UTC as local time when display it:
Value was saved: 2012-11-25 09:30:00
Value I want display on form (ICT +7:00): 25-11-2012 16:30:00
To display value I want, I used this on form (I used simple_form):
<%= f.input :test_date, as: :string, label: false, input_html: { id: "datetime_picker", value: f.object.test_date.strftime("%d-%m-%Y, %H:%M") } %>
I have got value in database and format it by:
value: f.object.test_date.strftime("%d-%m-%Y, %H:%M") } %>
And when I want display test_date in table data, I also used strftime("%d-%m-%Y, %H:%M") to display datetime format as I want.
The proper setting is related with your Rails config , but also with your DB config . There is a Railscast , explaining how to avoid most of the gotchas . For consistency all the dates and times are saved in the database in UTC . The conversion is made by Rails config , depending on your config.time_zone . In this case you should try :
Time.zone.now
which takes in account the configuration in Rails and is different from:
Time.now
I'm writing an app that keeps track of school classes.
I need to store the schedule. For example: Monday-Friday from 8:am-11am.
I was thinking about using a simple string column but I'm going to need to make time calculations later.
For example, I need to store a representation of 8am, such as start_at:8am end_at:11am
So how should I store the time? What datatype should I use? Should I store start time and number of seconds or minutes and then calculate from there? or is there an easier way?
I use MySQL for production and SQLite for development.
I made an app recently that had to tackle this problem. I decided to store open_at and closed_at in seconds from midnight in a simple business hour model. ActiveSupport includes this handy helper for finding out the time in seconds since midnight:
Time.now.seconds_since_midnight
This way I can do a simple query to find out if a venue is open:
BusinessHour.where("open_at > ? and close_at < ?", Time.now.seconds_since_midnight, Time.now.seconds_since_midnight)
Any tips for making this better would be appreciated =)
If you're using Postgresql you can use a time column type which is just the time of day and no date. You can then query
Event.where("start_time > '10:00:00' and end_time < '12:00:00'")
Maybe MySQL has something similar
Check out the gem 'tod' for Rails 4 or Time_of_Day for Rails 3. They both solve the problem of storing time in a database while using an an Active Record model.
SQL has a time data type but Ruby does not. Active Record addresses this difference by representing time attributes using Ruby’s Time class on the canonical date 2000-01-01. All Time attributes are arbitrarily assigned the same dates. While the attributes can be compared with one another without an issue, (the dates are the same), errors arise when you attempt to compare them with other Time instances. Simply using Time.parse on a string like ”10:05” adds today’s date to the output.
Lailson Bandeira created a created solution for this problem, the Time_of_Day gem for Rails 3. Unfortunately the gem is no longer maintained. Use Jack Christensen’s ‘tod’ gem instead. It works like a charm.
This ruby gem converts time of day to seconds since midnight and back. The seconds value is stored in the database and can be used for calculations and validations.
Define the time of day attributes:
class BusinessHour < ActiveRecord::Base
time_of_day_attr :opening, :closing
end
Converts time of day to seconds since midnight when a string was set:
business_hour = BusinessHour.new(opening: '9:00', closing: '17:00')
business_hour.opening
=> 32400
business_hour.closing
=> 61200
To convert back to time of day:
TimeOfDayAttr.l(business_hour.opening)
=> '9:00'
TimeOfDayAttr.l(business_hour.closing)
=> '17:00'
You could also omit minutes at full hour:
TimeOfDayAttr.l(business_hour.opening, omit_minutes_at_full_hour: true)
=> '9'
I would store the starting hour and the duration within the database, using two integer columns.
By retrieving both values, you could convert the starting hour as in (assuming that you know the day already:
# assuming date is the date of the day, datetime will hold the start time
datetime = date.change({:hour => your_stored_hour_value , :min => 0 , :sec => 0 })
# calculating the end time
end_time = datetime + your_stored_duration.seconds
Otherwise, hava a look at Chronic. The gem makes handling time a little bit easier. Note that the changemethod is part of rails, and not available in plain Ruby.
The documentation on DateTime for plain Ruby can be found here.
Also, whatever you do, don't start storing your dates/time in 12-hour format, you can use I18nin Rails to convert the time:
I18n.l Time.now, :format => "%I.%m %p", :locale => :"en"
I18n.l Time.now + 12.hours, :format => "%I.%m %p", :locale => :"en"
You can also get from this notation, that you can store you duration in hours, if you want, you can then convert them rather easily by:
your_stored_value.hours
if stored as an integer, that is.
Suggestion:
Don’t worry about a specific datatype for that. A simple solution would be:
In the database, add an integer type column for start_time and another for end_time. Each will store the number of minutes since midnight.
Ex: 8:30am would be stored as 510 (8*60+30)
In the form, create a select field (dropdown) that displays all available times in time format:Ex.: 10am, 10:30am and so on.
But the actual field values that get saved in the database are their integer equivalents:
Ex: 600, 630 and so on (following the example above)
I assume you are using some kind of database for this. If you are using MySQL or Postgresql, you can use the datetime column type, which Ruby/Rails will automatically convert to/from a Time object when reading/writing to the database. I'm not sure if sqlite has something similar, but I imagine it probably does.
From the SQLite 3 website,
"SQLite does not have a storage class set aside for storing dates and/or times. Instead, the built-in Date And Time Functions of SQLite are capable of storing dates and times as TEXT, REAL, or INTEGER values:
TEXT as ISO8601 strings ("YYYY-MM-DD HH:MM:SS.SSS").
REAL as Julian day numbers, the number of days since noon in Greenwich on November 24, 4714 B.C. according to the proleptic Gregorian calendar.
INTEGER as Unix Time, the number of seconds since 1970-01-01 00:00:00 UTC.
Applications can chose to store dates and times in any of these formats and freely convert between formats using the built-in date and time functions."
You can then manipulate the values using the Date and Time functions outlined here.
I am using a js calendar that inserts a string into a text field for submission as a datetime value. Not sure if it matters but I am using SQLite for now.
I am setting the format as follows (in an initializer):
Time::DATE_FORMATS[:default] = '%m/%d/%Y %H:%M'
Time::DATE_FORMATS[:db] = '%m/%d/%Y %H:%M'
This isn't working because Rails is apparently validating the date using a different format.
For example, if I set it as follows:
myobject.my_datetime = '06/30/2012 00:00'
it ends up null (the SQL query itself generated by ActiveRecord sets it to NULL). If I set it to a day less than or equal to 12 the date part ends up correct (but the generated SQL query still shows the string with the day before the month, i.e. in the above example the SQL query has the string as '30/06/2012 05:00:000000').
As you can see it also seems to be adding 5 hours for UTC(?) even though I have config.time_zone set to eastern time.
Behavior is the same either from console or via form submission.
Any suggestions on what I am missing?
UPDATE:
When I follow jdoe's suggestion and do this:
myobject.my_datetime = Time.strptime('06/30/2012 08:00', '%m/%d/%Y %H:%M')
The generated query now looks correct (ignoring the 4 hour difference):
UPDATE "myjoin_table" SET "my_datetime" = '06/30/2012 04:00.000000' .....
and it winds up in the database that way.
But when I reload the object the value in the AR object is initialized to nil.
I guess I'll just parse the string piece by piece in my controller action and set the parameters to update_attributes manually. This is harder than it should be.
ActiveRecord stores date/time in UTC+00:00. If you're living in the +5 zone, ActiveRecord will subtract 5 hours on assigning automatically. So, your current time zone just says how many hours has to be added/subtracted from your local time.
About parsing. Did you try the following?
myobject.my_datetime = Time.strptime('06/30/2012 00:00', '%m/%d/%Y %H:%M')
Rails time/date settings are made for showing, not for assignment. It's not a brilliant idea to get strings from a user and assign them to your date/time attributes. You'd better use proper time objects in assignment instead of stings. The strptime method will raise the ArgumentError if some user is trying to be a hacker. Your record.date_time='string' fails silently.
UPD: Usage Example
p = Product.first
p.last_visited = Time.strptime('06/30/2012 00:00', '%m/%d/%Y %H:%M')
p.save # leads to UPDATE "products" SET "last_visited" = '2012-06-29 21:00:00.000000'
Product.last_visited.localtime.strftime('%m/%d/%Y %H:%M') # => "06/30/2012 00:00"
As you see, time is stored and retrieved w/o any problems.
UPD 2: I18n
Locate your config/locales/en.yml. Add the following to it:
en:
time:
formats:
default: '%m/%d/%Y %H:%M'
To parse your time use t(or translate) helper:
#time = Time.strptime('06/30/2012 00:00', t('time.formats.default'))
Use l(or localize) helper to show time in your format:
= l #time
I have made a huge mistake.
Initially I created my model with a field called start_date and made it a string to keep track of event dates.
Now I'm realizing it would be nice to have this field as a date type so I could do calculations like find events where start_date is between today and 1 month from now.
This issue is I already have 500 records so starting over would suck....
The format of the start_date field is in a rails compatible type " 2011-02-21 22:00:00 " but its just a string...
Is there anything I can do?
Create a migration to add a start_date_2 column of the type you want
Model.find(:all).each { |i| i.update_attributes(:start_date_2, Date.new(i.start_date)) }
Create a migration to delete start_date and to rename start_date_2 to start_date
This should work, out of the top of my head.
You could try just doing an EXPORT on the table (making sure to only export data, do not include CREATE and/or DROP table commands).
Create a migration to change the datatype
TRUNCATE the table
IMPORT the data
Since the column is now a date field, it should parse the input of a string just fine, considering that's what you provide it anyway
Perhaps, you can do away with the risk of changing column type if there is live data. The parse methods can save you. From Ruby-doc:
parse(str='-4712-01-01', comp=true, sg=ITALY)
Create a new Date object by parsing from a String, without specifying the format.
str is a String holding a date representation. comp specifies whether to interpret 2-digit years as 19XX (>= 69) or 20XX (< 69); the default is not to. The method will attempt to parse a date from the String using various heuristics; see _parse in date/format.rb for more details. If parsing fails, an ArgumentError will be raised.
Here and here are some more examples / explanations. Hope this helps.