Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: a915eebaccdf
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: f9194541c358
Choose a head ref
  • 3 commits
  • 3 files changed
  • 1 contributor

Commits on Nov 25, 2015

  1. [Truffle] fix Time#localtime

    pitr-ch committed Nov 25, 2015
    Copy the full SHA
    2476aef View commit details
  2. [Truffle] code style

    pitr-ch committed Nov 25, 2015
    Copy the full SHA
    22a6c09 View commit details
  3. Copy the full SHA
    f919454 View commit details
1 change: 0 additions & 1 deletion spec/truffle/tags/core/time/localtime_tags.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
fails:Time#localtime returns a Time with a UTC offset of the specified number of Rational seconds
fails:Time#localtime changes the timezone according to the set one
fails:Time#localtime with an argument that responds to #to_r coerces using #to_r
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/time/zone_tags.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
fails:Time#zone returns the correct timezone for a local time
fails:Time#zone returns nil when getting the local time with a fixed offset
fails:Time#zone Encoding.default_internal is set returns the string with the default internal encoding
fails:Time#zone Encoding.default_internal is set returns an ASCII string
fails:Time#zone returns UTC when called on a UTC time
Original file line number Diff line number Diff line change
@@ -19,6 +19,8 @@
import org.jcodings.specific.UTF8Encoding;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.tz.FixedDateTimeZone;
import org.jruby.runtime.Helpers;
import org.jruby.truffle.nodes.RubyGuards;
import org.jruby.truffle.nodes.core.TimeNodes;
import org.jruby.truffle.nodes.objects.AllocateObjectNode;
@@ -29,7 +31,11 @@
import org.jruby.truffle.runtime.core.StringOperations;
import org.jruby.truffle.runtime.layouts.Layouts;
import org.jruby.util.RubyDateFormatter;
import org.jruby.util.StringSupport;

import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Rubinius primitives associated with the Ruby {@code Time} class.
@@ -41,7 +47,7 @@ public static abstract class TimeSNowPrimitiveNode extends RubiniusPrimitiveNode

@Child private AllocateObjectNode allocateObjectNode;
@Child private ReadTimeZoneNode readTimeZoneNode;

public TimeSNowPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
allocateObjectNode = AllocateObjectNodeGen.create(context, sourceSection, null, null);
@@ -53,7 +59,7 @@ public DynamicObject timeSNow(VirtualFrame frame, DynamicObject timeClass) {
// TODO CS 4-Mar-15 whenever we get time we have to convert lookup and time zone to a string and look it up - need to cache somehow...
return allocateObjectNode.allocate(timeClass, now((DynamicObject) readTimeZoneNode.execute(frame)), nil());
}

@TruffleBoundary
private DateTime now(DynamicObject timeZone) {
assert RubyGuards.isRubyString(timeZone);
@@ -193,7 +199,7 @@ public DynamicObject timeDecompose(VirtualFrame frame, DynamicObject time) {
zone = createString(StringOperations.encodeByteList(zoneString, UTF8Encoding.INSTANCE));
}

final Object[] decomposed = new Object[]{sec, min, hour, day, month, year, wday, yday, isdst, zone};
final Object[] decomposed = new Object[]{ sec, min, hour, day, month, year, wday, yday, isdst, zone };
return Layouts.ARRAY.createArray(getContext().getCoreLibrary().getArrayFactory(), decomposed, decomposed.length);
}

@@ -230,18 +236,18 @@ public TimeSFromArrayPrimitiveNode(RubyContext context, SourceSection sourceSect

@Specialization
public DynamicObject timeSFromArray(VirtualFrame frame, DynamicObject timeClass, int sec, int min, int hour, int mday, int month, int year,
int nsec, int isdst, boolean fromutc, Object utcoffset) {
int nsec, int isdst, boolean fromutc, Object utcoffset) {
return buildTime(frame, timeClass, sec, min, hour, mday, month, year, nsec, isdst, fromutc, utcoffset);
}

@Specialization(guards = "!isInteger(sec) || !isInteger(nsec)")
public DynamicObject timeSFromArrayFallback(VirtualFrame frame, DynamicObject timeClass, Object sec, int min, int hour, int mday, int month, int year,
Object nsec, int isdst, boolean fromutc, Object utcoffset) {
Object nsec, int isdst, boolean fromutc, Object utcoffset) {
return null; // Primitive failure
}

private DynamicObject buildTime(VirtualFrame frame, DynamicObject timeClass, int sec, int min, int hour, int mday, int month, int year,
int nsec, int isdst, boolean fromutc, Object utcoffset) {
int nsec, int isdst, boolean fromutc, Object utcoffset) {
CompilerDirectives.transferToInterpreter();

if (sec < 0 || sec > 59 ||
@@ -319,23 +325,147 @@ public long timeSetNSeconds(DynamicObject time, int nanoseconds) {

}

// TODO (pitr 25-Nov-2015): clen up the implementation
@RubiniusPrimitive(name = "time_env_zone")
public static abstract class TimeEnvZonePrimitiveNode extends RubiniusPrimitiveNode {

@Child private ReadTimeZoneNode readTimeZoneNode;

public TimeEnvZonePrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
readTimeZoneNode = new ReadTimeZoneNode(context, sourceSection);
}

@TruffleBoundary
@Specialization
public Object timeEnvZone(DynamicObject time) {
final DateTime dt = Layouts.TIME.getDateTime(time);
public Object timeEnvZone(VirtualFrame frame, DynamicObject time) {
DateTime dt = Layouts.TIME.getDateTime(time);
final DynamicObject zoneName = (DynamicObject) readTimeZoneNode.execute(frame);
final DateTimeZone zone = parseTimeZoneString(StringOperations.getString(getContext(), zoneName));

dt = dt.withZone(zone);
Layouts.TIME.setDateTime(time, dt);
Layouts.TIME.setOffset(time, dt.getZone().getOffset(dt.getMillis()) / 1_000);

final String timezone = dt.getZone().getShortName(dt.getMillis());

return createString(StringOperations.encodeByteList(timezone, UTF8Encoding.INSTANCE));
}

// Following private methods in this class were copied over from org.jruby.RubyTime.
// Slight modifications were made.

/* Version: EPL 1.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Eclipse Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.eclipse.org/legal/epl-v10.html
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* Copyright (C) 2001 Chad Fowler <chadfowler@chadfowler.com>
* Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
* Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
* Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
* Copyright (C) 2004 Joey Gibson <joey@joeygibson.com>
* Copyright (C) 2004 Charles O Nutter <headius@headius.com>
* Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
* Copyright (C) 2006 Thomas E Enebo <enebo@acm.org>
* Copyright (C) 2006 Ola Bini <ola.bini@ki.se>
* Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com>
* Copyright (C) 2009 Joseph LaFata <joe@quibb.org>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the EPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the EPL, the GPL or the LGPL.
*/

private static final Pattern TZ_PATTERN
= Pattern.compile("([^-\\+\\d]+)?([\\+-]?)(\\d+)(?::(\\d+))?(?::(\\d+))?");

private static final Map<String, String> LONG_TZNAME = Helpers.map(
"MET", "CET", // JRUBY-2759
"ROC", "Asia/Taipei", // Republic of China
"WET", "Europe/Lisbon" // Western European Time
);

private DateTimeZone parseTimeZoneString(String zone) {
String upZone = zone.toUpperCase(Locale.ENGLISH);

Matcher tzMatcher = TZ_PATTERN.matcher(zone);
if (tzMatcher.matches()) {
String zoneName = tzMatcher.group(1);
String sign = tzMatcher.group(2);
String hours = tzMatcher.group(3);
String minutes = tzMatcher.group(4);
String seconds = tzMatcher.group(5);

if (zoneName == null) {
zoneName = "";
}

// Sign is reversed in legacy TZ notation
return getTimeZoneFromHHMM(zoneName, sign.equals("-"), hours, minutes, seconds);
} else {
if (LONG_TZNAME.containsKey(upZone)) {
zone = LONG_TZNAME.get(upZone);
} else if (upZone.equals("UTC") || upZone.equals("GMT")) {
// MRI behavior: With TZ equal to "GMT" or "UTC", Time.now
// is *NOT* considered as a proper GMT/UTC time:
// ENV['TZ']="GMT"; Time.now.gmt? #=> false
// ENV['TZ']="UTC"; Time.now.utc? #=> false
// Hence, we need to adjust for that.
zone = "Etc/" + upZone;
}

try {
return DateTimeZone.forID(zone);
} catch (IllegalArgumentException e) {
return DateTimeZone.UTC;
}
}
}

private DateTimeZone getTimeZoneFromHHMM(String name, boolean positive, String hours, String minutes, String seconds) {
int h = Integer.parseInt(hours);
int m = 0;
int s = 0;
if (minutes != null) {
m = Integer.parseInt(minutes);
}

if (seconds != null) {
s = Integer.parseInt(seconds);
}

if (h > 23 || m > 59) {
throw new RaiseException(getContext().getCoreLibrary().argumentError("utc_offset out of range", this));
}

int offset = (positive ? +1 : -1) * ((h * 3600) + m * 60 + s) * 1000;
return timeZoneWithOffset(name, offset);
}

private DateTimeZone timeZoneWithOffset(String zoneName, int offset) {
if (zoneName.isEmpty()) {
return DateTimeZone.forOffsetMillis(offset);
} else {
return new FixedDateTimeZone(zoneName, null, offset, offset);
}
}

}

@RubiniusPrimitive(name = "time_utc_offset")
@@ -348,6 +478,7 @@ public TimeUTCOffsetPrimitiveNode(RubyContext context, SourceSection sourceSecti
@TruffleBoundary
@Specialization
public Object timeUTCOffset(DynamicObject time) {

Object offset = Layouts.TIME.getOffset(time);
if (offset != nil()) {
return offset;