Java tutorial
/* * R : A Computer Language for Statistical Data Analysis * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka * Copyright (C) 1997--2008 The R Development Core Team * Copyright (C) 2003, 2004 The R Foundation * Copyright (C) 2010 bedatadriven * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.renjin.primitives.time; import com.google.common.base.Strings; import org.joda.time.*; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeParser; import org.joda.time.format.DateTimeParserBucket; import org.renjin.invoke.annotations.Internal; import org.renjin.sexp.*; import java.util.List; import java.util.Locale; /** * Implementation of date time-related functions. * * <p> * R has three representations of date/times: * * <ul> * <li>POSIXct - which is a stored as DoubleVector with the number seconds since Jan 1st 1970, with * classes "POSIXct" and "POSIXt"</li> * <li>POSIXlt - which is stored as ListVector containing calendar elements sec, min, mon, etc</li> * <li>Date - which is stored as a DoubleVector with the number of days since Jan 1st 1970, where * Jan 1st, 1970 is day zero.</li> * </ul> */ public class Time { public static DateTime EPOCH = new DateTime(1970, 1, 1, 0, 0, 0); /** * Parses a string value into a date time value. * @return */ @Internal public static SEXP strptime(StringVector x, StringVector formats, String tz) { if (x.length() == 0 || formats.length() == 0) { return StringVector.EMPTY; } DateTimeZone timeZone = timeZoneFromRSpecification(tz); List<DateTimeFormatter> formatters = DateTimeFormat.forPatterns(formats, timeZone, false); PosixLtVector.Builder result = new PosixLtVector.Builder(); int resultLength = Math.max(x.length(), formats.length()); for (int i = 0; i != resultLength; ++i) { DateTimeFormatter formatter = formatters.get(i % formatters.size()); String string = x.getElementAsString(i % x.length()); try { result.add(parseIgnoreTrailingCharacters(formatter, string)); } catch (IllegalArgumentException e) { result.addNA(); } } if (!Strings.isNullOrEmpty(tz)) { result.withTimeZone(timeZone); } return result.buildListVector(); } private static DateTime parseIgnoreTrailingCharacters(DateTimeFormatter formatter, String text) { // this is a modified version of DateTimeFormatter.parseDateTime() that does not // throw an exception on trailing characters Chronology chronology = DateTimeUtils.getChronology(null); DateTimeParser parser = formatter.getParser(); Locale locale = null; Integer pivotYear = null; int defaultYear = 2000; DateTimeZone timeZone = null; DateTimeParserBucket bucket = new DateTimeParserBucket(0, chronology, locale, pivotYear, defaultYear); int newPos = parser.parseInto(bucket, text, 0); if (newPos >= 0) { long millis = bucket.computeMillis(true, text); if (formatter.isOffsetParsed() && bucket.getOffsetInteger() != null) { int parsedOffset = bucket.getOffsetInteger(); DateTimeZone parsedZone = DateTimeZone.forOffsetMillis(parsedOffset); chronology = chronology.withZone(parsedZone); } else if (bucket.getZone() != null) { chronology = chronology.withZone(bucket.getZone()); } DateTime dt = new DateTime(millis, chronology); if (timeZone != null) { dt = dt.withZone(timeZone); } return dt; } throw new IllegalArgumentException(); } /** * Converts a calendar-based representation of time (POSIXlt: see above) to * a unix time value. * * @param x a ListVector containing the fields above */ @Internal("as.POSIXct") public static DoubleVector asPOSIXct(ListVector x, String tz) { return new PosixCtVector.Builder().addAll(new PosixLtVector(x)).buildDoubleVector(); } @Internal("as.POSIXlt") public static ListVector asPOSIXlt(DoubleVector x, String tz) { return new PosixLtVector.Builder().addAll(new PosixCtVector(x)).buildListVector(); } /** * Converts a POSIXlt object (in calendar form) to a Date object, * which stores dates as an offset from Jan 1, 1970. */ @Internal public static DoubleVector POSIXlt2Date(ListVector x) { PosixLtVector ltVector = new PosixLtVector(x); DoubleArrayVector.Builder dateVector = DoubleArrayVector.Builder.withInitialCapacity(ltVector.length()); for (int i = 0; i != ltVector.length(); ++i) { DateTime date = ltVector.getElementAsDateTime(i); dateVector.add(Days.daysBetween(EPOCH, date).getDays()); } dateVector.setAttribute(Symbols.CLASS, StringVector.valueOf("Date")); return dateVector.build(); } @Internal public static ListVector Date2POSIXlt(DoubleVector x) { PosixLtVector.Builder ltVector = new PosixLtVector.Builder(); for (int i = 0; i != x.length(); ++i) { int daysSinceEpoch = x.getElementAsInt(i); ltVector.add(EPOCH.plusDays(daysSinceEpoch)); } return ltVector.buildListVector(); } @Internal("Sys.time") public static DoubleVector sysTime() { return new PosixCtVector.Builder().add(new DateTime()).buildDoubleVector(); } /** * Formats a Posix-lt time as a string. */ @Internal("format.POSIXlt") public static StringVector formatPOSIXlt(ListVector x, StringVector patterns, boolean useTz) { PosixLtVector dateTimes = new PosixLtVector(x); List<DateTimeFormatter> formatters = DateTimeFormat.forPatterns(patterns, DateTimeZone.getDefault(), useTz); StringVector.Builder result = new StringVector.Builder(); int resultLength = Math.max(dateTimes.length(), patterns.length()); for (int i = 0; i != resultLength; ++i) { DateTimeFormatter formatter = formatters.get(i % formatters.size()); DateTime dateTime = dateTimes.getElementAsDateTime(i % dateTimes.length()); result.add(formatter.print(dateTime)); } return result.build(); } /** * Creates a Joda {@link DateTimeZone} instance from an R timezone string. */ public static DateTimeZone timeZoneFromRSpecification(String tz) { if (Strings.isNullOrEmpty(tz)) { return DateTimeZone.getDefault(); } else if ("GMT".equals(tz)) { return DateTimeZone.UTC; } else { // TODO: this probably isn't right.. return DateTimeZone.forID(tz); } } /** * Creates a Joda {@link DateTimeZone} instance from the {@code tzone} * attribute of an R Posix object. Returns the current timezone if * there is no {@code tzone} attribute; */ public static DateTimeZone timeZoneFromPosixObject(SEXP lt) { SEXP attribute = lt.getAttribute(Symbols.TZONE); if (attribute instanceof StringVector) { return timeZoneFromRSpecification(((StringVector) attribute).getElementAsString(0)); } else { return DateTimeZone.getDefault(); } } }