Skip to content

Commit

Permalink
made changes to dump and object for time
Browse files Browse the repository at this point in the history
  • Loading branch information
ohler55 committed Mar 1, 2015
1 parent 2521bd7 commit c4d4eff
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 35 deletions.
19 changes: 11 additions & 8 deletions ext/oj/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -1016,23 +1016,18 @@ dump_time(VALUE obj, Out out, int withZone) {
#endif
#endif

if (0 > sec) {
neg = 1;
sec = -sec;
if (0 < nsec) {
nsec = 1000000000 - nsec;
sec--;
}
}
*b-- = '\0';
if (withZone) {
long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0));
int neg = (0 > tzsecs);

if (neg) {
tzsecs = -tzsecs;
sec -= tzsecs;
} else if (0 == tzsecs && Qtrue == rb_funcall2(obj, oj_utcq_id, 0, 0)) {
tzsecs = 86400;
} else {
sec -= tzsecs;
}
if (0 == tzsecs) {
*b-- = '0';
Expand All @@ -1046,6 +1041,14 @@ dump_time(VALUE obj, Out out, int withZone) {
}
*b-- = 'e';
}
if (0 > sec) {
neg = 1;
sec = -sec;
if (0 < nsec) {
nsec = 1000000000 - nsec;
sec--;
}
}
dot = b - 9;
if (0 < out->opts->sec_prec) {
if (9 > out->opts->sec_prec) {
Expand Down
24 changes: 19 additions & 5 deletions ext/oj/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,6 @@ hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
}
}
if (86400 == ni->exp) { // UTC time
time_t now = time(0);
struct tm *st = localtime(&now);

ni->i += st->tm_gmtoff;
#if HAS_NANO_TIME
parent->val = rb_time_nano_new(ni->i, (long)nsec);
#else
Expand All @@ -176,7 +172,24 @@ hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
} else if (ni->hasExp) {
time_t t = (time_t)ni->i;
struct tm *st = localtime(&t);
struct tm *st = gmtime(&t);
#if RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8
// The only methods that allow the UTC offset to be set in
// 1.8.7 is the parse() and xmlschema() methods. The
// xmlschema() method always returns a Time instance that is
// UTC time. (true on some platforms anyway)
char buf[64];
int z = (0 > ni->exp ? -ni->exp : ni->exp);
int tzhour = z / 3600;
int tzsecs = z - tzhour * 3600;
int cnt;

cnt = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d",
1900 + st->tm_year, 1 + st->tm_mon, st->tm_mday,
st->tm_hour, st->tm_min, st->tm_sec, (long)nsec,
(0 > ni->exp ? '-' : '+'), tzhour, tzsecs);
parent->val = rb_funcall(oj_time_class, rb_intern("parse"), 1, rb_str_new(buf, cnt));
#else
VALUE args[8];

args[0] = LONG2NUM(1900 + st->tm_year);
Expand All @@ -187,6 +200,7 @@ hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
args[5] = rb_float_new((double)st->tm_sec + (double)nsec / 1000000000.0);
args[6] = LONG2NUM(ni->exp);
parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
#endif
} else {
#if HAS_NANO_TIME
parent->val = rb_time_nano_new(ni->i, (long)nsec);
Expand Down
2 changes: 1 addition & 1 deletion lib/oj/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

module Oj
# Current version of the module.
VERSION = '2.12.0a2'
VERSION = '2.12.0a3'
end
4 changes: 4 additions & 0 deletions notes
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
^c^s show subtree

- time
- object.c hat_num()
- for 1.8.7 have to create string and then call parse, not xmlschema (xmlschema always makes UTC)
- for 1.9 and above use Time.new()
- use oj_parse_id, not intern
- test
- check number parsing for big exp
- times with different zones - check string also
Expand Down
35 changes: 30 additions & 5 deletions test/test_compat.rb
Original file line number Diff line number Diff line change
Expand Up @@ -194,25 +194,50 @@ def test_bigdecimal_load

# Time
def test_time_ruby
t = Time.new(2015, 1, 5, 21, 37, 7.123456, -28800)
if RUBY_VERSION.start_with?('1.8')
t = Time.parse('2015-01-05T21:37:07.123456-08:00')
else
t = Time.new(2015, 1, 5, 21, 37, 7.123456, -8 * 3600)
end
expect = '"' + t.to_s + '"'
json = Oj.dump(t, :mode => :compat, :time_format => :ruby)
assert_equal(expect, json)
end
def test_time_xml
t = Time.new(2015, 1, 5, 21, 37, 7.123456, -28800)
if RUBY_VERSION.start_with?('1.8')
t = Time.parse('2015-01-05T21:37:07.123456-08:00')
else
t = Time.new(2015, 1, 5, 21, 37, 7.123456, -8 * 3600)
end
json = Oj.dump(t, :mode => :compat, :time_format => :xmlschema, :second_precision => 6)
assert_equal('"2015-01-05T21:37:07.123456-08:00"', json)
end
def test_time_unix
t = Time.new(2015, 1, 5, 21, 37, 7.123456, -28800)
if RUBY_VERSION.start_with?('1.8')
t = Time.parse('2015-01-05T21:37:07.123456-08:00')
else
t = Time.new(2015, 1, 5, 21, 37, 7.123456, -8 * 3600)
end
json = Oj.dump(t, :mode => :compat, :time_format => :unix, :second_precision => 6)
assert_equal('1420522627.123456', json)
end
def test_time_unix_zone
t = Time.new(2015, 1, 5, 21, 37, 7.123456, -28800)
if RUBY_VERSION.start_with?('1.8')
t = Time.parse('2015-01-05T21:37:07.123456-08:00')
else
t = Time.new(2015, 1, 5, 21, 37, 7.123456, -8 * 3600)
end
json = Oj.dump(t, :mode => :compat, :time_format => :unix_zone, :second_precision => 6)
assert_equal('1420493827.123456e-28800', json)
end
def test_time_unix_zone_early
if RUBY_VERSION.start_with?('1.8')
t = Time.parse('1954-01-05T21:37:07.123456-08:00')
else
t = Time.new(1954, 1, 5, 21, 37, 7.123456, -8 * 3600)
end
json = Oj.dump(t, :mode => :compat, :time_format => :unix_zone, :second_precision => 6)
assert_equal('1420522627.123456e-28800', json)
assert_equal('-504498172.876544e-28800', json)
end

# Stream IO
Expand Down
153 changes: 137 additions & 16 deletions test/test_object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -352,36 +352,157 @@ def test_time
end

def test_xml_time
Oj.default_options = { :mode => :object, :time_format => :xmlschema }
t = Time.now()
dump_and_load(t, false)
if RUBY_VERSION.start_with?('1.8')
t = Time.parse('2015-01-05T21:37:07.123456789-08:00')
else
t = Time.new(2015, 1, 5, 21, 37, 7.123456789, -8 * 3600)
end
# The fractional seconds are not always recreated exactly which cacuses a
# mismatch so instead the seconds, nsecs, and gmt_offset are checked
# separately along with utc.
json = Oj.dump(t, :mode => :object, :time_format => :xmlschema)
#puts json
loaded = Oj.object_load(json);
assert_equal(t.tv_sec, loaded.tv_sec)
if t.respond_to?(:tv_nsec)
assert_equal(t.tv_nsec, loaded.tv_nsec)
else
assert_equal(t.tv_usec, loaded.tv_usec)
end
assert_equal(t.utc?, loaded.utc?)
assert_equal(t.utc_offset, loaded.utc_offset)
end

def test_utc_time
Oj.default_options = { :mode => :object, :time_format => :xmlschema }
t = Time.parse('2015-01-05 21:37:07.123456789Z')
dump_and_load(t, false)
def test_xml_time_utc
if RUBY_VERSION.start_with?('1.8')
t = Time.parse('2015-01-05T21:37:07.123456789Z')
else
t = Time.utc(2015, 1, 5, 21, 37, 7.123456789)
end
# The fractional seconds are not always recreated exactly which cacuses a
# mismatch so instead the seconds, nsecs, and gmt_offset are checked
# separately along with utc.
json = Oj.dump(t, :mode => :object, :time_format => :xmlschema)
#puts json
loaded = Oj.object_load(json);
assert_equal(t.tv_sec, loaded.tv_sec)
if t.respond_to?(:tv_nsec)
assert_equal(t.tv_nsec, loaded.tv_nsec)
else
assert_equal(t.tv_usec, loaded.tv_usec)
end
assert_equal(t.utc?, loaded.utc?)
assert_equal(t.utc_offset, loaded.utc_offset)
end

def test_ruby_time
Oj.default_options = { :mode => :object, :time_format => :ruby }
t = Time.parse('2015-01-05 21:37:07.123456789 -0700')
dump_and_load(t, false)
if RUBY_VERSION.start_with?('1.8')
t = Time.parse('2015-01-05T21:37:07.123456789-08:00')
else
t = Time.new(2015, 1, 5, 21, 37, 7.123456789, -8 * 3600)
end
# The fractional seconds are not always recreated exactly which cacuses a
# mismatch so instead the seconds, nsecs, and gmt_offset are checked
# separately along with utc.
json = Oj.dump(t, :mode => :object, :time_format => :ruby)
#puts json
loaded = Oj.object_load(json);
assert_equal(t.tv_sec, loaded.tv_sec)
if t.respond_to?(:tv_nsec)
assert_equal(t.tv_nsec, loaded.tv_nsec)
else
assert_equal(t.tv_usec, loaded.tv_usec)
end
assert_equal(t.utc?, loaded.utc?)
assert_equal(t.utc_offset, loaded.utc_offset)
end

def test_ruby_time_utc
if RUBY_VERSION.start_with?('1.8')
t = Time.parse('2015-01-05T21:37:07.123456789Z')
else
t = Time.utc(2015, 1, 5, 21, 37, 7.123456789)
end
# The fractional seconds are not always recreated exactly which cacuses a
# mismatch so instead the seconds, nsecs, and gmt_offset are checked
# separately along with utc.
json = Oj.dump(t, :mode => :object, :time_format => :ruby)
#puts json
loaded = Oj.object_load(json);
assert_equal(t.tv_sec, loaded.tv_sec)
if t.respond_to?(:tv_nsec)
assert_equal(t.tv_nsec, loaded.tv_nsec)
else
assert_equal(t.tv_usec, loaded.tv_usec)
end
assert_equal(t.utc?, loaded.utc?)
assert_equal(t.utc_offset, loaded.utc_offset)
end

def test_time_early
t = Time.xmlschema("1954-01-05T00:00:00.123456")
dump_and_load(t, false)
if RUBY_VERSION.start_with?('1.8')
t = Time.parse('1954-01-05T21:37:07.123456789-08:00')
else
t = Time.new(1954, 1, 5, 21, 37, 7.123456789, -8 * 3600)
end
# The fractional seconds are not always recreated exactly which cacuses a
# mismatch so instead the seconds, nsecs, and gmt_offset are checked
# separately along with utc.
json = Oj.dump(t, :mode => :object, :time_format => :unix_zone)
#puts json
loaded = Oj.object_load(json);
assert_equal(t.tv_sec, loaded.tv_sec)
if t.respond_to?(:tv_nsec)
assert_equal(t.tv_nsec, loaded.tv_nsec)
else
assert_equal(t.tv_usec, loaded.tv_usec)
end
assert_equal(t.utc?, loaded.utc?)
assert_equal(t.utc_offset, loaded.utc_offset)
end

def test_time_unix_zone
t = Time.parse('2015-01-05 21:37:07.123456789 -0800')
dump_and_load(t, false)
if RUBY_VERSION.start_with?('1.8')
t = Time.parse('2015-01-05T21:37:07.123456789-08:00')
else
t = Time.new(2015, 1, 5, 21, 37, 7.123456789, -8 * 3600)
end
# The fractional seconds are not always recreated exactly which cacuses a
# mismatch so instead the seconds, nsecs, and gmt_offset are checked
# separately along with utc.
json = Oj.dump(t, :mode => :object, :time_format => :unix_zone)
#puts json
loaded = Oj.object_load(json);
assert_equal(t.tv_sec, loaded.tv_sec)
if t.respond_to?(:tv_nsec)
assert_equal(t.tv_nsec, loaded.tv_nsec)
else
assert_equal(t.tv_usec, loaded.tv_usec)
end
assert_equal(t.utc?, loaded.utc?)
assert_equal(t.utc_offset, loaded.utc_offset)
end

def test_time_unix_zone_utc
t = Time.parse('2015-01-05 21:37:07.123456789Z')
dump_and_load(t, false)
if RUBY_VERSION.start_with?('1.8')
t = Time.parse('2015-01-05T21:37:07.123456789Z')
else
t = Time.utc(2015, 1, 5, 21, 37, 7.123456789)
end
# The fractional seconds are not always recreated exactly which cacuses a
# mismatch so instead the seconds, nsecs, and gmt_offset are checked
# separately along with utc.
json = Oj.dump(t, :mode => :object, :time_format => :unix_zone)
#puts json
loaded = Oj.object_load(json);
assert_equal(t.tv_sec, loaded.tv_sec)
if t.respond_to?(:tv_nsec)
assert_equal(t.tv_nsec, loaded.tv_nsec)
else
assert_equal(t.tv_usec, loaded.tv_usec)
end
assert_equal(t.utc?, loaded.utc?)
assert_equal(t.utc_offset, loaded.utc_offset)
end

def test_json_object
Expand Down

0 comments on commit c4d4eff

Please sign in to comment.