Пример #1
0
/** List Localizable Date-Time Formatting Data
 *
 * @param locale single string or NULL
 * @param context single string
 * @param width single string
 * @return list
 *
 * @version 0.5-1 (Marek Gagolewski, 2014-12-25)
 *
 * @version 0.5-1 (Marek Gagolewski, 2015-01-01)
 *    use calendar keyword in locale
 */
SEXP stri_datetime_symbols(SEXP locale, SEXP context, SEXP width) {
   const char* qloc = stri__prepare_arg_locale(locale, "locale", true); /* this is R_alloc'ed */

   const char* context_str = stri__prepare_arg_string_1_notNA(context, "context");
   const char* context_opts[] = {"format", "standalone", NULL};
   int context_cur = stri__match_arg(context_str, context_opts);

   const char* width_str = stri__prepare_arg_string_1_notNA(width, "width");
   const char* width_opts[] = {"abbreviated", "wide", "narrow", NULL};
   int width_cur = stri__match_arg(width_str, width_opts);

   DateFormatSymbols::DtContextType context_val;
   if (context_cur == 0)            context_val = DateFormatSymbols::FORMAT;
   else if (context_cur == 1)       context_val = DateFormatSymbols::STANDALONE;
   else Rf_error(MSG__INCORRECT_MATCH_OPTION, "context");

   DateFormatSymbols::DtWidthType width_val;
        if (width_cur == 0)       width_val = DateFormatSymbols::ABBREVIATED;
   else if (width_cur == 1)       width_val = DateFormatSymbols::WIDE;
   else if (width_cur == 2)       width_val = DateFormatSymbols::NARROW;
   else Rf_error(MSG__INCORRECT_MATCH_OPTION, "width");

   UErrorCode status = U_ZERO_ERROR;
   String8buf calendar_type(128);
   Locale loc = Locale::createFromName(qloc);
   int32_t kvlen = loc.getKeywordValue("calendar", calendar_type.data(), calendar_type.size(), status);
   STRI__CHECKICUSTATUS_RFERROR(status, {/* do nothing special on err */})

   status = U_ZERO_ERROR;
   DateFormatSymbols sym(status);
   status = U_ZERO_ERROR;
   if (kvlen == 0)
      sym = DateFormatSymbols(loc, status);
   else
      sym = DateFormatSymbols(loc, calendar_type.data(), status);
   STRI__CHECKICUSTATUS_RFERROR(status, {/* do nothing special on err */})
Пример #2
0
/** Get localized time zone info
 *
 * @param tz single string or NULL
 * @param locale single string or NULL
 * @param display_type single string
 * @return list
 *
 * @version 0.5-1 (Marek Gagolewski, 2014-12-24)
 *
 * @version 0.5-1 (Marek Gagolewski, 2015-03-01)
 *    new out: WindowsID, NameDaylight, new in: display_type
 */
SEXP stri_timezone_info(SEXP tz, SEXP locale, SEXP display_type) {
   TimeZone* curtz = stri__prepare_arg_timezone(tz, "tz", R_NilValue);
   const char* qloc = stri__prepare_arg_locale(locale, "locale", true); /* this is R_alloc'ed */
   const char* dtype_str = stri__prepare_arg_string_1_notNA(display_type, "display_type"); /* this is R_alloc'ed */
   const char* dtype_opts[] = {
      "short", "long", "generic_short", "generic_long", "gmt_short", "gmt_long",
      "common", "generic_location",
      NULL};
   int dtype_cur = stri__match_arg(dtype_str, dtype_opts);

   TimeZone::EDisplayType dtype;
   switch (dtype_cur) {
      case 0:  dtype = TimeZone::SHORT; break;
      case 1:  dtype = TimeZone::LONG; break;
      case 2:  dtype = TimeZone::SHORT_GENERIC; break;
      case 3:  dtype = TimeZone::LONG_GENERIC; break;
      case 4:  dtype = TimeZone::SHORT_GMT; break;
      case 5:  dtype = TimeZone::LONG_GMT; break;
      case 6:  dtype = TimeZone::SHORT_COMMONLY_USED; break;
      case 7:  dtype = TimeZone::GENERIC_LOCATION; break;
      default: Rf_error(MSG__INCORRECT_MATCH_OPTION, "display_type"); break;
   }

   const R_len_t infosize = 6;
   SEXP vals;

   PROTECT(vals = Rf_allocVector(VECSXP, infosize));
   for (int i=0; i<infosize; ++i)
      SET_VECTOR_ELT(vals, i, R_NilValue);

   R_len_t curidx = -1;

   ++curidx;
   UnicodeString val_ID;
   curtz->getID(val_ID);
   SET_VECTOR_ELT(vals, curidx, stri__make_character_vector_UnicodeString_ptr(1, &val_ID));

   ++curidx;
   UnicodeString val_name;
   curtz->getDisplayName(false, dtype, Locale::createFromName(qloc), val_name);
   SET_VECTOR_ELT(vals, curidx, stri__make_character_vector_UnicodeString_ptr(1, &val_name));

   ++curidx;
   if ((bool)curtz->useDaylightTime()) {
      UnicodeString val_name2;
      curtz->getDisplayName(true, dtype, Locale::createFromName(qloc), val_name2);
      SET_VECTOR_ELT(vals, curidx, stri__make_character_vector_UnicodeString_ptr(1, &val_name2));
   }
   else
      SET_VECTOR_ELT(vals, curidx, Rf_ScalarString(NA_STRING));

   ++curidx;
   UnicodeString val_windows;
   UErrorCode status = U_ZERO_ERROR;
#if U_ICU_VERSION_MAJOR_NUM>=52
   TimeZone::getWindowsID(val_ID, val_windows, status); // Stable since ICU 52
#endif
   if (U_SUCCESS(status) && val_windows.length() > 0)
      SET_VECTOR_ELT(vals, curidx, stri__make_character_vector_UnicodeString_ptr(1, &val_windows));
   else
      SET_VECTOR_ELT(vals, curidx, Rf_ScalarString(NA_STRING));

   ++curidx;
   SET_VECTOR_ELT(vals, curidx, Rf_ScalarReal(curtz->getRawOffset()/1000.0/3600.0));

   ++curidx;
   SET_VECTOR_ELT(vals, curidx, Rf_ScalarLogical((bool)curtz->useDaylightTime()));

   delete curtz;
   stri__set_names(vals, infosize, "ID", "Name", "Name.Daylight", "Name.Windows", "RawOffset", "UsesDaylightTime");
   UNPROTECT(1);
   return vals;
}
Пример #3
0
/**
 * Format date-time objects
 *
 * @param time
 * @param format
 * @param tz
 * @param locale
 *
 * @return character vector
 *
 * @version 0.5-1 (Marek Gagolewski, 2015-01-05)
 *
 * @version 0.5-1 (Marek Gagolewski, 2015-02-22)
 *    use tz
 */
SEXP stri_datetime_format(SEXP time, SEXP format, SEXP tz, SEXP locale) {
   PROTECT(time = stri_prepare_arg_POSIXct(time, "time"));
   const char* locale_val = stri__prepare_arg_locale(locale, "locale", true);
   const char* format_val = stri__prepare_arg_string_1_notNA(format, "format");

   // "format" may be one of:
   const char* format_opts[] = {
      "date_full", "date_long", "date_medium", "date_short",
      "date_relative_full", "date_relative_long", "date_relative_medium", "date_relative_short",
      "time_full", "time_long", "time_medium", "time_short",
      "time_relative_full", "time_relative_long", "time_relative_medium", "time_relative_short",
      "datetime_full", "datetime_long", "datetime_medium", "datetime_short",
      "datetime_relative_full", "datetime_relative_long", "datetime_relative_medium", "datetime_relative_short",
      NULL};
   int format_cur = stri__match_arg(format_val, format_opts);

   TimeZone* tz_val = stri__prepare_arg_timezone(tz, "tz", true/*allowdefault*/);
   Calendar* cal = NULL;
   DateFormat* fmt = NULL;
   STRI__ERROR_HANDLER_BEGIN(1)
   R_len_t vectorize_length = LENGTH(time);
   StriContainerDouble time_cont(time, vectorize_length);
   UnicodeString format_str(format_val);

   UErrorCode status = U_ZERO_ERROR;
   if (format_cur >= 0) {
      DateFormat::EStyle style = DateFormat::kNone;
      switch (format_cur % 8) {
         case 0:  style = DateFormat::kFull; break;
         case 1:  style = DateFormat::kLong; break;
         case 2:  style = DateFormat::kMedium; break;
         case 3:  style = DateFormat::kShort; break;
         case 4:  style = DateFormat::kFullRelative; break;
         case 5:  style = DateFormat::kLongRelative; break;
         case 6:  style = DateFormat::kMediumRelative; break;
         case 7:  style = DateFormat::kShortRelative; break;
         default: style = DateFormat::kNone; break;
      }

      /* ICU 54.1: Relative time styles are not currently supported.  */
      switch (format_cur / 8) {
         case 0:
            fmt = DateFormat::createDateInstance(style,
               Locale::createFromName(locale_val));
            break;

         case 1:
            fmt = DateFormat::createTimeInstance(
               (DateFormat::EStyle)(style & ~DateFormat::kRelative),
               Locale::createFromName(locale_val));
            break;

         case 2:
            fmt = DateFormat::createDateTimeInstance(style,
               (DateFormat::EStyle)(style & ~DateFormat::kRelative),
               Locale::createFromName(locale_val));
            break;

         default:
            fmt = NULL;
            break;

      }
   }
   else
      fmt = new SimpleDateFormat(format_str, Locale::createFromName(locale_val), status);
   STRI__CHECKICUSTATUS_THROW(status, {/* do nothing special on err */})

   status = U_ZERO_ERROR;
   cal = Calendar::createInstance(locale_val, status);
   STRI__CHECKICUSTATUS_THROW(status, {/* do nothing special on err */})

   cal->adoptTimeZone(tz_val);
   tz_val = NULL; /* The Calendar takes ownership of the TimeZone. */

   SEXP ret;
   STRI__PROTECT(ret = Rf_allocVector(STRSXP, vectorize_length));
   for (R_len_t i=0; i<vectorize_length; ++i) {
      if (time_cont.isNA(i)) {
         SET_STRING_ELT(ret, i, NA_STRING);
         continue;
      }

      status = U_ZERO_ERROR;
      cal->setTime((UDate)(time_cont.get(i)*1000.0), status);
      STRI__CHECKICUSTATUS_THROW(status, {/* do nothing special on err */})

      FieldPosition pos;
      UnicodeString out;
      fmt->format(*cal, out, pos);

      std::string s;
      out.toUTF8String(s);
      SET_STRING_ELT(ret, i, Rf_mkCharLenCE(s.c_str(), (int)s.length(), (cetype_t)CE_UTF8));
   }

   if (tz_val) { delete tz_val; tz_val = NULL; }
   if (fmt) { delete fmt; fmt = NULL; }
   if (cal) { delete cal; cal = NULL; }
   STRI__UNPROTECT_ALL
   return ret;
   STRI__ERROR_HANDLER_END({
      if (tz_val) { delete tz_val; tz_val = NULL; }
      if (fmt) { delete fmt; fmt = NULL; }
      if (cal) { delete cal; cal = NULL; }
   })
}
Пример #4
0
/** Date-time artithmetic
 *
 * @param time
 * @param value
 * @param units
 * @param tz
 * @param locale
 *
 * @return POSIXst
 *
 * @version 0.5-1 (Marek Gagolewski, 2014-12-30)
 * @version 0.5-1 (Marek Gagolewski, 2015-03-06) tz arg added
 */
SEXP stri_datetime_add(SEXP time, SEXP value, SEXP units, SEXP tz, SEXP locale) {
   PROTECT(time = stri_prepare_arg_POSIXct(time, "time"));
   PROTECT(value = stri_prepare_arg_integer(value, "value"));
   if (!isNull(tz)) PROTECT(tz = stri_prepare_arg_string_1(tz, "tz"));
   else             PROTECT(tz); /* needed to set tzone attrib */

   R_len_t vectorize_length = stri__recycling_rule(true, 2, LENGTH(time), LENGTH(value));

   const char* units_val = stri__prepare_arg_string_1_notNA(units, "units");
   const char* units_opts[] = {"years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", NULL};
   int units_cur = stri__match_arg(units_val, units_opts);

   const char* locale_val = stri__prepare_arg_locale(locale, "locale", true);

   TimeZone* tz_val = stri__prepare_arg_timezone(tz, "tz", true/*allowdefault*/);

   Calendar* cal = NULL;
   STRI__ERROR_HANDLER_BEGIN(3)
   StriContainerDouble time_cont(time, vectorize_length);
   StriContainerInteger value_cont(value, vectorize_length);

   UCalendarDateFields units_field;
   switch (units_cur) {
      case 0: units_field = UCAL_YEAR;                   break;
      case 1: units_field = UCAL_MONTH;                  break;
      case 2: units_field = UCAL_WEEK_OF_YEAR;           break;
      case 3: units_field = UCAL_DAY_OF_MONTH;           break;
      case 4: units_field = UCAL_HOUR_OF_DAY;            break;
      case 5: units_field = UCAL_MINUTE;                 break;
      case 6: units_field = UCAL_SECOND;                 break;
      case 7: units_field = UCAL_MILLISECOND;            break;
      default: throw StriException(MSG__INCORRECT_MATCH_OPTION, "units");
   }

   UErrorCode status = U_ZERO_ERROR;
   cal = Calendar::createInstance(locale_val, status);
   STRI__CHECKICUSTATUS_THROW(status, {/* do nothing special on err */})

   cal->adoptTimeZone(tz_val);
   tz_val = NULL; /* The Calendar takes ownership of the TimeZone. */

   SEXP ret;
   STRI__PROTECT(ret = Rf_allocVector(REALSXP, vectorize_length));
   double* ret_val = REAL(ret);
   for (R_len_t i=0; i<vectorize_length; ++i) {
      if (time_cont.isNA(i) || value_cont.isNA(i)) {
         ret_val[i] = NA_REAL;
         continue;
      }
      status = U_ZERO_ERROR;
      cal->setTime((UDate)(time_cont.get(i)*1000.0), status);
      STRI__CHECKICUSTATUS_THROW(status, {/* do nothing special on err */})

      status = U_ZERO_ERROR;
      cal->add(units_field, value_cont.get(i), status);
      STRI__CHECKICUSTATUS_THROW(status, {/* do nothing special on err */})

      status = U_ZERO_ERROR;
      ret_val[i] = ((double)cal->getTime(status))/1000.0;
      STRI__CHECKICUSTATUS_THROW(status, {/* do nothing special on err */})
   }

   if (!isNull(tz)) Rf_setAttrib(ret, Rf_ScalarString(Rf_mkChar("tzone")), tz);
   stri__set_class_POSIXct(ret);
   if (tz_val) { delete tz_val; tz_val = NULL; }
   if (cal) { delete cal; cal = NULL; }
   STRI__UNPROTECT_ALL
   return ret;
   STRI__ERROR_HANDLER_END({
      if (tz_val) { delete tz_val; tz_val = NULL; }
      if (cal) { delete cal; cal = NULL; }
   })
}
Пример #5
0
/**
 * Parse date-time objects
 *
 * @param str
 * @param format
 * @param tz
 * @param lenient
 * @param locale
 *
 * @return character vector
 *
 * @version 0.5-1 (Marek Gagolewski, 2015-01-08)
 * @version 0.5-1 (Marek Gagolewski, 2015-01-11) lenient arg added
 * @version 0.5-1 (Marek Gagolewski, 2015-02-22) use tz
 * @version 0.5-1 (Marek Gagolewski, 2015-03-01) set tzone attrib on retval
 */
SEXP stri_datetime_parse(SEXP str, SEXP format, SEXP lenient, SEXP tz, SEXP locale) {
   PROTECT(str = stri_prepare_arg_string(str, "str"));
   const char* locale_val = stri__prepare_arg_locale(locale, "locale", true);
   const char* format_val = stri__prepare_arg_string_1_notNA(format, "format");
   bool lenient_val = stri__prepare_arg_logical_1_notNA(lenient, "lenient");
   if (!isNull(tz)) PROTECT(tz = stri_prepare_arg_string_1(tz, "tz"));
   else             PROTECT(tz); /* needed to set tzone attrib */

   // "format" may be one of:
   const char* format_opts[] = {
      "date_full", "date_long", "date_medium", "date_short",
      "date_relative_full", "date_relative_long", "date_relative_medium", "date_relative_short",
      "time_full", "time_long", "time_medium", "time_short",
      "time_relative_full", "time_relative_long", "time_relative_medium", "time_relative_short",
      "datetime_full", "datetime_long", "datetime_medium", "datetime_short",
      "datetime_relative_full", "datetime_relative_long", "datetime_relative_medium", "datetime_relative_short",
      NULL};
   int format_cur = stri__match_arg(format_val, format_opts);

   TimeZone* tz_val = stri__prepare_arg_timezone(tz, "tz", true/*allowdefault*/);
   Calendar* cal = NULL;
   DateFormat* fmt = NULL;
   STRI__ERROR_HANDLER_BEGIN(2)
   R_len_t vectorize_length = LENGTH(str);
   StriContainerUTF16 str_cont(str, vectorize_length);
   UnicodeString format_str(format_val);

   UErrorCode status = U_ZERO_ERROR;
   if (format_cur >= 0) {
      DateFormat::EStyle style = DateFormat::kNone;
      switch (format_cur % 8) {
         case 0:  style = DateFormat::kFull; break;
         case 1:  style = DateFormat::kLong; break;
         case 2:  style = DateFormat::kMedium; break;
         case 3:  style = DateFormat::kShort; break;
         case 4:  style = DateFormat::kFullRelative; break;
         case 5:  style = DateFormat::kLongRelative; break;
         case 6:  style = DateFormat::kMediumRelative; break;
         case 7:  style = DateFormat::kShortRelative; break;
         default: style = DateFormat::kNone; break;
      }

      /* ICU 54.1: Relative time styles are not currently supported.  */
      switch (format_cur / 8) {
         case 0:
            fmt = DateFormat::createDateInstance(style, Locale::createFromName(locale_val));
            break;

         case 1:
            fmt = DateFormat::createTimeInstance((DateFormat::EStyle)(style & ~DateFormat::kRelative),
               Locale::createFromName(locale_val));
            break;

         case 2:
            fmt = DateFormat::createDateTimeInstance(style,
               (DateFormat::EStyle)(style & ~DateFormat::kRelative),
               Locale::createFromName(locale_val));
            break;

         default:
            fmt = NULL;
            break;

      }
   }
   else
      fmt = new SimpleDateFormat(format_str, Locale::createFromName(locale_val), status);
   STRI__CHECKICUSTATUS_THROW(status, {/* do nothing special on err */})

   status = U_ZERO_ERROR;
   cal = Calendar::createInstance(locale_val, status);
   STRI__CHECKICUSTATUS_THROW(status, {/* do nothing special on err */})

   cal->adoptTimeZone(tz_val);
   tz_val = NULL; /* The Calendar takes ownership of the TimeZone. */

   cal->setLenient(lenient_val);

   SEXP ret;
   STRI__PROTECT(ret = Rf_allocVector(REALSXP, vectorize_length));
   for (R_len_t i=0; i<vectorize_length; ++i) {
      if (str_cont.isNA(i)) {
         REAL(ret)[i] = NA_REAL;
         continue;
      }

      status = U_ZERO_ERROR;
      ParsePosition pos;
      fmt->parse(str_cont.get(i), *cal, pos);

      if (pos.getErrorIndex() >= 0)
         REAL(ret)[i] = NA_REAL;
      else {
         status = U_ZERO_ERROR;
         REAL(ret)[i] = ((double)cal->getTime(status))/1000.0;
         if (U_FAILURE(status)) REAL(ret)[i] = NA_REAL;
      }
   }


   if (!isNull(tz)) Rf_setAttrib(ret, Rf_ScalarString(Rf_mkChar("tzone")), tz);
   stri__set_class_POSIXct(ret);
   if (tz_val) { delete tz_val; tz_val = NULL; }
   if (fmt) { delete fmt; fmt = NULL; }
   if (cal) { delete cal; cal = NULL; }
   STRI__UNPROTECT_ALL
   return ret;
   STRI__ERROR_HANDLER_END({
      if (tz_val) { delete tz_val; tz_val = NULL; }
      if (fmt) { delete fmt; fmt = NULL; }
      if (cal) { delete cal; cal = NULL; }
   })
}