Skip to content

Commit 4cfc467

Browse files
sorentwopixeltrix
authored andcommitted
Customize subsecond digits when encoding DateWithTime
The subsecond fraction digits had been hardcoded to 3. This forced all timestamps to include the subsecond digits with no way to customize the value. While the subsecond format is part of the ISO8601 spec, it is not adhered to by all parsers (notably mobile clients). This adds the ability to customize the number of digits used, optionally setting them to 0 in order to eliminate the subsecond fraction entirely: ActiveSupport::JSON::Encoding.subsecond_fraction_digits = 0
1 parent e1e17a5 commit 4cfc467

File tree

3 files changed

+30
-9
lines changed

3 files changed

+30
-9
lines changed

activesupport/lib/active_support/json/encoding.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
module ActiveSupport
55
class << self
66
delegate :use_standard_json_time_format, :use_standard_json_time_format=,
7+
:subsecond_fraction_digits, :subsecond_fraction_digits=,
78
:escape_html_entities_in_json, :escape_html_entities_in_json=,
89
:encode_big_decimal_as_string, :encode_big_decimal_as_string=,
910
:json_encoder, :json_encoder=,
@@ -60,7 +61,7 @@ def to_json(*)
6061
end
6162

6263
# Mark these as private so we don't leak encoding-specific constructs
63-
private_constant :ESCAPED_CHARS, :ESCAPE_REGEX_WITH_HTML_ENTITIES,
64+
private_constant :ESCAPED_CHARS, :ESCAPE_REGEX_WITH_HTML_ENTITIES,
6465
:ESCAPE_REGEX_WITHOUT_HTML_ENTITIES, :EscapedString
6566

6667
# Convert an object into a "JSON-ready" representation composed of
@@ -105,6 +106,10 @@ class << self
105106
# as a safety measure.
106107
attr_accessor :escape_html_entities_in_json
107108

109+
# Configures the inclusion of subsecond resolution when serializing instances
110+
# of ActiveSupport::TimeWithZone.
111+
attr_accessor :subsecond_fraction_digits
112+
108113
# Sets the encoder used by Rails to encode Ruby objects into JSON strings
109114
# in +Object#to_json+ and +ActiveSupport::JSON.encode+.
110115
attr_accessor :json_encoder

activesupport/lib/active_support/time_with_zone.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,8 @@ def xmlschema(fraction_digits = 0)
154154
# # => "2005/02/01 05:15:10 -1000"
155155
def as_json(options = nil)
156156
if ActiveSupport::JSON::Encoding.use_standard_json_time_format
157-
xmlschema(3)
157+
digits = ActiveSupport::JSON::Encoding.subsecond_fraction_digits || 3
158+
xmlschema(digits)
158159
else
159160
%(#{time.strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)})
160161
end

activesupport/test/core_ext/time_with_zone_test.rb

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,25 @@ def test_zone
6767
end
6868

6969
def test_to_json_with_use_standard_json_time_format_config_set_to_false
70-
old, ActiveSupport.use_standard_json_time_format = ActiveSupport.use_standard_json_time_format, false
71-
assert_equal "\"1999/12/31 19:00:00 -0500\"", ActiveSupport::JSON.encode(@twz)
72-
ensure
73-
ActiveSupport.use_standard_json_time_format = old
70+
with_standard_json_time_format(false) do
71+
assert_equal "\"1999/12/31 19:00:00 -0500\"", ActiveSupport::JSON.encode(@twz)
72+
end
7473
end
7574

7675
def test_to_json_with_use_standard_json_time_format_config_set_to_true
77-
old, ActiveSupport.use_standard_json_time_format = ActiveSupport.use_standard_json_time_format, true
78-
assert_equal "\"1999-12-31T19:00:00.000-05:00\"", ActiveSupport::JSON.encode(@twz)
76+
with_standard_json_time_format(true) do
77+
assert_equal "\"1999-12-31T19:00:00.000-05:00\"", ActiveSupport::JSON.encode(@twz)
78+
end
79+
end
80+
81+
def test_to_json_with_custom_subsecond_resolution
82+
with_standard_json_time_format(true) do
83+
ActiveSupport::JSON::Encoding.subsecond_fraction_digits = 0
84+
85+
assert_equal "\"1999-12-31T19:00:00-05:00\"", ActiveSupport::JSON.encode(@twz)
86+
end
7987
ensure
80-
ActiveSupport.use_standard_json_time_format = old
88+
ActiveSupport::JSON::Encoding.subsecond_fraction_digits = nil
8189
end
8290

8391
def test_to_json_when_wrapping_a_date_time
@@ -814,6 +822,13 @@ def with_env_tz(new_tz = 'US/Eastern')
814822
ensure
815823
old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
816824
end
825+
826+
def with_standard_json_time_format(boolean = true)
827+
old, ActiveSupport.use_standard_json_time_format = ActiveSupport.use_standard_json_time_format, boolean
828+
yield
829+
ensure
830+
ActiveSupport.use_standard_json_time_format = old
831+
end
817832
end
818833

819834
class TimeWithZoneMethodsForTimeAndDateTimeTest < ActiveSupport::TestCase

0 commit comments

Comments
 (0)