47
47
import java .util .regex .Matcher ;
48
48
import java .util .regex .Pattern ;
49
49
50
+ import javax .print .DocFlavor ;
50
51
import org .joda .time .DateTime ;
51
52
import org .joda .time .DateTimeZone ;
52
53
import org .joda .time .IllegalFieldValueException ;
68
69
69
70
import static org .jruby .CompatVersion .*;
70
71
import org .jruby .runtime .Helpers ;
72
+ import org .jruby .util .TypeConverter ;
71
73
72
74
import static org .jruby .runtime .Helpers .invokedynamic ;
73
75
import static org .jruby .runtime .invokedynamic .MethodNames .OP_CMP ;
@@ -227,23 +229,68 @@ private static DateTimeZone parseZoneString(Ruby runtime, String zone) {
227
229
return parseTZString (runtime , zone );
228
230
}
229
231
230
- public static DateTimeZone getTimeZoneFromUtcOffset (Ruby runtime , String utcOffset ) {
231
- DateTimeZone cachedZone = runtime .getTimezoneCache ().get (utcOffset );
232
+ public static DateTimeZone getTimeZoneFromUtcOffset (Ruby runtime , IRubyObject utcOffset ) {
233
+ String strOffset = utcOffset .toString ();
234
+
235
+ DateTimeZone cachedZone = runtime .getTimezoneCache ().get (strOffset );
232
236
if (cachedZone != null ) return cachedZone ;
233
-
234
- Matcher offsetMatcher = TIME_OFFSET_PATTERN .matcher (utcOffset );
235
- if (!offsetMatcher .matches ()) {
236
- throw runtime .newArgumentError ("\" +HH:MM\" or \" -HH:MM\" expected for utc_offset" );
237
+
238
+ DateTimeZone dtz ;
239
+ if (utcOffset instanceof RubyString ) {
240
+ Matcher offsetMatcher = TIME_OFFSET_PATTERN .matcher (strOffset );
241
+ if (!offsetMatcher .matches ()) {
242
+ throw runtime .newArgumentError ("\" +HH:MM\" or \" -HH:MM\" expected for utc_offset" );
243
+ }
244
+ String sign = offsetMatcher .group (1 );
245
+ String hours = offsetMatcher .group (2 );
246
+ String minutes = offsetMatcher .group (3 );
247
+ dtz = getTimeZoneFromHHMM (runtime , "" , !sign .equals ("-" ), hours , minutes );
248
+ } else {
249
+ IRubyObject numericOffset = numExact (runtime , utcOffset );
250
+ int newOffset = (int )Math .round (numericOffset .convertToFloat ().getDoubleValue () * 1000 );
251
+ dtz = getTimeZoneWithOffset (runtime , "" , newOffset );
237
252
}
238
- String sign = offsetMatcher .group (1 );
239
- String hours = offsetMatcher .group (2 );
240
- String minutes = offsetMatcher .group (3 );
241
- DateTimeZone dtz = getTimeZoneFromHHMM (runtime , "" , !sign .equals ("-" ), hours , minutes );
242
253
243
- runtime .getTimezoneCache ().put (utcOffset , dtz );
254
+ runtime .getTimezoneCache ().put (strOffset , dtz );
244
255
return dtz ;
245
256
}
246
257
258
+ // mri: time.c num_exact
259
+ private static IRubyObject numExact (Ruby runtime , IRubyObject v ) {
260
+ IRubyObject tmp ;
261
+ if (v instanceof RubyFixnum || v instanceof RubyBignum ) return v ;
262
+ if (v .isNil ()) exactTypeError (runtime , v );
263
+ if (!(v instanceof RubyRational )) { // Default unknown
264
+ if (v .respondsTo ("to_r" )) {
265
+ tmp = v .callMethod (runtime .getCurrentContext (), "to_r" );
266
+ // WTF is this condition for? It responds to to_r and makes something which thinks it is a String?
267
+ if (tmp != null && v .respondsTo ("to_str" )) exactTypeError (runtime , v );
268
+ } else {
269
+ tmp = TypeConverter .checkIntegerType (runtime , v , "to_int" );
270
+ if (tmp .isNil ()) exactTypeError (runtime , v );
271
+ }
272
+ v = tmp ;
273
+ }
274
+
275
+ if (v instanceof RubyFixnum || v instanceof RubyBignum ) {
276
+ return v ;
277
+ } else if (v instanceof RubyRational ) {
278
+ RubyRational r = (RubyRational ) v ;
279
+ if (r .denominator (runtime .getCurrentContext ()) == RubyFixnum .newFixnum (runtime , 1 )) {
280
+ return r .numerator (runtime .getCurrentContext ());
281
+ }
282
+ } else {
283
+ exactTypeError (runtime , v );
284
+ }
285
+
286
+ return v ;
287
+ }
288
+
289
+ private static void exactTypeError (Ruby runtime , IRubyObject received ) {
290
+ throw runtime .newTypeError (
291
+ String .format ("Can't convert %s into an exact number" , received .getMetaClass ().getRealClass ()));
292
+ }
293
+
247
294
private static DateTimeZone getTimeZoneFromHHMM (Ruby runtime , String name , boolean positive , String hours , String minutes ) {
248
295
int h = Integer .parseInt (hours );
249
296
int m = 0 ;
@@ -404,11 +451,14 @@ public RubyTime localtime() {
404
451
405
452
@ JRubyMethod (name = "localtime" , optional = 1 , compat = RUBY1_9 )
406
453
public RubyTime localtime19 (ThreadContext context , IRubyObject [] args ) {
407
- if (args .length == 0 ) return localtime ();
408
-
409
- String offset = args [0 ].asJavaString ();
410
- DateTimeZone dtz = getTimeZoneFromUtcOffset (context .runtime , offset );
411
- return newTime (context .runtime , dt .withZone (dtz ), nsec );
454
+ DateTimeZone newDtz ;
455
+ if (args .length == 0 ) {
456
+ newDtz = getLocalTimeZone (context .runtime );
457
+ } else {
458
+ newDtz = getTimeZoneFromUtcOffset (context .runtime , args [0 ]);
459
+ }
460
+ dt = dt .withZone (newDtz );
461
+ return this ;
412
462
}
413
463
414
464
@ JRubyMethod (name = {"gmt?" , "utc?" , "gmtime?" })
@@ -431,18 +481,8 @@ public RubyTime getlocal19(ThreadContext context, IRubyObject[] args) {
431
481
if (args .length == 0 || args [0 ].isNil ()) {
432
482
return newTime (getRuntime (), dt .withZone (getLocalTimeZone (getRuntime ())), nsec );
433
483
} else {
434
- Matcher tzMatcher = TIME_OFFSET_PATTERN .matcher (args [0 ].toString ());
435
- int hours , minutes , millis = 0 ;
436
- if (tzMatcher .matches ()) {
437
- hours = Integer .parseInt (tzMatcher .group (2 ));
438
- minutes = Integer .parseInt (tzMatcher .group (3 ));
439
- millis = (hours * 60 + minutes ) * 60 * 1000 ;
440
- if (tzMatcher .group (1 ).equals ("-" ))
441
- millis = -millis ;
442
- } else {
443
- throw getRuntime ().newArgumentError ("\" +HH:MM\" or \" -HH:MM\" expected for utc_offset" );
444
- }
445
- return newTime (getRuntime (), dt .withZone (DateTimeZone .forOffsetMillis (millis )), nsec );
484
+ DateTimeZone dtz = getTimeZoneFromUtcOffset (context .runtime , args [0 ]);
485
+ return newTime (getRuntime (), dt .withZone (dtz ), nsec );
446
486
}
447
487
}
448
488
@@ -725,8 +765,8 @@ private IRubyObject inspectCommon(DateTimeFormatter formatter, DateTimeFormatter
725
765
@ JRubyMethod (name = "to_a" )
726
766
@ Override
727
767
public RubyArray to_a () {
728
- return getRuntime ().newArrayNoCopy (new IRubyObject [] { sec (), min (), hour (), mday (), month (),
729
- year (), wday (), yday (), isdst (), zone () });
768
+ return getRuntime ().newArrayNoCopy (new IRubyObject []{ sec (), min (), hour (), mday (), month (),
769
+ year (), wday (), yday (), isdst (), zone ()});
730
770
}
731
771
732
772
@ JRubyMethod (name = "to_f" )
@@ -804,7 +844,7 @@ public RubyInteger year() {
804
844
805
845
@ JRubyMethod (name = "wday" )
806
846
public RubyInteger wday () {
807
- return getRuntime ().newFixnum ((dt .getDayOfWeek ()% 7 ));
847
+ return getRuntime ().newFixnum ((dt .getDayOfWeek () % 7 ));
808
848
}
809
849
810
850
@ JRubyMethod (name = "yday" )
@@ -826,8 +866,7 @@ public IRubyObject subsec() {
826
866
@ JRubyMethod (name = {"gmt_offset" , "gmtoff" , "utc_offset" })
827
867
public RubyInteger gmt_offset () {
828
868
int offset = dt .getZone ().getOffset (dt .getMillis ());
829
-
830
- return getRuntime ().newFixnum ((int )(offset /1000 ));
869
+ return getRuntime ().newFixnum (offset / 1000 );
831
870
}
832
871
833
872
@ JRubyMethod (name = {"isdst" , "dst?" })
@@ -995,7 +1034,7 @@ public RubyTime round(ThreadContext context, IRubyObject[] args) {
995
1034
public static IRubyObject s_new (IRubyObject recv , IRubyObject [] args , Block block ) {
996
1035
Ruby runtime = recv .getRuntime ();
997
1036
RubyTime time = new RubyTime (runtime , (RubyClass ) recv , new DateTime (getLocalTimeZone (runtime )));
998
- time .callInit (args ,block );
1037
+ time .callInit (args , block );
999
1038
return time ;
1000
1039
}
1001
1040
@@ -1278,10 +1317,10 @@ private static RubyTime createTime(IRubyObject recv, IRubyObject[] args, boolean
1278
1317
dtz = DateTimeZone .UTC ;
1279
1318
} else if (args .length == 10 && args [9 ] instanceof RubyString ) {
1280
1319
if (utcOffset ) {
1281
- dtz = getTimeZoneFromUtcOffset (runtime , (( RubyString ) args [9 ]). toString () );
1320
+ dtz = getTimeZoneFromUtcOffset (runtime , args [9 ]);
1282
1321
setTzRelative = true ;
1283
1322
} else {
1284
- dtz = getTimeZoneFromString (runtime , (( RubyString ) args [9 ]) .toString ());
1323
+ dtz = getTimeZoneFromString (runtime , args [9 ].toString ());
1285
1324
}
1286
1325
} else if (args .length == 10 && args [9 ].respondsTo ("to_int" )) {
1287
1326
IRubyObject offsetInt = args [9 ].callMethod (runtime .getCurrentContext (), "to_int" );
@@ -1291,7 +1330,7 @@ private static RubyTime createTime(IRubyObject recv, IRubyObject[] args, boolean
1291
1330
}
1292
1331
1293
1332
if (args .length == 10 ) {
1294
- if (args [8 ] instanceof RubyBoolean ) isDst = (( RubyBoolean ) args [8 ]) .isTrue ();
1333
+ if (args [8 ] instanceof RubyBoolean ) isDst = args [8 ].isTrue ();
1295
1334
1296
1335
args = new IRubyObject [] { args [5 ], args [4 ], args [3 ], args [2 ], args [1 ], args [0 ], runtime .getNil () };
1297
1336
} else {
0 commit comments