Package org.renjin.primitives.time

Source Code of org.renjin.primitives.time.Time

/*
* 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();
    }
  }
}
TOP

Related Classes of org.renjin.primitives.time.Time

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.