oj 2.11.5 → 2.12.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of oj might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8d1ef3e0a7644077283534c35c890016691f9592
4
- data.tar.gz: 671cfd43d8f6b32f3d84a389326e090ca42fa2f2
3
+ metadata.gz: b4f6db0371ed698ce4c6002a7d12acfb79982191
4
+ data.tar.gz: 8255ac3b86ed139ebbb350aacf8a8b25cd4806d1
5
5
  SHA512:
6
- metadata.gz: e443fc1c93a8399fa30e5bf48e10547bbf5baf7a5cd749a9e37b8fd234d4e8bb15dbc1942012f5c5cf7eff60064d5a37447e6a69f7beaea7bbdcb4dfea54bd0c
7
- data.tar.gz: 323cb80c48f393bca6ffe4b11dae19af16ce88b2b6f2f5052264de1e3487fafd04ab61ce4daadb76eb1be5737a1fb13c47adec5572451f24ede11be8777be89a
6
+ metadata.gz: ee7a31844af7de0fcf4074146e963f17952cf396de304af36b7b04ad35a9e6904dc3ff93207cd728fbcb5102a5f4d8307942df9124cb4085b82c07ab3f0111c1
7
+ data.tar.gz: daa03c5114facec630dea16ce5925aa873a398e008383a6fc9323c3a468d6dec173167f1c071c036192564a3e9ec856e0d5b6b23222d21ff90aabf4e2900987b
data/README.md CHANGED
@@ -26,19 +26,16 @@ Follow [@peterohler on Twitter](http://twitter.com/#!/peterohler) for announceme
26
26
 
27
27
  [![Build Status](https://secure.travis-ci.org/ohler55/oj.png?branch=master)](http://travis-ci.org/ohler55/oj)
28
28
 
29
- ## Release 2.11.5
29
+ ## Future Release 2.12.0
30
30
 
31
- - Fixed issue with rails as_json not being called for Structs.
31
+ - String formats for UTC time are now explitly UTC instead of offset of
32
+ zero. This fixes a problem with pre-2.2.0 Rubies that automatically convert
33
+ zero offset times to local times.
32
34
 
33
- - Added support for anonymous Structs with object mode encoding. Note that this
34
- will result in a new anonymous Struct for each instance.
35
-
36
- ## Release 2.11.4
37
-
38
- - DateTime second encoding is now always a Rational to preserve accuracy.
39
-
40
- - Fixed bug in the Oj.load() callback feature that caused an endless loop when
41
- a StringIO was used with a JSON that was a number.
35
+ - Added :unix_zone time_format option for formating numeric time. This option
36
+ is the same as the :unix time option but the UTC offset is included as an
37
+ exponent to the number time value. A value of 86400 is an indication of UTC
38
+ time.
42
39
 
43
40
  [Older release notes](http://www.ohler.com/dev/oj_misc/release_notes.html).
44
41
 
@@ -80,7 +80,7 @@ static int hash_cb_strict(VALUE key, VALUE value, Out out);
80
80
  static int hash_cb_compat(VALUE key, VALUE value, Out out);
81
81
  static int hash_cb_object(VALUE key, VALUE value, Out out);
82
82
  static void dump_hash(VALUE obj, VALUE clas, int depth, int mode, Out out);
83
- static void dump_time(VALUE obj, Out out);
83
+ static void dump_time(VALUE obj, Out out, int withZone);
84
84
  static void dump_ruby_time(VALUE obj, Out out);
85
85
  static void dump_xml_time(VALUE obj, Out out);
86
86
  static void dump_data_strict(VALUE obj, Out out);
@@ -996,11 +996,11 @@ dump_hash(VALUE obj, VALUE clas, int depth, int mode, Out out) {
996
996
  }
997
997
 
998
998
  static void
999
- dump_time(VALUE obj, Out out) {
999
+ dump_time(VALUE obj, Out out, int withZone) {
1000
1000
  char buf[64];
1001
1001
  char *b = buf + sizeof(buf) - 1;
1002
1002
  long size;
1003
- char *dot = b - 10;
1003
+ char *dot;
1004
1004
  int neg = 0;
1005
1005
  long one = 1000000000;
1006
1006
  #if HAS_RB_TIME_TIMESPEC
@@ -1016,6 +1016,31 @@ dump_time(VALUE obj, Out out) {
1016
1016
  #endif
1017
1017
  #endif
1018
1018
 
1019
+ *b-- = '\0';
1020
+ if (withZone) {
1021
+ long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0));
1022
+ int zneg = (0 > tzsecs);
1023
+
1024
+ if (0 == tzsecs && Qtrue == rb_funcall2(obj, oj_utcq_id, 0, 0)) {
1025
+ tzsecs = 86400;
1026
+ } else {
1027
+ sec += tzsecs;
1028
+ }
1029
+ if (zneg) {
1030
+ tzsecs = -tzsecs;
1031
+ }
1032
+ if (0 == tzsecs) {
1033
+ *b-- = '0';
1034
+ } else {
1035
+ for (; 0 < tzsecs; b--, tzsecs /= 10) {
1036
+ *b = '0' + (tzsecs % 10);
1037
+ }
1038
+ if (zneg) {
1039
+ *b-- = '-';
1040
+ }
1041
+ }
1042
+ *b-- = 'e';
1043
+ }
1019
1044
  if (0 > sec) {
1020
1045
  neg = 1;
1021
1046
  sec = -sec;
@@ -1024,7 +1049,7 @@ dump_time(VALUE obj, Out out) {
1024
1049
  sec--;
1025
1050
  }
1026
1051
  }
1027
- *b-- = '\0';
1052
+ dot = b - 9;
1028
1053
  if (0 < out->opts->sec_prec) {
1029
1054
  if (9 > out->opts->sec_prec) {
1030
1055
  int i;
@@ -1088,7 +1113,7 @@ dump_xml_time(VALUE obj, Out out) {
1088
1113
  long nsec = NUM2LONG(rb_funcall2(obj, oj_tv_usec_id, 0, 0)) * 1000;
1089
1114
  #endif
1090
1115
  #endif
1091
- long tz_secs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0));
1116
+ long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0));
1092
1117
  int tzhour, tzmin;
1093
1118
  char tzsign = '+';
1094
1119
 
@@ -1109,16 +1134,16 @@ dump_xml_time(VALUE obj, Out out) {
1109
1134
  }
1110
1135
  // 2012-01-05T23:58:07.123456000+09:00
1111
1136
  //tm = localtime(&sec);
1112
- sec += tz_secs;
1137
+ sec += tzsecs;
1113
1138
  tm = gmtime(&sec);
1114
1139
  #if 1
1115
- if (0 > tz_secs) {
1140
+ if (0 > tzsecs) {
1116
1141
  tzsign = '-';
1117
- tzhour = (int)(tz_secs / -3600);
1118
- tzmin = (int)(tz_secs / -60) - (tzhour * 60);
1142
+ tzhour = (int)(tzsecs / -3600);
1143
+ tzmin = (int)(tzsecs / -60) - (tzhour * 60);
1119
1144
  } else {
1120
- tzhour = (int)(tz_secs / 3600);
1121
- tzmin = (int)(tz_secs / 60) - (tzhour * 60);
1145
+ tzhour = (int)(tzsecs / 3600);
1146
+ tzmin = (int)(tzsecs / 60) - (tzhour * 60);
1122
1147
  }
1123
1148
  #else
1124
1149
  if (0 > tm->tm_gmtoff) {
@@ -1131,7 +1156,7 @@ dump_xml_time(VALUE obj, Out out) {
1131
1156
  }
1132
1157
  #endif
1133
1158
  if (0 == nsec || 0 == out->opts->sec_prec) {
1134
- if (0 == tzhour && 0 == tzmin) {
1159
+ if (0 == tzsecs && Qtrue == rb_funcall2(obj, oj_utcq_id, 0, 0)) {
1135
1160
  sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ",
1136
1161
  tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
1137
1162
  tm->tm_hour, tm->tm_min, tm->tm_sec);
@@ -1143,6 +1168,18 @@ dump_xml_time(VALUE obj, Out out) {
1143
1168
  tzsign, tzhour, tzmin);
1144
1169
  dump_cstr(buf, 25, 0, 0, out);
1145
1170
  }
1171
+ } else if (0 == tzsecs && Qtrue == rb_funcall2(obj, oj_utcq_id, 0, 0)) {
1172
+ char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ";
1173
+ int len = 30;
1174
+
1175
+ if (9 > out->opts->sec_prec) {
1176
+ format[32] = '0' + out->opts->sec_prec;
1177
+ len -= 9 - out->opts->sec_prec;
1178
+ }
1179
+ sprintf(buf, format,
1180
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
1181
+ tm->tm_hour, tm->tm_min, tm->tm_sec, nsec);
1182
+ dump_cstr(buf, len, 0, 0, out);
1146
1183
  } else {
1147
1184
  char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d";
1148
1185
  int len = 35;
@@ -1232,8 +1269,9 @@ dump_data_comp(VALUE obj, int depth, Out out) {
1232
1269
  switch (out->opts->time_format) {
1233
1270
  case RubyTime: dump_ruby_time(obj, out); break;
1234
1271
  case XmlTime: dump_xml_time(obj, out); break;
1272
+ case UnixZTime: dump_time(obj, out, 1); break;
1235
1273
  case UnixTime:
1236
- default: dump_time(obj, out); break;
1274
+ default: dump_time(obj, out, 0); break;
1237
1275
  }
1238
1276
  } else if (oj_bigdecimal_class == clas) {
1239
1277
  volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
@@ -1266,9 +1304,12 @@ dump_data_obj(VALUE obj, int depth, Out out) {
1266
1304
  case XmlTime:
1267
1305
  dump_xml_time(obj, out);
1268
1306
  break;
1307
+ case UnixZTime:
1308
+ dump_time(obj, out, 1);
1309
+ break;
1269
1310
  case UnixTime:
1270
1311
  default:
1271
- dump_time(obj, out);
1312
+ dump_time(obj, out, 0);
1272
1313
  break;
1273
1314
  }
1274
1315
  *out->cur++ = '}';
@@ -29,6 +29,7 @@
29
29
  */
30
30
 
31
31
  #include <stdio.h>
32
+ #include <time.h>
32
33
 
33
34
  #include "oj.h"
34
35
  #include "err.h"
@@ -93,6 +94,146 @@ str_to_value(ParseInfo pi, const char *str, size_t len, const char *orig) {
93
94
  return rstr;
94
95
  }
95
96
 
97
+ #if (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8)
98
+ static VALUE
99
+ parse_xml_time(const char *str, int len) {
100
+ return rb_funcall(rb_cTime, oj_parse_id, 1, rb_str_new(str, len));
101
+ }
102
+ #else
103
+ // The much faster approach (4x faster)
104
+ static int
105
+ parse_num(const char *str, const char *end, int cnt) {
106
+ int n = 0;
107
+ char c;
108
+ int i;
109
+
110
+ for (i = cnt; 0 < i; i--, str++) {
111
+ c = *str;
112
+ if (end <= str || c < '0' || '9' < c) {
113
+ return -1;
114
+ }
115
+ n = n * 10 + (c - '0');
116
+ }
117
+ return n;
118
+ }
119
+
120
+ static VALUE
121
+ parse_xml_time(const char *str, int len) {
122
+ VALUE args[8];
123
+ const char *end = str + len;
124
+ int n;
125
+
126
+ // year
127
+ if (0 > (n = parse_num(str, end, 4))) {
128
+ return Qnil;
129
+ }
130
+ str += 4;
131
+ args[0] = LONG2NUM(n);
132
+ if ('-' != *str++) {
133
+ return Qnil;
134
+ }
135
+ // month
136
+ if (0 > (n = parse_num(str, end, 2))) {
137
+ return Qnil;
138
+ }
139
+ str += 2;
140
+ args[1] = LONG2NUM(n);
141
+ if ('-' != *str++) {
142
+ return Qnil;
143
+ }
144
+ // day
145
+ if (0 > (n = parse_num(str, end, 2))) {
146
+ return Qnil;
147
+ }
148
+ str += 2;
149
+ args[2] = LONG2NUM(n);
150
+ if ('T' != *str++) {
151
+ return Qnil;
152
+ }
153
+ // hour
154
+ if (0 > (n = parse_num(str, end, 2))) {
155
+ return Qnil;
156
+ }
157
+ str += 2;
158
+ args[3] = LONG2NUM(n);
159
+ if (':' != *str++) {
160
+ return Qnil;
161
+ }
162
+ // minute
163
+ if (0 > (n = parse_num(str, end, 2))) {
164
+ return Qnil;
165
+ }
166
+ str += 2;
167
+ args[4] = LONG2NUM(n);
168
+ if (':' != *str++) {
169
+ return Qnil;
170
+ }
171
+ // second
172
+ if (0 > (n = parse_num(str, end, 2))) {
173
+ return Qnil;
174
+ }
175
+ str += 2;
176
+ if (str == end) {
177
+ args[5] = LONG2NUM(n);
178
+ args[6] = LONG2NUM(0);
179
+ } else {
180
+ char c = *str++;
181
+
182
+ if ('.' == c) {
183
+ long nsec = 0;
184
+
185
+ for (; str < end; str++) {
186
+ c = *str;
187
+ if (c < '0' || '9' < c) {
188
+ str++;
189
+ break;
190
+ }
191
+ nsec = nsec * 10 + (c - '0');
192
+ }
193
+ args[5] = rb_float_new((double)n + ((double)nsec + 0.5) / 1000000000.0);
194
+ } else {
195
+ args[5] = LONG2NUM(n);
196
+ }
197
+ if (end < str) {
198
+ args[6] = LONG2NUM(0);
199
+ } else {
200
+ if ('Z' == c) {
201
+ return rb_funcall2(rb_cTime, oj_utc_id, 6, args);
202
+ } else if ('+' == c) {
203
+ int hr = parse_num(str, end, 2);
204
+ int min;
205
+
206
+ str += 2;
207
+ if (0 > hr || ':' != *str++) {
208
+ return Qnil;
209
+ }
210
+ min = parse_num(str, end, 2);
211
+ if (0 > min) {
212
+ return Qnil;
213
+ }
214
+ args[6] = LONG2NUM(hr * 3600 + min * 60);
215
+ } else if ('-' == c) {
216
+ int hr = parse_num(str, end, 2);
217
+ int min;
218
+
219
+ str += 2;
220
+ if (0 > hr || ':' != *str++) {
221
+ return Qnil;
222
+ }
223
+ min = parse_num(str, end, 2);
224
+ if (0 > min) {
225
+ return Qnil;
226
+ }
227
+ args[6] = LONG2NUM(-(hr * 3600 + min * 60));
228
+ } else {
229
+ args[6] = LONG2NUM(0);
230
+ }
231
+ }
232
+ }
233
+ return rb_funcall2(rb_cTime, oj_new_id, 7, args);
234
+ }
235
+ #endif
236
+
96
237
  static int
97
238
  hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t len) {
98
239
  const char *key = kval->key;
@@ -133,7 +274,7 @@ hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t len) {
133
274
  parent->val = oj_name2class(pi, str, len, Yes == pi->options.auto_define);
134
275
  break;
135
276
  case 't': // time
136
- parent->val = rb_funcall(oj_time_class, rb_intern("parse"), 1, rb_str_new(str, len));
277
+ parent->val = parse_xml_time(str, len);
137
278
  break;
138
279
  default:
139
280
  return 0;
@@ -159,11 +300,55 @@ hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
159
300
  nsec = 1000000000LL - nsec;
160
301
  }
161
302
  }
303
+ if (86400 == ni->exp) { // UTC time
304
+ #if HAS_NANO_TIME
305
+ parent->val = rb_time_nano_new(ni->i, (long)nsec);
306
+ #else
307
+ parent->val = rb_time_new(ni->i, (long)(nsec / 1000));
308
+ #endif
309
+ // Since the ruby C routines alway create local time, the
310
+ // offset and then a convertion to UTC keeps makes the time
311
+ // match the expected value.
312
+ parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
313
+ } else if (ni->hasExp) {
314
+ time_t t = (time_t)ni->i;
315
+ struct tm *st = gmtime(&t);
316
+ #if RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8
317
+ // The only methods that allow the UTC offset to be set in
318
+ // 1.8.7 is the parse() and xmlschema() methods. The
319
+ // xmlschema() method always returns a Time instance that is
320
+ // UTC time. (true on some platforms anyway) Time.parse()
321
+ // fails on other Ruby versions until 2.2.0.
322
+ char buf[64];
323
+ int z = (0 > ni->exp ? -ni->exp : ni->exp) / 60;
324
+ int tzhour = z / 60;
325
+ int tzmin = z - tzhour * 60;
326
+ int cnt;
327
+
328
+ cnt = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d",
329
+ 1900 + st->tm_year, 1 + st->tm_mon, st->tm_mday,
330
+ st->tm_hour, st->tm_min, st->tm_sec, (long)nsec,
331
+ (0 > ni->exp ? '-' : '+'), tzhour, tzmin);
332
+ parent->val = rb_funcall(rb_cTime, oj_parse_id, 1, rb_str_new(buf, cnt));
333
+ #else
334
+ VALUE args[8];
335
+
336
+ args[0] = LONG2NUM(1900 + st->tm_year);
337
+ args[1] = LONG2NUM(1 + st->tm_mon);
338
+ args[2] = LONG2NUM(st->tm_mday);
339
+ args[3] = LONG2NUM(st->tm_hour);
340
+ args[4] = LONG2NUM(st->tm_min);
341
+ args[5] = rb_float_new((double)st->tm_sec + ((double)nsec + 0.5) / 1000000000.0);
342
+ args[6] = LONG2NUM(ni->exp);
343
+ parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
344
+ #endif
345
+ } else {
162
346
  #if HAS_NANO_TIME
163
- parent->val = rb_time_nano_new(ni->i, (long)nsec);
347
+ parent->val = rb_time_nano_new(ni->i, (long)nsec);
164
348
  #else
165
- parent->val = rb_time_new(ni->i, (long)(nsec / 1000));
349
+ parent->val = rb_time_new(ni->i, (long)(nsec / 1000));
166
350
  #endif
351
+ }
167
352
  }
168
353
  break;
169
354
  case 'i': // circular index
@@ -70,6 +70,7 @@ ID oj_instance_variables_id;
70
70
  ID oj_json_create_id;
71
71
  ID oj_length_id;
72
72
  ID oj_new_id;
73
+ ID oj_parse_id;
73
74
  ID oj_pos_id;
74
75
  ID oj_read_id;
75
76
  ID oj_readpartial_id;
@@ -84,7 +85,9 @@ ID oj_to_time_id;
84
85
  ID oj_tv_nsec_id;
85
86
  ID oj_tv_sec_id;
86
87
  ID oj_tv_usec_id;
88
+ ID oj_utc_id;
87
89
  ID oj_utc_offset_id;
90
+ ID oj_utcq_id;
88
91
  ID oj_write_id;
89
92
 
90
93
  VALUE oj_bag_class;
@@ -97,7 +100,6 @@ VALUE oj_stream_writer_class;
97
100
  VALUE oj_string_writer_class;
98
101
  VALUE oj_stringio_class;
99
102
  VALUE oj_struct_class;
100
- VALUE oj_time_class;
101
103
 
102
104
  VALUE oj_slash_string;
103
105
 
@@ -130,6 +132,7 @@ static VALUE strict_sym;
130
132
  static VALUE symbol_keys_sym;
131
133
  static VALUE time_format_sym;
132
134
  static VALUE unix_sym;
135
+ static VALUE unix_zone_sym;
133
136
  static VALUE use_to_json_sym;
134
137
  static VALUE xmlschema_sym;
135
138
  static VALUE xss_safe_sym;
@@ -164,7 +167,7 @@ struct _Options oj_default_options = {
164
167
  JSONEsc, // escape_mode
165
168
  ObjectMode, // mode
166
169
  Yes, // class_cache
167
- UnixTime, // time_format
170
+ UnixZTime, // time_format
168
171
  Yes, // bigdec_as_num
169
172
  AutoDec, // bigdec_load
170
173
  Yes, // to_json
@@ -191,7 +194,7 @@ static VALUE define_mimic_json(int argc, VALUE *argv, VALUE self);
191
194
  * - escape_mode: [:newline|:json|:xss_safe|:ascii|nil] determines the characters to escape
192
195
  * - class_cache: [true|false|nil] cache classes for faster parsing (if dynamically modifying classes or reloading classes then don't use this)
193
196
  * - mode: [:object|:strict|:compat|:null] load and dump modes to use for JSON
194
- * - time_format: [:unix|:xmlschema|:ruby] time format when dumping in :compat mode
197
+ * - time_format: [:unix|:unix_zone|:xmlschema|:ruby] time format when dumping in :compat and :object mode
195
198
  * - bigdecimal_as_decimal: [true|false|nil] dump BigDecimal as a decimal number or as a String
196
199
  * - bigdecimal_load: [:bigdecimal|:float|:auto] load decimals as BigDecimal instead of as a Float. :auto pick the most precise for the number of digits.
197
200
  * - create_id: [String|nil] create id for json compatible object encoding, default is 'json_create'
@@ -236,6 +239,7 @@ get_def_opts(VALUE self) {
236
239
  switch (oj_default_options.time_format) {
237
240
  case XmlTime: rb_hash_aset(opts, time_format_sym, xmlschema_sym); break;
238
241
  case RubyTime: rb_hash_aset(opts, time_format_sym, ruby_sym); break;
242
+ case UnixZTime: rb_hash_aset(opts, time_format_sym, unix_zone_sym); break;
239
243
  case UnixTime:
240
244
  default: rb_hash_aset(opts, time_format_sym, unix_sym); break;
241
245
  }
@@ -275,6 +279,7 @@ get_def_opts(VALUE self) {
275
279
  * replaces them with a null.
276
280
  * @param [:unix|:xmlschema|:ruby] time format when dumping in :compat mode
277
281
  * :unix decimal number denoting the number of seconds since 1/1/1970,
282
+ * :unix_zone decimal number denoting the number of seconds since 1/1/1970 plus the utc_offset in the exponent ,
278
283
  * :xmlschema date-time format taken from XML Schema as a String,
279
284
  * :ruby Time.to_s formatted String
280
285
  * @param [String|nil] :create_id create id for json compatible object encoding
@@ -360,12 +365,14 @@ set_def_opts(VALUE self, VALUE opts) {
360
365
  // ignore
361
366
  } else if (unix_sym == v) {
362
367
  oj_default_options.time_format = UnixTime;
368
+ } else if (unix_zone_sym == v) {
369
+ oj_default_options.time_format = UnixZTime;
363
370
  } else if (xmlschema_sym == v) {
364
371
  oj_default_options.time_format = XmlTime;
365
372
  } else if (ruby_sym == v) {
366
373
  oj_default_options.time_format = RubyTime;
367
374
  } else {
368
- rb_raise(rb_eArgError, ":time_format must be :unix, :xmlschema, or :ruby.");
375
+ rb_raise(rb_eArgError, ":time_format must be :unix, :unix_zone, :xmlschema, or :ruby.");
369
376
  }
370
377
 
371
378
  v = rb_hash_lookup(opts, escape_mode_sym);
@@ -512,12 +519,14 @@ oj_parse_options(VALUE ropts, Options copts) {
512
519
  if (Qnil != (v = rb_hash_lookup(ropts, time_format_sym))) {
513
520
  if (unix_sym == v) {
514
521
  copts->time_format = UnixTime;
522
+ } else if (unix_zone_sym == v) {
523
+ copts->time_format = UnixZTime;
515
524
  } else if (xmlschema_sym == v) {
516
525
  copts->time_format = XmlTime;
517
526
  } else if (ruby_sym == v) {
518
527
  copts->time_format = RubyTime;
519
528
  } else {
520
- rb_raise(rb_eArgError, ":time_format must be :unix, :xmlschema, or :ruby.");
529
+ rb_raise(rb_eArgError, ":time_format must be :unix, :unix_zone, :xmlschema, or :ruby.");
521
530
  }
522
531
  }
523
532
 
@@ -2042,6 +2051,7 @@ void Init_oj() {
2042
2051
  oj_json_create_id = rb_intern("json_create");
2043
2052
  oj_length_id = rb_intern("length");
2044
2053
  oj_new_id = rb_intern("new");
2054
+ oj_parse_id = rb_intern("parse");
2045
2055
  oj_pos_id = rb_intern("pos");
2046
2056
  oj_read_id = rb_intern("read");
2047
2057
  oj_readpartial_id = rb_intern("readpartial");
@@ -2056,7 +2066,9 @@ void Init_oj() {
2056
2066
  oj_tv_nsec_id = rb_intern("tv_nsec");
2057
2067
  oj_tv_sec_id = rb_intern("tv_sec");
2058
2068
  oj_tv_usec_id = rb_intern("tv_usec");
2069
+ oj_utc_id = rb_intern("utc");
2059
2070
  oj_utc_offset_id = rb_intern("utc_offset");
2071
+ oj_utcq_id = rb_intern("utc?");
2060
2072
  oj_write_id = rb_intern("write");
2061
2073
 
2062
2074
  rb_require("oj/bag");
@@ -2072,7 +2084,6 @@ void Init_oj() {
2072
2084
  oj_parse_error_class = rb_const_get_at(Oj, rb_intern("ParseError"));
2073
2085
  oj_stringio_class = rb_const_get(rb_cObject, rb_intern("StringIO"));
2074
2086
  oj_struct_class = rb_const_get(rb_cObject, rb_intern("Struct"));
2075
- oj_time_class = rb_const_get(rb_cObject, rb_intern("Time"));
2076
2087
 
2077
2088
  allow_gc_sym = ID2SYM(rb_intern("allow_gc")); rb_gc_register_address(&allow_gc_sym);
2078
2089
  ascii_only_sym = ID2SYM(rb_intern("ascii_only")); rb_gc_register_address(&ascii_only_sym);
@@ -2103,6 +2114,7 @@ void Init_oj() {
2103
2114
  symbol_keys_sym = ID2SYM(rb_intern("symbol_keys")); rb_gc_register_address(&symbol_keys_sym);
2104
2115
  time_format_sym = ID2SYM(rb_intern("time_format")); rb_gc_register_address(&time_format_sym);
2105
2116
  unix_sym = ID2SYM(rb_intern("unix")); rb_gc_register_address(&unix_sym);
2117
+ unix_zone_sym = ID2SYM(rb_intern("unix_zone")); rb_gc_register_address(&unix_zone_sym);
2106
2118
  use_to_json_sym = ID2SYM(rb_intern("use_to_json")); rb_gc_register_address(&use_to_json_sym);
2107
2119
  xmlschema_sym = ID2SYM(rb_intern("xmlschema")); rb_gc_register_address(&xmlschema_sym);
2108
2120
  xss_safe_sym = ID2SYM(rb_intern("xss_safe")); rb_gc_register_address(&xss_safe_sym);