I am calling the date a record was created at in a basic app running Rails 3.1.
<%= #issue.created_at %>
The above outputs the following timestamp:
2011-09-10 14:44:24 UTC
What is the simplest way of altering the way this displays? I would like something like this:
10 Sept. 2011
and then somehow call it again with a different format:
14:44
so I can call it twice and merge the two together:
10 Sept. 2011
14:44
The reason I want to call it twice rather than create a helper to format a two line date/time is to allow me to call the date in some places and just the time in others.
The simplest thing to do is to use the strftime function
# Day / Month / Year
#issue.created_at.strftime("%d %b. %Y")
# Hour:Min
#issue.created_at.strftime("%H:%M")
You could put those two calls in separate helpers if you find yourself doing it a lot.
I would use I18n. Take a look at some example http://guides.rubyonrails.org/i18n.html#adding-date-time-formats. It's a clean and flexible way of formatting dates and times.
<%= l(#issue.created_at, :format=>:your_format) %>
in locale YAML (app/config/locale/country_id.yml) you must declare
time:
formats:
your_format: '%d %b. %Y'
your_another_format: '%I:%M'
Date formatting should be declared inside your i18n YAML definition file for easy configure, and other date format could be found here
Check out http://www.foragoodstrftime.com/ for an easy way to customize date/time formatting #spike
You can do:
#issue.created_at.to_date.iso8601
to_s also takes format input argument:
http://apidock.com/rails/ActiveSupport/TimeWithZone/to_s
Related
I'm in the U.S., and we usually format dates as "month/day/year". I'm trying to make sure that my Rails app, using Ruby 1.9, assumes this format everywhere, and works the way it did under Ruby 1.8.
I know that lots of people have this issue, so I'd like to create a definitive guide here.
Specifically:
'04/01/2011' is April 1, 2011, not Jan 4, 2011.
'4/1/2011' is also April 1, 2011 - the leading zeros should not be necessary.
How can I do this?
Here's what I have so far.
Controlling Date#to_s behavior
I have this line in application.rb:
# Format our dates like "12/25/2011'
Date::DATE_FORMATS[:default] = '%m/%d/%Y'
This ensures that if I do the following:
d = Date.new(2011,4,1)
d.to_s
... I get "04/01/2011", not "2011-04-01".
Controlling String#to_date behavior
ActiveSupport's String#to_date method currently looks like this (source):
def to_date
return nil if self.blank?
::Date.new(*::Date._parse(self, false).values_at(:year, :mon, :mday))
end
(In case you don't follow that, the second line creates a new date, passing in year, month and day, in that order. The way it gets the year, month and day values is by using Date._parse, which parses a string and somehow decides what those values are, then returns a hash. .values_at pulls the values out of that hash in the order Date.new wants them.)
Since I know that I will normally pass in strings like "04/01/2011" or "4/1/2011", I can fix this by monkeypatching it like this:
class String
# Keep a pointer to ActiveSupport's String#to_date
alias_method :old_to_date, :to_date
# Redefine it as follows
def to_date
return nil if self.blank?
begin
# Start by assuming the values are in this order, separated by /
month, day, year = self.split('/').map(&:to_i)
::Date.new(year, month, day)
rescue
# If this fails - like for "April 4, 2011" - fall back to original behavior
begin
old_to_date
rescue NoMethodError => e
# Stupid, unhelpful error from the bowels of Ruby date-parsing code
if e.message == "undefined method `<' for nil:NilClass"
raise InvalidDateError.new("#{self} is not a valid date")
else
raise e
end
end
end
end
end
class InvalidDateError < StandardError; end;
This solution makes my tests pass, but is it crazy? Am I just missing a configuration option somewhere, or is there some other, easier solution?
Are there any other date-parsing cases I'm not covering?
Gem: ruby-american_date
This gem was created since I asked this question. I'm now using it and have been pleased.
https://github.com/jeremyevans/ruby-american_date
Date.strptime is probably what you're looking for in ruby 1.9.
You're probably stuck monkeypatching it onto string.to_date for now, but strptime is the best solution for parsing dates from strings in ruby 1.9.
Also, the formats are symmetric with strftime as far as I know.
you can use rails-i18n gem or just copy the en-US.yml and set your default locale "en-US" in config/application.rb
For parsing US-style dates, you could use:
Date.strptime(date_string, '%m/%d/%Y')
In console:
> Date.strptime('04/01/2011', '%m/%d/%Y')
=> Fri, 01 Apr 2011
> Date.strptime('4/1/2011', '%m/%d/%Y')
=> Fri, 01 Apr 2011
Use REE? :D
Seriously though. If this is a small app you have complete control over or you are standardizing on that date format, monkey patching for a project is totally reasonable. You just need to make sure all your inputs come in with the correct format, be it via API or website.
Instead of using to_s for Date instances, get in the habit of using strftime. It takes a format string that gives you complete control over the date format.
Edit:
strptime gives you full control over the parsing by specifying a format string as well. You can use the same format string in both methods.
Another option is Chronic - http://chronic.rubyforge.org/
You just need to set the endian preference to force only MM/DD/YYYY date format:
Chronic::DEFAULT_OPTIONS[ :endian_precedence ] = [ :middle ]
However the default for Chronic is the out-of-order US date format anyway!
I am building a simple event system and i am having problem with rails time helper conversions. I want to be able to have a 12hour clock that has an output of something like 12:00am or 12:00pm using something like <%= event.start_at %> to give the time output in the 12hour clock format
If event.start_at is already a date or time object (e.g. an ActiveRecord instance) then you could do something like:
<%= event.start_at.to_s(:my_format) %>
You'd need to define :my_format in an initializer:
# config/initializers/date_and_time_formats.rb
Time::DATE_FORMATS[:my_format] = '%I:%M%P' # 12:30pm
You can tweak the format to your liking and use it over and over again using to_s(:my_format). #Dave Newton pointed out where to go for formatting above.
http://apidock.com/ruby/Time/strftime
In my view I want to display the current date in "mm/dd/yyyy" format.
<%= Time.now.strftime("%m/%d/%Y") %>
You could simply do (substitute in Time for DateTime if using straight Ruby -- i.e. no Rails):
DateTime.now.strftime('%m/%d/%Y')
If you're using that format a lot, you might want to create a date_time_formats initializer in your RAILS_ROOT/config/initializers folder (assuming Rails 2), something like this:
# File: date_time_formats.rb
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(
:human => "%m/%d/%Y"
)
Which will then let you use the more friendly version of DateTime.now.to_s(:human) in your code.
I think you can use .strftime:
t = Time.now()
t.strftime("The date is %m/%d/%y")
This should give "The date is 09/09/10". See here for a great list of the format codes for .strftime.
If you don't need the full year you could try
Time.now.strftime('%D')
For instance, if I have a Time.now, how would I convert that to a friendly url string?
Time.now.some_method_here => some_url_friendly_string_here
I believe there is a built-in Ruby method to do so, but I can't seem to locate it on Google. Any ideas?
As you're using Rails (as indicated by your tag), you can use .to_s:
Time.now.to_s
You can specify a time format to the method, which will format the string differently, such as Time.now.to_s(:db). Please see this link for the default date formats. If you don't specify a format, it'll use the same as strftime.
The next part of that page also describes how to add your own time formats, which is very simple:
# Initializer
Time::DATE_FORMATS[:month_and_year] = "%B %Y"
# Any code
Time.now.to_s(:month_and_year) # => September 2010
Everything in ruby is open and extensible
class Time
def to_url_string
self.strftime("%H:%M:%s")
end
end
You can use the strftime method. It's a bit cryptic, but if you look at the docs, you can pick out the year, month, day, etc.
For example, Time.now.strftime("%H:%M:%s") will give the time in hours, minutes and seconds.
You might consider using the xmlschema method which will return a date/time in the format:
CCYY-MM-DDThh:mm:ssTZD
or
CCYY-MM-DDThh:mm:ss.sssTZD
depending on the value of the fraction_digits argument.
This would give you a time like:
2010-09-15T20:31:15+05:00
for example.
See the docs for more info and a link to the code.
I've been pulling my hair out trying to work with Time in Rails. Basically I need to set all time output (core as well as ActiveSupport) to the server's local time -- no GMT, no UTC, etc. I've seen various posts relating to Time, but they usually involve someone's need to set it for each user. Mine isn't nearly as complex, I simply want consistency when I use any Time object. (I'd also appreciate not receiving errors every 3 seconds telling me that I can't convert a Fixnum (or some other type) to string -- it's Ruby, just do it!)
I also seem to be getting drastically different times for Time.new vs the ActiveSupport 1.second.ago. Anyway, does anyone have any quality suggestions as regards working with Time in Rails?
If you just want Time objects to be consistent, then why not stick with UTC? I just tried Time.new and 1.second.ago using script/console and I get the same output (give or take a second for typing the command). How are you doing it?
Somewhere in your initializers, define the format(s) that you want to use.
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(:default => '%m/%d/%Y %H:%M')
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(:my_special_format => '%H:%M %p')
Then when you want to print a Time object, it works like the following example. Notice that the Time object in my console is already aware of my time zone. I'm not performing any magical transformations here.
>> t = Time.now
=> Wed Jul 15 18:47:33 -0500 2009
>> t.to_s
=> "07/15/2009 18:47"
>> t.to_s(:my_special_format)
=> "18:47 PM"
Calling Time#to_s uses the :default format, or you can pass in the name of the format you'd rather use like I did with :my_special_format.
You can see the various options for formatting a Time object here.
If u don't want to store each user time setting, the only solution is to use javascript time system because it work on user client time. For example i have an application that each time user try it, the app will create some example data with each data have a initial date value "today". At first time, it confuse me a lot because my host server is in australia and lot of user is on western part, so sometime the initial date value is not "today", it said "yesterday" because of different time region.
After a couple day of headache i finally take decision to JUST use javascript time system and include it in the link, so when user click the "try now" link it will also include today date value.
<% javascript_tag do -%>
var today = new Date();
$("trynow").href = "<%= new_invitation_path %>?today=" + today.toLocaleString();
<% end -%>
Add the following to config/environment.rb to handle time correctly and consistently all the time within the context of Rails. It's important to know that it will store your times to the database in UTC -- but this is what you want -- all the conversion is done automatically.
config.time_zone = 'Pacific Time (US & Canada)'
You can run rake time:zones:local from your Rails root directory to get a list of valid time zone strings in your area.
A quick addition to the DATE_FORMAT solution posted above. Your format can be a string, in which case it works as noted above by calling strftime, but you can also define the format as a lambda:
CoreExtensions::Time::Conversions::DATE_FORMATS.merge! :my_complex_format => lambda {|time|
# your code goes here
}