Ruby on Rails - Handling of DateTime.current and User Input Time - ruby-on-rails

I'm using Rails 3.2.9 with Postgres database and JRuby 1.7.12.
Application is running Ubuntu Server with GMT+7 Asia/Bangkok Time Zone.
config.time_zone is set to Bangkok
Postgres timezone is also set to Asia/Bangkok
In my invoice model, I have 2 datetime fields called document_date and movement_date
-> movement_date is generated by application using DateTime.current
-> document_date is input by the User (i.e 2014-07-28)
When User save the Invoice, both will be converted to UTC and saved into Database.
for movement_date, it is fine (as this is the expected behaviour)
for document_date, when it is convert to UTC, it will be saved as 2014-07-27 17:00.
How can I save document_date to 2014-07-28 00:00 into database without converting to UTC.
Your Help, Advise, Suggestion would be highly appreciated and Many Thanks in advance.
If there are any additional info I should add, kindly let me know.
EDIT: the field in postgresql for both is using Timestamp Without Time Zone

If i understood it correctly, you want the document_date (which is an user input) to be in UTC, rather than in your local time. Is it correct? If so, you'll have to change it manually, as Rails makes the assumption that you want it in your local time.
What you could do is set it manually, converting the date string to datetime (String#to_datime), just before the object saving on your controller. Something like that:
def create
#invoice = Invoice.new(params[:invoice])
#invoice.document_date = params[:invoice][:document_date].to_datetime
#invoice.save
end
String#to_datetime will create a UTC DateTime as long as the string doesn't have Time and TimeZone parts on it (ie: "2014-07-28 00:00:00 +0700" will be converted to Bangkok DateTime).

Related

TimeZone convertion in Ruby on Rails

Im my application.rb I've set: config.time_zone = 'Brasilia'. It's ok when I save datetimes in the system. The problem is that I receive datetimes from another system that is already on the correct timezone. So, when this datetime is saved on my RoR system, it's being saved wrongly. Example: The another system sends a datetime 2015-11-10 15:07:00 (that is already on the right timezone, ready to save). But my RoR saves it like 2015-11-10 13:07:00 -0200. Is there a way to tell Rails that this datetime is already on the correct timezone?
You need to tell Rails/Ruby which timezone the incoming datetime is in, see a list of timezones using rake time:zones:all and then use the right one in the following code, eg.
Time.use_zone("Montevideo") { Time.zone.parse "2015-11-10 15:07:00" }
That will return an ActiveSupport::TimeWithZone object with the correct timezone set, and then you'll just store it in your DB and Rails will convert it to the correct UTC time.

How to present Rails form datetime select in different time zone?

I would like to present a datetime select to the user in their preferred time zone but store the datetime as UTC. Currently, the default behavior is to display and store the datetime field using UTC. How can I change the behavior of this field without affecting the entire application (i.e. not changing the application default time zone)?
Update: This is not a per-user timezone. I don't need to adjust how times are displayed. Only these specific fields deal with a different time zone, so I would like the user to be able to specify the time in this time zone.
Here's how you can allow the user to set a date using a specific time zone:
To convert the multi-parameter attributes that are submitted in the form to a specific time zone, add a method in your controller to manually convert the params into a datetime object. I chose to add this to the controller because I did not want to affect the model behavior. You should still be able to set a date on the model and assume your date was set correctly.
def create
convert_datetimes_to_pdt("start_date")
convert_datetimes_to_pdt("end_date")
#model = MyModel.new(params[:my_model])
# ...
end
def update
convert_datetimes_to_pdt("start_date")
convert_datetimes_to_pdt("end_date")
# ...
end
def convert_datetimes_to_pdt(field)
datetime = (1..5).collect {|num| params['my_model'].delete "#{field}(#{num}i)" }
if datetime[0] and datetime[1] and datetime[2] # only if a date has been set
params['my_model'][field] = Time.find_zone!("Pacific Time (US & Canada)").local(*datetime.map(&:to_i))
end
end
Now the datetime will be adjusted to the correct time zone. However, when the user goes to edit the time, the form fields will still display the time in UTC. To fix this, we can wrap the fields in a call to Time.use_zone:
Time.use_zone("Pacific Time (US & Canada)") do
f.datetime_select :start_date
end
There are a couple of options:
Utilize the user's local timezone when displaying data to them. This is really easy with something like the browser-timezone-rails gem. See https://github.com/kbaum/browser-timezone-rails. It is essentially overriding the application timezone for each request based on the timezone detected from the browser. NOTE: it only uses the OS timezone, so it's not as accurate as an IP/geo based solution.
Setup your application timezone so that it is consistent with the majority of your user base. For example: config.time_zone = 'Mountain Time (US & Canada)'. This is a very standard thing to do in rails. Rails will always store the data in the DB as UTC, but will present / load it using the application timezone.
Create a timezone for your user model. Allow users to set this value in their account settings. And, then use a similar approach to that of the above gem does in the application_controller.

Saving a Rails Record with a specific Timezone

How to save an event in Berlin with its own specific timezone and the next event in Tijuana with a different one?
The user is asked to choose a City for the event, as a source for e.g. +02:00.
I would like to receive a time code like this:
eventstart = "2011-07-22T18:00:00+02:00"
How would you go about creating that form?
UPDATE:
Realized saving as standard UTC is fine for many reasons. So now I am altering a time string in the view to present a *distance_to_time_in_words* for eventstart, depending on the user's local time.
Event in Tijuana, viewing from Berlin time:
old_zone = Time.zone
#=> "Berlin"
Time.zone = "Tijuana"
t = Time.zone.parse(eventstart.to_s[0..-7])
#=> 2011-07-22 18:00:00 +08:00
Time.zone = old_zone
#=> "Berlin"
distance_of_time_in_words(Time.now.in_time_zone, t)
#=> "9 hours"
cumbersome, but works for now. Improvement ideas welcome!
Add a time_zone column to your database and use time_zone_select in your form to let user select the time_zone for which he is creating event.
And in the model you can convert the datetime to zone specific datetime and store utc in the database. You can use helper something like below
def local_time(date)
Time.use_zone(self.time_zone) do
Time.zone.at(date.to_i)
end
end

How to save dates in local timezone to db with rails3?

I have Rails3 application with model user and field expires_at created like this:
t.column :expires_at, :timestamp
In my database (postgresql) it has type:
timestamp without timezone
The problem is when I call:
#user.expires_at = Time.now
#user.save
it is saved into database with UTC timezone (my local time is UTC + 1:00, Warsaw) but I don't want that. I just want to have time with my local timezone saved into the database (2011-03-30 01:29:01.766709, not 2011-03-29 23:29:01.766709)
Can I achieve this using rails3?
For saving time in local timezone to database this has to be set in application.rb
config.active_record.default_timezone = :local
If you only want to use local times on certain columns, rather than as a global setting, then the Rails documentation tells us this:
# If your attributes are time zone aware and you desire to skip time zone conversion to the current Time#zone when reading certain attributes then you can do following:
class Topic < ActiveRecord::Base
self.skip_time_zone_conversion_for_attributes = [:written_on]
end
(This also skips time zone conversion on writing, not just reading). And you can pass in an array of symbols for multiple attributes.
I am not sure which versions of Rails this was introduced in, though.

time_select with 12 hour time and Time Zone in Ruby on Rails

I have the need to capture a time and time zone from users of a rails 2.3.8 app, but have been unable to think of a clean solution to create and parse the selections.
Ideally I would have a drop-down menus for the following:
hour (1-12)
minute (0-59)
AM/PM
Time Zone
Is there a gem/plugin that accomplishes what I am looking for? Will I need to store both the time and time zone in the database? What is the best strategy for storage?
I'll eventually need to spit these values out in UTC, but a user should be able to go back and review the time in the correct time zone.
You can get time zone selects with the appropriate methods:
time_zone_options_for_select
time_zone_select
Similarly, there's date_select for dates.
Storage:
If the timezone is specific to the user and doesn't change, then store their time zone in their user record and set it when you load the current_user. Rails will convert times to/from UTC and always store UTC in the database and do the automatic convert to that default timezone for you (including daylight savings!). Easiest way to do it.
use_zone(zone) lets you override the default zone for a block, so you can accept a form value and set it with that function and set your value in that block.
UPDATE: I wrote up some Rails timezone examples as a blog entry.
I personally used jQuery to change the display only:
ampm = ["12 AM","01 AM","02 AM","03 AM","04 AM","05 AM","06 AM","07 AM","08 AM","09 AM","10 AM","11 AM","12 PM","01 PM","12 PM","01 PM","02 PM","01 PM","02 PM","03 PM","04 PM","05 PM","06 PM","07 PM","08 PM","09 PM","10 PM","11 PM"]
j("#game_start_time_4i option").each(function(index,value){
j(value).html(ampm[index]);
});
Rails:
<%= datetime_select('game', 'start_time') %>

Resources