Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Fixing discrepancy between date.to_s(:long) and localize(date, format: :long) #14245

Open
wants to merge 11 commits into from

6 participants

@oliveiraethales

This is an attempt to fix #14237 using the format string kindly provided by @gabrielecirulli

Feedback and review is welcome <3

activesupport/test/core_ext/date_ext_test.rb
@@ -28,6 +28,12 @@ def test_to_s
assert_equal "2005-02-21", date.to_s(:iso8601)
end
+ def test_to_s_one_digit_day
+ date = Date.new(2005, 2, 2)
+
@pixeltrix Owner

I don't think we need this empty line

Oops, that one got unnoticed. Thanks for pointing out, will fix it (:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
activesupport/test/i18n_test.rb
@@ -26,7 +26,7 @@ def test_date_localization_with_short_format
end
def test_date_localization_with_long_format
- assert_equal @date.strftime("%B %d, %Y"), I18n.localize(@date, :format => :long)
+ assert_equal @date.strftime("%B %-e, %Y"), I18n.localize(@date, :format => :long)
@pixeltrix Owner

I prefer to use literal expected values - using an dynamic one makes it possible that a bug in strftime goes unnoticed. Can you convert all the @date and @time values in this test file to literal ones - thanks!

Sure! Will be a pleasure :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@gabrielecirulli
@oliveiraethales

@pixeltrix Done! Let me know if there's anything else before squashing (:
Btw, does this requires a Changelog update?

activesupport/test/i18n_test.rb
@@ -10,39 +10,39 @@ def setup
def test_time_zone_localization_with_default_format
now = Time.local(2000)
- assert_equal now.strftime("%a, %d %b %Y %H:%M:%S %z"), I18n.localize(now)
+ assert_equal "Sat, 01 Jan 2000 00:00:00 -0200", I18n.localize(now)
@pixeltrix Owner

This test fails on Travis because the default timezone there is UTC - you need to make the test independent of the timezone. Either set the timezone and restore it with an ensure block or use Time#in_time_zone to convert it to a known one - the latter is easiest in this case.

Nice, thanks for pointing that one! :D
Just to check if I understood it correctly... using something like 'I18n.localize(now.in_time_zone('Alaska')' would be a valid way?

@pixeltrix Owner

using something like 'I18n.localize(now.in_time_zone('Alaska')'

Use it with Time.utc when creating the local variable, e.g:

now = Time.utc(2000).in_time_zone('Alaska')

otherwise you'll still be system configuration dependent.

Nice! Thanks for the insight :3 Will do that

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pixeltrix
Owner

Btw, does this requires a Changelog update?

Yes, since we're changing the default to not including zeros.

@gabrielecirulli

Do you guys think it might also make sense to change the :long format for Time to make use of %-e instead of %d (as it currently does) on the grounds of consistency?

en:
  time:
    formats:
      long: "%B %d, %Y %H:%M"
@pixeltrix
Owner

@gabrielecirulli yes, they should be consistent - good catch.

@oliveiraethales

There you go guys! Please let me know if there's anything else you guys think might be good. (:

@gabrielecirulli

Hey @oliveiraethales! Great work! I hope this is not too much to ask, I think we should also consider fixing the discrepancies between the other formats, as they seem to be even bigger. I've highlighted them for you and provided solutions that you could use:


:short format

date = Date.new(2000, 2, 1)

date.to_s(:short)            #=> " 1 Feb"
I18n.l(date, format: :short) #=> "Feb 01"

The format used by Date#to_formatted_s (%e %b) causes the number to be padded with empty spaces. I believe it's undesirable behavior.

The format uses by I18n::localize is saner but the number is still padded with zeroes. In my opinion, that doesn't look very natural.

In this case, I would suggest that the %b %-e format is used instead:

date.strftime("%b %-e") #=> "Feb 1"

In the same way, the :short time format in en.yml should become:

en:
  time:
    formats:
      short: "%b %-e %H:%M"

:default format

This one is a bit tougher. Date#to_formatted_s uses Ruby's default Date#to_s behavior when the format is :default, and I think we shouldn't modify that. The output in that case is:

date = Date.new(2000, 2, 1)

date.to_s(:default)                    #=> "2000-02-01"
I18n.l(date, format: :default)         #=> "2000-02-01"

date.to_time.to_s                      #=> "2000-02-01 00:00:00 +0100"
I18n.l(date.to_time, format: :default) #=> "Tue, 01 Feb 2000 00:00:00 +0100"

I believe the only thing it makes sense to change is the :default time format in en.yml, which is completely inconsistent with the rest. Here's what I think it should look like:

en:
  time:
    formats:
      default: "%Y-%m-%d %H:%M:%S %z"

The output of that format is: "2000-02-01 00:00:00 +0100"


I think that's it as far as modifications go :smile:

The other formats in Date::DATE_FORMATS don't really have a counterpart in I18n::localize formats, so I think there's not much to do.

@gabrielecirulli

I think this change might also cause some issues for people who rely on the default behavior and update their Rails app to the latest version, so I think it might make sense to note the change on upgrading guides if possible.

@oliveiraethales

Hey mate! :D What a lovable research, very nice man! :3
I agree with upgrading the guides, I'll happily do them also!

I just don't know if it would be good to continue using this PR for this or if another one should be opened. What do you think @pixeltrix ?

@pixeltrix
Owner

Keep it in the same request - easier to revert if necessary

@oliveiraethales

Alright! Will update the other formats and the docs also.

@gabrielecirulli

@oliveiraethales Please note that I made a small mistake in my suggestion for en.yml in the case of the :default time format: I forgot to include hours, minutes and seconds in the format.

I've updated my previous comment with the correct format and I'll also paste it here for clarity:

en:
  time:
    formats:
      default: "%Y-%m-%d %H:%M:%S %z"

Sorry for the mess!

@oliveiraethales

Hey guys! There it is, fixed the other formats and updated the guides also.
Please review and let me know it there's anything else :3

@pixeltrix pixeltrix commented on the diff
actionview/test/template/date_helper_test.rb
@@ -3197,7 +3197,7 @@ def test_time_tag_with_given_block
def test_time_tag_with_different_format
time = Time.new(2013, 2, 20, 0, 0, 0, '+00:00')
- expected = '<time datetime="2013-02-20T00:00:00+00:00">20 Feb 00:00</time>'
+ expected = '<time datetime="2013-02-20T00:00:00+00:00">Feb 20 00:00</time>'
@pixeltrix Owner

I'm not sure about changing the order of day and month in the short format - I think that may be one standardisation too far

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pixeltrix
Owner

Other than the question of the order of the short format it looks good - obviously the commits need to be squashed. I'll ask the other team members about the short format and get back to you.

@gabrielecirulli
@robin850 robin850 added this to the 4.2.0 milestone
@oliveiraethales

Hey @pixeltrix! (:

Sorry to bother, but have you been able to confirm about the short format?

Thanks a lot!

@robin850
Collaborator

I did not comment yet because I was not sure that everything was finished but could you please just wrap your guide and changelog additions around 80 chars please ? Beside this, it looks great, thank you for the work here! :+1:

@oliveiraethales

Sure thing @robin850! :D Will do that

@pftg

@oliveiraethales please squash commits too

@oliveiraethales

Yup, I'm just waiting for @pixeltrix considerations and then I'll squash (:

@rafaelfranca rafaelfranca modified the milestone: 4.2.0, 5.0.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
2  actionview/test/template/date_helper_test.rb
@@ -3197,7 +3197,7 @@ def test_time_tag_with_given_block
def test_time_tag_with_different_format
time = Time.new(2013, 2, 20, 0, 0, 0, '+00:00')
- expected = '<time datetime="2013-02-20T00:00:00+00:00">20 Feb 00:00</time>'
+ expected = '<time datetime="2013-02-20T00:00:00+00:00">Feb 20 00:00</time>'
@pixeltrix Owner

I'm not sure about changing the order of day and month in the short format - I think that may be one standardisation too far

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
assert_equal expected, time_tag(time, :format => :short)
end
View
10 activesupport/CHANGELOG.md
@@ -1,3 +1,13 @@
+* Fixing discrepancy between Date and Time to_s and I18n.localize for default,
+ short and long formats. Previously, a call to Date#to_s when there was only
+ one digit in the day would cause a zero to be added before the day digit,
+ while calling I18n#localize would add an unnecessary space. Now, both calls
+ return the Date/Time without the zero and the space.
+
+ Fixes #14245.
+
+ *Thales Oliveira, Gabriele Cirulli*
+
* Change the signature of `fetch_multi` to return a hash rather than an
array. This makes it consistent with the output of `read_multi`.
View
4 activesupport/lib/active_support/core_ext/date/conversions.rb
@@ -5,8 +5,8 @@
class Date
DATE_FORMATS = {
- :short => '%e %b',
- :long => '%B %e, %Y',
+ :short => '%b %-e',
+ :long => '%B %-e, %Y',
:db => '%Y-%m-%d',
:number => '%Y%m%d',
:long_ordinal => lambda { |date|
View
10 activesupport/lib/active_support/locale/en.yml
@@ -5,8 +5,8 @@ en:
# When no format has been given, it uses default.
# You can provide other formats here if you like!
default: "%Y-%m-%d"
- short: "%b %d"
- long: "%B %d, %Y"
+ short: "%b %-e"
+ long: "%B %-e, %Y"
day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday]
abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat]
@@ -22,9 +22,9 @@ en:
time:
formats:
- default: "%a, %d %b %Y %H:%M:%S %z"
- short: "%d %b %H:%M"
- long: "%B %d, %Y %H:%M"
+ default: "%Y-%m-%d %H:%M:%S %z"
+ short: "%b %-e %H:%M"
+ long: "%B %-e, %Y %H:%M"
am: "am"
pm: "pm"
View
8 activesupport/test/core_ext/date_ext_test.rb
@@ -20,7 +20,7 @@ def test_tomorrow_in_calendar_reform
def test_to_s
date = Date.new(2005, 2, 21)
assert_equal "2005-02-21", date.to_s
- assert_equal "21 Feb", date.to_s(:short)
+ assert_equal "Feb 21", date.to_s(:short)
assert_equal "February 21, 2005", date.to_s(:long)
assert_equal "February 21st, 2005", date.to_s(:long_ordinal)
assert_equal "2005-02-21", date.to_s(:db)
@@ -28,6 +28,12 @@ def test_to_s
assert_equal "2005-02-21", date.to_s(:iso8601)
end
+ def test_to_s_one_digit_day
+ date = Date.new(2005, 2, 2)
+ assert_equal "Feb 2", date.to_s(:short)
+ assert_equal "February 2, 2005", date.to_s(:long)
+ end
+
def test_readable_inspect
assert_equal "Mon, 21 Feb 2005", Date.new(2005, 2, 21).readable_inspect
assert_equal Date.new(2005, 2, 21).readable_inspect, Date.new(2005, 2, 21).inspect
View
20 activesupport/test/i18n_test.rb
@@ -9,40 +9,40 @@ def setup
end
def test_time_zone_localization_with_default_format
- now = Time.local(2000)
- assert_equal now.strftime("%a, %d %b %Y %H:%M:%S %z"), I18n.localize(now)
+ now = Time.utc(2000).in_time_zone('Alaska')
+ assert_equal "1999-12-31 15:00:00 -0900", I18n.localize(now)
end
def test_date_localization_should_use_default_format
- assert_equal @date.strftime("%Y-%m-%d"), I18n.localize(@date)
+ assert_equal "2008-07-02", I18n.localize(@date)
end
def test_date_localization_with_default_format
- assert_equal @date.strftime("%Y-%m-%d"), I18n.localize(@date, :format => :default)
+ assert_equal "2008-07-02", I18n.localize(@date, :format => :default)
end
def test_date_localization_with_short_format
- assert_equal @date.strftime("%b %d"), I18n.localize(@date, :format => :short)
+ assert_equal "Jul 2", I18n.localize(@date, :format => :short)
end
def test_date_localization_with_long_format
- assert_equal @date.strftime("%B %d, %Y"), I18n.localize(@date, :format => :long)
+ assert_equal "July 2, 2008", I18n.localize(@date, :format => :long)
end
def test_time_localization_should_use_default_format
- assert_equal @time.strftime("%a, %d %b %Y %H:%M:%S %z"), I18n.localize(@time)
+ assert_equal "2008-07-02 16:47:01 +0000", I18n.localize(@time)
end
def test_time_localization_with_default_format
- assert_equal @time.strftime("%a, %d %b %Y %H:%M:%S %z"), I18n.localize(@time, :format => :default)
+ assert_equal "2008-07-02 16:47:01 +0000", I18n.localize(@time, :format => :default)
end
def test_time_localization_with_short_format
- assert_equal @time.strftime("%d %b %H:%M"), I18n.localize(@time, :format => :short)
+ assert_equal "Jul 2 16:47", I18n.localize(@time, :format => :short)
end
def test_time_localization_with_long_format
- assert_equal @time.strftime("%B %d, %Y %H:%M"), I18n.localize(@time, :format => :long)
+ assert_equal "July 2, 2008 16:47", I18n.localize(@time, :format => :long)
end
def test_day_names
View
13 guides/source/i18n.md
@@ -434,6 +434,19 @@ So that would give you:
![rails i18n demo localized time to pirate](images/i18n/demo_localized_pirate.png)
+It is important to note that the standard long, short and default Date/Time formats used by Rails do not pad one digit days with zeroes or spaces, e.g.:
+
+```erb
+# app/views/home/index.html.erb
+
+<h1><%=t :hello_world %></h1>
+<p><%= l Date.new(2014, 2, 2), format: :short %></p>
+<p><%= l Date.new(2014, 2, 2), format: :long %></p>
+<p><%= l Date.new(2014, 2, 2), format: :default %></p>
+<p><%= l Date.new(2014, 2, 2) %></p>
+```
+The same applies for the Time object.
+
TIP: Right now you might need to add some more date/time formats in order to make the I18n backend work as expected (at least for the 'pirate' locale). Of course, there's a great chance that somebody already did all the work by **translating Rails' defaults for your locale**. See the [rails-i18n repository at GitHub](https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale) for an archive of various locale files. When you put such file(s) in `config/locales/` directory, they will automatically be ready for use.
### Inflection Rules For Other Locales
Something went wrong with that request. Please try again.