Пример #1
0
SEXP make_d(SEXP year, SEXP month, SEXP day) {

  if(!isInteger(year)) error("year must be integer");
  if(!isInteger(month)) error("month must be integer");
  if(!isInteger(day)) error("day must be integer");

  R_len_t n = LENGTH(year);
  if(n != LENGTH(month)) error("length of 'month' vector is not the same as that of 'year'");
  if(n != LENGTH(day)) error("length of 'day' vector is not the same as that of 'year'");

  int* pyear = INTEGER(year);
  int* pmonth = INTEGER(month);
  int* pday = INTEGER(day);

  SEXP res = allocVector(REALSXP, n);
  double *data = REAL(res);

  for(int i = 0; i < n; i++) {

	// main accumulator
    double SECS = 0.0;

	int y = pyear[i];
	int m = pmonth[i];
	int d = pday[i];

	if(y == NA_INTEGER || m == NA_INTEGER || d == NA_INTEGER) {

	  data[i] = NA_REAL;

	} else {

	  if ( 0 < m && m < 13 )
		SECS += sm[m];
	  else {
		data[i] = NA_REAL;
		continue;
	  }

	  if ( 0 < d && d < 32 )
		SECS += (d - 1) * 86400;
	  else {
		data[i] = NA_REAL;
		continue;
	  }

	  int is_leap = IS_LEAP(y);

	  if(check_ymd(y, m, d, is_leap)){

		SECS += d30;
		y -= 2000;
		SECS += y * yearlen;
		SECS += adjust_leap_years(y, m, is_leap);
		data[i] = SECS;

	  } else {

		data[i] = NA_REAL;

	  }
	}
  }

  return res;
}
Пример #2
0
SEXP make_dt(SEXP year, SEXP month, SEXP day, SEXP hour, SEXP minute, SEXP second) {

  if(!isInteger(year)) error("year must be integer");
  if(!isInteger(month)) error("month must be integer");
  if(!isInteger(day)) error("day must be integer");
  if(!isInteger(hour)) error("hour must be integer");
  if(!isInteger(minute)) error("minute must be integer");
  if(!isNumeric(second)) error("second must be numeric");

  R_len_t n = LENGTH(year);
  
  if(n != LENGTH(month)) error("length of 'month' vector is not the same as that of 'year'");
  if(n != LENGTH(day)) error("length of 'day' vector is not the same as that of 'year'");
  if(n != LENGTH(hour)) error("length of 'hour' vector is not the same as that of 'year'");
  if(n != LENGTH(minute)) error("length of 'minute' vector is not the same as that of 'year'");
  if(n != LENGTH(second)) error("length of 'second' vector is not the same as that of 'year'");

  int* pyear = INTEGER(year);
  int* pmonth = INTEGER(month);
  int* pday = INTEGER(day);
  int* phour = INTEGER(hour);
  int* pminute = INTEGER(minute);

  int int_second = TYPEOF(second) == INTSXP;

  SEXP res = allocVector(REALSXP, n);
  double *data = REAL(res);

  for(int i = 0; i < n; i++) {

	// main accumulator
    double SECS = 0.0;

	int y = pyear[i];
	int m = pmonth[i];
	int d = pday[i];
	int H = phour[i];
	int M = pminute[i];
	int naS;
	double S;

	if(int_second){
	  S = (double) INTEGER(second)[i];
	  naS = INTEGER(second)[i] == NA_INTEGER;
	} else {
	  S = REAL(second)[i];
	  naS = ISNA(S);
	}

	if(naS || y == NA_INTEGER || m == NA_INTEGER || d == NA_INTEGER || H == NA_INTEGER || M == NA_INTEGER) {

	  data[i] = NA_REAL;

	} else {
	  
	  if ( 0 < m && m < 13 )
		SECS += sm[m];
	  else {
		data[i] = NA_REAL;
		continue;
	  }
	
	  if ( 0 < d && d < 32 )
		SECS += (d - 1) * 86400;
	  else {
		data[i] = NA_REAL;
		continue; 
	  }

	  if( H < 25 )
		SECS += H * 3600;
	  else {
		data[i] = NA_REAL;
		continue;
	  }
	
	  if ( M < 61 )
		SECS += M * 60;
	  else{
		data[i] = NA_REAL;
		continue;
	  }

	  // allow leap seconds
	  if ( S < 62 ) {
		SECS += S;
	  } else {
		data[i] = NA_REAL;
		continue;
	  }

	  int is_leap = LEAP(y);

	  if(check_ymd(y, m, d, is_leap)){
	
		SECS += d30;
		y -= 2000;
		SECS += y * yearlen;
		SECS += adjust_leap_years(y, m, is_leap);

		data[i] = SECS;
	  
	  } else {
		data[i] = NA_REAL;
	  }
	}
  }
  
  return res;
}
Пример #3
0
SEXP parse_dt(SEXP str, SEXP ord, SEXP formats, SEXP lt) {
  // STR: character vector of date-times.
  // ORD: formats (as in strptime) or orders (as in parse_date_time)
  // FORMATS: TRUE if ord is a string of formats (as in strptime)
  // LT: TRUE - return POSIXlt type list, FALSE - return POSIXct seconds

  if ( !isString(str) ) error("Date-time must be a character vector");
  if ( !isString(ord) || (LENGTH(ord) > 1))
    error("Format argument must be a character vector of length 1");

  R_len_t n = LENGTH(str);
  int is_fmt = *LOGICAL(formats);
  int out_lt = *LOGICAL(lt);

  SEXP oYEAR, oMONTH, oDAY, oHOUR, oMIN, oSEC;

  if(out_lt){
    oYEAR  = PROTECT(allocVector(INTSXP, n));
    oMONTH = PROTECT(allocVector(INTSXP, n));
    oDAY   = PROTECT(allocVector(INTSXP, n));
    oHOUR  = PROTECT(allocVector(INTSXP, n));
    oMIN   = PROTECT(allocVector(INTSXP, n));
    oSEC   = PROTECT(allocVector(REALSXP, n));
  } else {
    oSEC = PROTECT(allocVector(REALSXP, n));
  }

  const char *O = CHAR(STRING_ELT(ord, 0));

  for (int i = 0; i < n; i++) {

    const char *c = CHAR(STRING_ELT(str, i));
    const char *o = O;

    double secs = 0.0; // only accumulator for POSIXct case
    int y = 0, q = 0, m = 0, d = 0, H = 0, M = 0 , S = 0;
    int succeed = 1, O_format = 0, pm = 0, am = 0; // control logical

    // read order/format character by character
    while( *o && succeed ) {

      if( is_fmt && (*o != '%')) {
        // with fmt: non formatting characters should match exactly
        if ( *c == *o ) { c++; o++; } else succeed = 0;

      } else {

        if ( is_fmt ){
          o++; // skip %
        } else if ( *o != 'O' && *o != 'z' && *o != 'p' && *o != 'm' && *o != 'b' && *o != 'B') {
          // skip non-digits
          // O, z, p formats are treated specially below
          while (*c && !DIGIT(*c)) c++;
		}

        if ( *o == 'O' ) {
          // Special two letter orders/formats:
		  // Ou (Z), Oz (-0800), OO (-08:00) and Oo (-08)
          O_format = 1;
          o++;
        } else {
		  O_format = 0;
		}

        if (!(DIGIT(*c) || O_format || *o == 'z' || *o == 'p' || *o == 'm' || *o == 'b' || *o == 'B')) {
          succeed = 0;
        } else {

          /* Rprintf("c=%c o=%c\n", *c, *o); */

          switch( *o ) {
          case 'Y': // year in yyyy format
            y = parse_int(&c, 4, TRUE);
            if (y < 0)
              succeed = 0;
            break;
          case 'y': // year in yy format
            y = parse_int(&c, 2, FALSE);
            if (y < 0)
              succeed = 0;
			else if (y <= 68)
			  y += 2000;
			else
			  y += 1900;
            break;
          case 'q': // quarter
            q = parse_int(&c, 2, FALSE);
            if (!(0 < q && q < 5)) succeed = 0;
            break;
          case 'm': // month (allowing all months formats - m, b and B)
            SKIP_NON_ALPHANUMS(c);
            m = parse_int(&c, 2, FALSE);
            if (m == -1) { // failed
              m = parse_alpha_month(&c);
              if (m == 0) { // failed
                SKIP_NON_DIGITS(c);
                m = parse_int(&c, 2, FALSE);
              }
            }
            if (!(0 < m && m < 13))
              succeed = 0;
            break;
          case 'b': // alpha English months (both abbreviated and long versions)
          case 'B':
            /* SKIP_NON_ALPHANUMS(c); */
            m = parse_alpha_month(&c);
            succeed = m;
            /* Rprintf("succ=%d c=%c\n", succeed, *c); */
            break;
          case 'd': // day
            d = parse_int(&c, 2, FALSE);
            if (!(0 < d && d < 32)) succeed = 0;
            break;
          case 'H': // hour 24
            H = parse_int(&c, 2, FALSE);
            if (H > 24) succeed = 0;
            break;
          case 'I': // hour 12
            H = parse_int(&c, 2, FALSE);
            if (H > 12) succeed = 0;
            break;
          case 'M': // minute
            M = parse_int(&c, 2, FALSE);
            if (M > 59) succeed = 0;
            break;
          case 'S': // second
            if( O_format && !is_fmt ){
              while (*c && !DIGIT(*c)) c++;
              if (!*c) {
                succeed = 0;
                break;
              }
            }
            S = parse_int(&c, 2, FALSE);
            if (S < 62){ // allow leap seconds
              secs += S;
              if (O_format){
                // Parse milliseconds; both . and , as decimal separator are allowed
                if( *c == '.' || *c == ','){
                  double ms = 0.0, msfact = 0.1;
                  c++;
                  while (DIGIT(*c)) { ms = ms + (*c - '0')*msfact; msfact *= 0.1; c++; }
                  secs += ms;
                }
              }
            } else succeed = 0;
            break;
          case 'p': // AM/PM Both standard 'p' and lubridate 'Op' format
            SKIP_NON_ALPHANUMS(c);
            if (O_format) {
              // with Op format, p is optional (for order parsimony reasons)
              if (!(*c == 'P' || *c == 'p' || *c == 'A' || *c == 'a'))
                break;
            }
            if (*c == 'P' || *c == 'p') {
              pm = 1;
              c++;
            } else if (*c == 'A' ||  *c == 'a'){
              am = 1;
              c++;
            } else {
              succeed = 0;
            }
            if (succeed && !(*c && (*c == 'M' || *c == 'm'))){
              succeed = 0;
            }
            if (succeed) c++;
            break;
		  case 'u':
			// %Ou: "2013-04-16T04:59:59Z"
            if( O_format )
              if( *c == 'Z' || *c == 'z') c++;
              else succeed = 0;
            else succeed  = 0;
            break;
          case 'z':
            // for %z: "+O100" or "+O1" or "+01:00"
            if( !O_format ) {
              if( !is_fmt ) {
                while (*c && *c != '+' && *c != '-' && *c != 'Z') c++; // skip non + -
                if( !*c ) { succeed = 0; break; };
              }
              int Z = 0, sig;
              if( *c == 'Z') {c++; break;}
              else if ( *c == '+' ) sig = -1;
              else if ( *c == '-') sig = 1;
              else {succeed = 0; break;}
              c++;
              Z = parse_int(&c, 2, FALSE);
              if (Z < 0) {succeed = 0; break;}
              secs += sig*Z*3600;
              if( *c == ':' ){
                c++;
                if ( !DIGIT(*c) ) {succeed = 0; break;}
              }
              if( DIGIT(*c) ){
                Z = 0;
                Z = parse_int(&c, 2, FALSE);
                secs += sig*Z*60;
              }
              break;
            }
            // else O_format %Oz: "+0100"; pass through
          case 'O':
            // %OO: "+01:00"
          case 'o':
            // %Oo: "+01"
            if( O_format ){
              while (*c && *c != '+' && *c != '-' ) c++; // skip non + -
              int Z = 0, sig;
              if ( *c == '+' ) sig = -1;
              else if ( *c == '-') sig = 1;
              else { succeed = 0; break; }
              c++;
              Z = parse_int(&c, 2, FALSE);
              if (Z < 0) {succeed = 0; break;}
              secs += sig*Z*3600;
              if( *o == 'O'){
                if ( *c == ':') c++;
				else { succeed = 0; break; }
			  }
              if ( *o != 'o' ){ // z or O
                Z = parse_int(&c, 2, FALSE);
                if (Z < 0) {succeed = 0; break;}
                secs += sig*Z*60;
              }
            } else error("Unrecognized format '%c' supplied", *o);
            break;
          default:
            error("Unrecognized format %c supplied", *o);
          }

          o++;
        }
      }
    }

    // skip all remaining non digits
    if( !is_fmt )
      while (*c && !DIGIT(*c)) c++;

    // If at least one subparser hasn't finished it's a failure.
    if ( *c || *o ) succeed = 0;

    int is_leap;

    // adjust months for quarter
    if (q > 1)
      m += (q - 1) * 3 + 1;

    if (succeed) {
      // leap year every 400 years; no leap every 100 years
      is_leap = IS_LEAP(y);

      // check month
      if (m == 2){
		// no check for d > 0 because we allow missing days in parsing
        if (is_leap)
          succeed = d < 30;
        else
          succeed = d < 29;
      } else {
		succeed = d <= mdays[m];
      }
    }

    // allow missing months and days
    if (m == 0) m = 1;
    if (d == 0) d = 1;

    if(pm){
      if(H > 12)
        succeed = 0;
      else if (H < 12)
        H += 12;
    }

    if (am){
      if (H > 12)
        succeed = 0;
      else if (H == 12)
        H = 0;
    }

    if (succeed) {
      if(out_lt){

        INTEGER(oYEAR)[i] = y - 1900;
        INTEGER(oMONTH)[i] = m - 1;
        INTEGER(oDAY)[i] = d;
        INTEGER(oHOUR)[i] = H;
        INTEGER(oMIN)[i] = M;
        REAL(oSEC)[i] = secs;

      } else {

        secs += sm[m];
        secs += (d - 1) * 86400;
        secs += H * 3600;
        secs += M * 60;
        // process leap years
        y -= 2000;
        secs += y * yearlen;
        secs += adjust_leap_years(y, m, is_leap);

        REAL(oSEC)[i] = secs + d30;
      }

    } else {
      if(out_lt){
        INTEGER(oYEAR)[i] = NA_INTEGER;
        INTEGER(oMONTH)[i] = NA_INTEGER;
        INTEGER(oDAY)[i] = NA_INTEGER;
        INTEGER(oHOUR)[i] = NA_INTEGER;
        INTEGER(oMIN)[i] = NA_INTEGER;
        REAL(oSEC)[i] = NA_REAL;
      } else {
        REAL(oSEC)[i] = NA_REAL;
      }
    }
  }

  if (out_lt){
    SEXP names, out;
    PROTECT(names = allocVector(STRSXP, 6));
    for(int i = 0; i < 6; i++)
      SET_STRING_ELT(names, i, mkChar(ltnames[i]));
    PROTECT(out = allocVector(VECSXP, 6));
    SET_VECTOR_ELT(out, 0, oSEC);
    SET_VECTOR_ELT(out, 1, oMIN);
    SET_VECTOR_ELT(out, 2, oHOUR);
    SET_VECTOR_ELT(out, 3, oDAY);
    SET_VECTOR_ELT(out, 4, oMONTH);
    SET_VECTOR_ELT(out, 5, oYEAR);
    setAttrib(out, R_NamesSymbol, names);
    UNPROTECT(8);
    return out;
  } else {
    UNPROTECT(1);
    return oSEC;
  }

}