]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/udat.cpp
ICU-64260.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / udat.cpp
index e1e62bebf9dac0744c1c7e79416c38f6f90319fa..28c22c2d457aed29bd0737722b7ee7bf934923ec 100644 (file)
@@ -1,6 +1,8 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /*
 *******************************************************************************
 /*
 *******************************************************************************
-*   Copyright (C) 1996-2001, International Business Machines
+*   Copyright (C) 1996-2015, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 *******************************************************************************
 */
 *   Corporation and others.  All Rights Reserved.
 *******************************************************************************
 */
 #include "unicode/numfmt.h"
 #include "unicode/dtfmtsym.h"
 #include "unicode/ustring.h"
 #include "unicode/numfmt.h"
 #include "unicode/dtfmtsym.h"
 #include "unicode/ustring.h"
+#include "unicode/udisplaycontext.h"
+#include "unicode/ufieldpositer.h"
+#include "unicode/ucasemap.h"
 #include "cpputils.h"
 #include "cpputils.h"
+#include "reldtfmt.h"
+#include "umutex.h"
 
 U_NAMESPACE_USE
 
 
 U_NAMESPACE_USE
 
+/**
+ * Verify that fmt is a SimpleDateFormat. Invalid error if not.
+ * @param fmt the UDateFormat, definitely a DateFormat, maybe something else
+ * @param status error code, will be set to failure if there is a familure or the fmt is NULL.
+ */
+static void verifyIsSimpleDateFormat(const UDateFormat* fmt, UErrorCode *status) {
+   if(U_SUCCESS(*status) &&
+       dynamic_cast<const SimpleDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))==NULL) {
+       *status = U_ILLEGAL_ARGUMENT_ERROR;
+   }
+}
+
+// This mirrors the correspondence between the
+// SimpleDateFormat::fgPatternIndexToDateFormatField and
+// SimpleDateFormat::fgPatternIndexToCalendarField arrays.
+static UCalendarDateFields gDateFieldMapping[] = {
+    UCAL_ERA,                  // UDAT_ERA_FIELD = 0
+    UCAL_YEAR,                 // UDAT_YEAR_FIELD = 1
+    UCAL_MONTH,                // UDAT_MONTH_FIELD = 2
+    UCAL_DATE,                 // UDAT_DATE_FIELD = 3
+    UCAL_HOUR_OF_DAY,          // UDAT_HOUR_OF_DAY1_FIELD = 4
+    UCAL_HOUR_OF_DAY,          // UDAT_HOUR_OF_DAY0_FIELD = 5
+    UCAL_MINUTE,               // UDAT_MINUTE_FIELD = 6
+    UCAL_SECOND,               // UDAT_SECOND_FIELD = 7
+    UCAL_MILLISECOND,          // UDAT_FRACTIONAL_SECOND_FIELD = 8
+    UCAL_DAY_OF_WEEK,          // UDAT_DAY_OF_WEEK_FIELD = 9
+    UCAL_DAY_OF_YEAR,          // UDAT_DAY_OF_YEAR_FIELD = 10
+    UCAL_DAY_OF_WEEK_IN_MONTH, // UDAT_DAY_OF_WEEK_IN_MONTH_FIELD = 11
+    UCAL_WEEK_OF_YEAR,         // UDAT_WEEK_OF_YEAR_FIELD = 12
+    UCAL_WEEK_OF_MONTH,        // UDAT_WEEK_OF_MONTH_FIELD = 13
+    UCAL_AM_PM,                // UDAT_AM_PM_FIELD = 14
+    UCAL_HOUR,                 // UDAT_HOUR1_FIELD = 15
+    UCAL_HOUR,                 // UDAT_HOUR0_FIELD = 16
+    UCAL_ZONE_OFFSET,          // UDAT_TIMEZONE_FIELD = 17
+    UCAL_YEAR_WOY,             // UDAT_YEAR_WOY_FIELD = 18
+    UCAL_DOW_LOCAL,            // UDAT_DOW_LOCAL_FIELD = 19
+    UCAL_EXTENDED_YEAR,        // UDAT_EXTENDED_YEAR_FIELD = 20
+    UCAL_JULIAN_DAY,           // UDAT_JULIAN_DAY_FIELD = 21
+    UCAL_MILLISECONDS_IN_DAY,  // UDAT_MILLISECONDS_IN_DAY_FIELD = 22
+    UCAL_ZONE_OFFSET,          // UDAT_TIMEZONE_RFC_FIELD = 23 (also UCAL_DST_OFFSET)
+    UCAL_ZONE_OFFSET,          // UDAT_TIMEZONE_GENERIC_FIELD = 24 (also UCAL_DST_OFFSET)
+    UCAL_DOW_LOCAL,            // UDAT_STANDALONE_DAY_FIELD = 25
+    UCAL_MONTH,                // UDAT_STANDALONE_MONTH_FIELD = 26
+    UCAL_MONTH,                // UDAT_QUARTER_FIELD = 27
+    UCAL_MONTH,                // UDAT_STANDALONE_QUARTER_FIELD = 28
+    UCAL_ZONE_OFFSET,          // UDAT_TIMEZONE_SPECIAL_FIELD = 29 (also UCAL_DST_OFFSET)
+    UCAL_YEAR,                 // UDAT_YEAR_NAME_FIELD = 30
+    UCAL_ZONE_OFFSET,          // UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD = 31 (also UCAL_DST_OFFSET)
+    UCAL_ZONE_OFFSET,          // UDAT_TIMEZONE_ISO_FIELD = 32 (also UCAL_DST_OFFSET)
+    UCAL_ZONE_OFFSET,          // UDAT_TIMEZONE_ISO_LOCAL_FIELD = 33 (also UCAL_DST_OFFSET)
+    UCAL_EXTENDED_YEAR,        // UDAT_RELATED_YEAR_FIELD = 34 (not an exact match)
+    UCAL_FIELD_COUNT,          // UDAT_FIELD_COUNT = 35
+    // UCAL_IS_LEAP_MONTH is not the target of a mapping
+};
+
+U_CAPI UCalendarDateFields U_EXPORT2
+udat_toCalendarDateField(UDateFormatField field) {
+  return gDateFieldMapping[field];
+}
+
+/* For now- one opener. */
+static UDateFormatOpener gOpener = NULL;
+
+U_INTERNAL void U_EXPORT2
+udat_registerOpener(UDateFormatOpener opener, UErrorCode *status)
+{
+  if(U_FAILURE(*status)) return;
+  umtx_lock(NULL);
+  if(gOpener==NULL) {
+    gOpener = opener;
+  } else {
+    *status = U_ILLEGAL_ARGUMENT_ERROR;
+  }
+  umtx_unlock(NULL);
+}
+
+U_INTERNAL UDateFormatOpener U_EXPORT2
+udat_unregisterOpener(UDateFormatOpener opener, UErrorCode *status)
+{
+  if(U_FAILURE(*status)) return NULL;
+  UDateFormatOpener oldOpener = NULL;
+  umtx_lock(NULL);
+  if(gOpener==NULL || gOpener!=opener) {
+    *status = U_ILLEGAL_ARGUMENT_ERROR;
+  } else {
+    oldOpener=gOpener;
+    gOpener=NULL;
+  }
+  umtx_unlock(NULL);
+  return oldOpener;
+}
+
+
+
 U_CAPI UDateFormat* U_EXPORT2
 udat_open(UDateFormatStyle  timeStyle,
           UDateFormatStyle  dateStyle,
 U_CAPI UDateFormat* U_EXPORT2
 udat_open(UDateFormatStyle  timeStyle,
           UDateFormatStyle  dateStyle,
@@ -35,80 +136,77 @@ udat_open(UDateFormatStyle  timeStyle,
           int32_t           patternLength,
           UErrorCode        *status)
 {
           int32_t           patternLength,
           UErrorCode        *status)
 {
+    DateFormat *fmt;
+    if(U_FAILURE(*status)) {
+        return 0;
+    }
+    if(gOpener!=NULL) { // if it's registered
+      fmt = (DateFormat*) (*gOpener)(timeStyle,dateStyle,locale,tzID,tzIDLength,pattern,patternLength,status);
+      if(fmt!=NULL) {
+        return (UDateFormat*)fmt;
+      } // else fall through.
+    }
+    if(timeStyle != UDAT_PATTERN) {
+        if(locale == 0) {
+            fmt = DateFormat::createDateTimeInstance((DateFormat::EStyle)dateStyle,
+                (DateFormat::EStyle)timeStyle);
+        }
+        else {
+            fmt = DateFormat::createDateTimeInstance((DateFormat::EStyle)dateStyle,
+                (DateFormat::EStyle)timeStyle,
+                Locale(locale));
+        }
+    }
+    else {
+        UnicodeString pat((UBool)(patternLength == -1), pattern, patternLength);
 
 
-  if(U_FAILURE(*status)) 
-  {
-      return 0;
-  }
-  if(timeStyle != UDAT_IGNORE)
-  {
-      DateFormat *fmt;
-      if(locale == 0)
-        fmt = DateFormat::createDateTimeInstance((DateFormat::EStyle)dateStyle,
-                             (DateFormat::EStyle)timeStyle);
-      else
-        fmt = DateFormat::createDateTimeInstance((DateFormat::EStyle)dateStyle,
-                             (DateFormat::EStyle)timeStyle,
-                                                 Locale(locale));
-  
-      if(fmt == 0) {
+        if(locale == 0) {
+            fmt = new SimpleDateFormat(pat, *status);
+        }
+        else {
+            fmt = new SimpleDateFormat(pat, Locale(locale), *status);
+        }
+    }
+
+    if(fmt == 0) {
         *status = U_MEMORY_ALLOCATION_ERROR;
         return 0;
         *status = U_MEMORY_ALLOCATION_ERROR;
         return 0;
-      }
+    }
 
 
-      if(tzID != 0) {
+    if(tzID != 0) {
         TimeZone *zone = TimeZone::createTimeZone(UnicodeString((UBool)(tzIDLength == -1), tzID, tzIDLength));
         if(zone == 0) {
         TimeZone *zone = TimeZone::createTimeZone(UnicodeString((UBool)(tzIDLength == -1), tzID, tzIDLength));
         if(zone == 0) {
-          *status = U_MEMORY_ALLOCATION_ERROR;
-          delete fmt;
-          return 0;
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            delete fmt;
+            return 0;
         }
         fmt->adoptTimeZone(zone);
         }
         fmt->adoptTimeZone(zone);
-      }
-  
-      return (UDateFormat*)fmt;
-  }
-  else
-  {
-      const UnicodeString pat = UnicodeString((UBool)(patternLength == -1), pattern, patternLength);
-      UDateFormat *retVal = 0;
-
-      if(locale == 0)
-        retVal = (UDateFormat*)new SimpleDateFormat(pat, *status);
-      else
-        retVal = (UDateFormat*)new SimpleDateFormat(pat, Locale(locale), *status);
+    }
 
 
-      if(retVal == 0) {
-        *status = U_MEMORY_ALLOCATION_ERROR;
-        return 0;
-      }
-      return retVal;
-  }
+    return (UDateFormat*)fmt;
 }
 
 
 U_CAPI void U_EXPORT2
 udat_close(UDateFormat* format)
 {
 }
 
 
 U_CAPI void U_EXPORT2
 udat_close(UDateFormat* format)
 {
-
-  delete (DateFormat*)format;
+    delete (DateFormat*)format;
 }
 
 U_CAPI UDateFormat* U_EXPORT2
 udat_clone(const UDateFormat *fmt,
        UErrorCode *status)
 {
 }
 
 U_CAPI UDateFormat* U_EXPORT2
 udat_clone(const UDateFormat *fmt,
        UErrorCode *status)
 {
+    if(U_FAILURE(*status)) return 0;
 
 
-  if(U_FAILURE(*status)) return 0;
+    Format *res = ((DateFormat*)fmt)->clone();
 
 
-  Format *res = ((SimpleDateFormat*)fmt)->clone();
-  
-  if(res == 0) {
-    *status = U_MEMORY_ALLOCATION_ERROR;
-    return 0;
-  }
+    if(res == 0) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return 0;
+    }
 
 
-  return (UDateFormat*) res;
+    return (UDateFormat*) res;
 }
 
 U_CAPI int32_t U_EXPORT2
 }
 
 U_CAPI int32_t U_EXPORT2
@@ -119,29 +217,128 @@ udat_format(    const    UDateFormat*    format,
         UFieldPosition* position,
         UErrorCode*     status)
 {
         UFieldPosition* position,
         UErrorCode*     status)
 {
+    if(U_FAILURE(*status)) {
+        return -1;
+    }
+    if (result == NULL ? resultLength != 0 : resultLength < 0) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return -1;
+    }
 
 
-  if(U_FAILURE(*status)) return -1;
+    UnicodeString res;
+    if (result != NULL) {
+        // NULL destination for pure preflighting: empty dummy string
+        // otherwise, alias the destination buffer
+        res.setTo(result, 0, resultLength);
+    }
 
 
-  UnicodeString res;
-  if(!(result==NULL && resultLength==0)) {
-    // NULL destination for pure preflighting: empty dummy string
-    // otherwise, alias the destination buffer
-    res.setTo(result, 0, resultLength);
-  }
+    FieldPosition fp;
 
 
-  FieldPosition fp;
-  
-  if(position != 0)
-    fp.setField(position->field);
-  
-  ((DateFormat*)format)->format(dateToFormat, res, fp);
-  
-  if(position != 0) {
-    position->beginIndex = fp.getBeginIndex();
-    position->endIndex = fp.getEndIndex();
-  }
-  
-  return res.extract(result, resultLength, *status);
+    if(position != 0)
+        fp.setField(position->field);
+
+    ((DateFormat*)format)->format(dateToFormat, res, fp);
+
+    if(position != 0) {
+        position->beginIndex = fp.getBeginIndex();
+        position->endIndex = fp.getEndIndex();
+    }
+
+    return res.extract(result, resultLength, *status);
+}
+
+U_CAPI int32_t U_EXPORT2
+udat_formatCalendar(const UDateFormat*  format,
+        UCalendar*      calendar,
+        UChar*          result,
+        int32_t         resultLength,
+        UFieldPosition* position,
+        UErrorCode*     status)
+{
+    if(U_FAILURE(*status)) {
+        return -1;
+    }
+    if (result == NULL ? resultLength != 0 : resultLength < 0) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return -1;
+    }
+
+    UnicodeString res;
+    if (result != NULL) {
+        // NULL destination for pure preflighting: empty dummy string
+        // otherwise, alias the destination buffer
+        res.setTo(result, 0, resultLength);
+    }
+
+    FieldPosition fp;
+
+    if(position != 0)
+        fp.setField(position->field);
+
+    ((DateFormat*)format)->format(*(Calendar*)calendar, res, fp);
+
+    if(position != 0) {
+        position->beginIndex = fp.getBeginIndex();
+        position->endIndex = fp.getEndIndex();
+    }
+
+    return res.extract(result, resultLength, *status);
+}
+
+U_CAPI int32_t U_EXPORT2
+udat_formatForFields(    const    UDateFormat*    format,
+        UDate           dateToFormat,
+        UChar*          result,
+        int32_t         resultLength,
+        UFieldPositionIterator* fpositer,
+        UErrorCode*     status)
+{
+    if(U_FAILURE(*status)) {
+        return -1;
+    }
+    if (result == NULL ? resultLength != 0 : resultLength < 0) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return -1;
+    }
+
+    UnicodeString res;
+    if (result != NULL) {
+        // NULL destination for pure preflighting: empty dummy string
+        // otherwise, alias the destination buffer
+        res.setTo(result, 0, resultLength);
+    }
+
+    ((DateFormat*)format)->format(dateToFormat, res, (FieldPositionIterator*)fpositer, *status);
+
+    return res.extract(result, resultLength, *status);
+}
+
+U_CAPI int32_t U_EXPORT2
+udat_formatCalendarForFields(const UDateFormat*  format,
+        UCalendar*      calendar,
+        UChar*          result,
+        int32_t         resultLength,
+        UFieldPositionIterator* fpositer,
+        UErrorCode*     status)
+{
+    if(U_FAILURE(*status)) {
+        return -1;
+    }
+    if (result == NULL ? resultLength != 0 : resultLength < 0) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return -1;
+    }
+
+    UnicodeString res;
+    if (result != NULL) {
+        // NULL destination for pure preflighting: empty dummy string
+        // otherwise, alias the destination buffer
+        res.setTo(result, 0, resultLength);
+    }
+
+    ((DateFormat*)format)->format(*(Calendar*)calendar, res, (FieldPositionIterator*)fpositer, *status);
+
+    return res.extract(result, resultLength, *status);
 }
 
 U_CAPI UDate U_EXPORT2
 }
 
 U_CAPI UDate U_EXPORT2
@@ -151,28 +348,29 @@ udat_parse(    const    UDateFormat*        format,
         int32_t         *parsePos,
         UErrorCode      *status)
 {
         int32_t         *parsePos,
         UErrorCode      *status)
 {
+    if(U_FAILURE(*status)) return (UDate)0;
 
 
-  if(U_FAILURE(*status)) return (UDate)0;
+    const UnicodeString src((UBool)(textLength == -1), text, textLength);
+    ParsePosition pp;
+    int32_t stackParsePos = 0;
+    UDate res;
 
 
-  const UnicodeString src((UBool)(textLength == -1), text, textLength);
-  ParsePosition pp;
-  UDate res;
+    if(parsePos == NULL) {
+        parsePos = &stackParsePos;
+    }
 
 
-  if(parsePos != 0)
     pp.setIndex(*parsePos);
 
     pp.setIndex(*parsePos);
 
-  res = ((DateFormat*)format)->parse(src, pp);
+    res = ((DateFormat*)format)->parse(src, pp);
 
 
-  if(parsePos != 0) {
     if(pp.getErrorIndex() == -1)
     if(pp.getErrorIndex() == -1)
-      *parsePos = pp.getIndex();
+        *parsePos = pp.getIndex();
     else {
     else {
-      *parsePos = pp.getErrorIndex();
-      *status = U_PARSE_ERROR;
+        *parsePos = pp.getErrorIndex();
+        *status = U_PARSE_ERROR;
     }
     }
-  }
-  
-  return res;
+
+    return res;
 }
 
 U_CAPI void U_EXPORT2
 }
 
 U_CAPI void U_EXPORT2
@@ -183,104 +381,147 @@ udat_parseCalendar(const    UDateFormat*    format,
                             int32_t         *parsePos,
                             UErrorCode      *status)
 {
                             int32_t         *parsePos,
                             UErrorCode      *status)
 {
+    if(U_FAILURE(*status)) return;
 
 
-  if(U_FAILURE(*status)) return;
+    const UnicodeString src((UBool)(textLength == -1), text, textLength);
+    ParsePosition pp;
+    int32_t stackParsePos = 0;
 
 
-  const UnicodeString src((UBool)(textLength == -1), text, textLength);
-  ParsePosition pp;
+    if(parsePos == NULL) {
+        parsePos = &stackParsePos;
+    }
 
 
-  if(parsePos != 0)
     pp.setIndex(*parsePos);
 
     pp.setIndex(*parsePos);
 
-  ((DateFormat*)format)->parse(src, *(Calendar*)calendar, pp);
+    ((DateFormat*)format)->parse(src, *(Calendar*)calendar, pp);
 
 
-  if(parsePos != 0) {
     if(pp.getErrorIndex() == -1)
     if(pp.getErrorIndex() == -1)
-      *parsePos = pp.getIndex();
+        *parsePos = pp.getIndex();
     else {
     else {
-      *parsePos = pp.getErrorIndex();
-      *status = U_PARSE_ERROR;
+        *parsePos = pp.getErrorIndex();
+        *status = U_PARSE_ERROR;
     }
     }
-  }
-  
-  return;
 }
 
 U_CAPI UBool U_EXPORT2
 udat_isLenient(const UDateFormat* fmt)
 {
 }
 
 U_CAPI UBool U_EXPORT2
 udat_isLenient(const UDateFormat* fmt)
 {
-
-  return ((DateFormat*)fmt)->isLenient();
+    return ((DateFormat*)fmt)->isLenient();
 }
 
 U_CAPI void U_EXPORT2
 udat_setLenient(    UDateFormat*    fmt,
             UBool          isLenient)
 {
 }
 
 U_CAPI void U_EXPORT2
 udat_setLenient(    UDateFormat*    fmt,
             UBool          isLenient)
 {
+    ((DateFormat*)fmt)->setLenient(isLenient);
+}
 
 
-  ((DateFormat*)fmt)->setLenient(isLenient);
+U_DRAFT UBool U_EXPORT2
+udat_getBooleanAttribute(const UDateFormat* fmt, 
+                         UDateFormatBooleanAttribute attr, 
+                         UErrorCode* status)
+{
+    if(U_FAILURE(*status)) return FALSE;
+    return ((DateFormat*)fmt)->getBooleanAttribute(attr, *status);
+    //return FALSE;
+}
+
+U_DRAFT void U_EXPORT2
+udat_setBooleanAttribute(UDateFormat *fmt, 
+                         UDateFormatBooleanAttribute attr, 
+                         UBool newValue, 
+                         UErrorCode* status)
+{
+    if(U_FAILURE(*status)) return;
+    ((DateFormat*)fmt)->setBooleanAttribute(attr, newValue, *status);
 }
 
 U_CAPI const UCalendar* U_EXPORT2
 udat_getCalendar(const UDateFormat* fmt)
 {
 }
 
 U_CAPI const UCalendar* U_EXPORT2
 udat_getCalendar(const UDateFormat* fmt)
 {
-
-  return (const UCalendar*) ((DateFormat*)fmt)->getCalendar();
+    return (const UCalendar*) ((DateFormat*)fmt)->getCalendar();
 }
 
 U_CAPI void U_EXPORT2
 }
 
 U_CAPI void U_EXPORT2
-udat_setCalendar(            UDateFormat*    fmt,
-                    const   UCalendar*      calendarToSet)
+udat_setCalendar(UDateFormat*    fmt,
+                 const   UCalendar*      calendarToSet)
 {
 {
+    ((DateFormat*)fmt)->setCalendar(*((Calendar*)calendarToSet));
+}
 
 
-  ((DateFormat*)fmt)->setCalendar(*((Calendar*)calendarToSet));
+U_DRAFT const UNumberFormat* U_EXPORT2 
+udat_getNumberFormatForField(const UDateFormat* fmt, UChar field)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    verifyIsSimpleDateFormat(fmt, &status);
+    if (U_FAILURE(status)) return (const UNumberFormat*) ((DateFormat*)fmt)->getNumberFormat();
+    return (const UNumberFormat*) ((SimpleDateFormat*)fmt)->getNumberFormatForField(field);
 }
 
 U_CAPI const UNumberFormat* U_EXPORT2
 udat_getNumberFormat(const UDateFormat* fmt)
 {
 }
 
 U_CAPI const UNumberFormat* U_EXPORT2
 udat_getNumberFormat(const UDateFormat* fmt)
 {
+    return (const UNumberFormat*) ((DateFormat*)fmt)->getNumberFormat();
+}
 
 
-  return (const UNumberFormat*) ((DateFormat*)fmt)->getNumberFormat();
+U_DRAFT void U_EXPORT2 
+udat_adoptNumberFormatForFields(           UDateFormat*    fmt,
+                                    const  UChar*          fields,
+                                           UNumberFormat*  numberFormatToSet,
+                                           UErrorCode*     status)
+{
+    verifyIsSimpleDateFormat(fmt, status);
+    if (U_FAILURE(*status)) return;
+    
+    if (fields!=NULL) {
+        UnicodeString overrideFields(fields);
+        ((SimpleDateFormat*)fmt)->adoptNumberFormat(overrideFields, (NumberFormat*)numberFormatToSet, *status);
+    }
 }
 
 U_CAPI void U_EXPORT2
 }
 
 U_CAPI void U_EXPORT2
-udat_setNumberFormat(            UDateFormat*    fmt,
-                    const   UNumberFormat*  numberFormatToSet)
+udat_setNumberFormat(UDateFormat*    fmt,
+                     const   UNumberFormat*  numberFormatToSet)
 {
 {
+    ((DateFormat*)fmt)->setNumberFormat(*((NumberFormat*)numberFormatToSet));
+}
 
 
-  ((DateFormat*)fmt)->setNumberFormat(*((NumberFormat*)numberFormatToSet));
+U_DRAFT void U_EXPORT2
+udat_adoptNumberFormat(      UDateFormat*    fmt,
+                             UNumberFormat*  numberFormatToAdopt)
+{
+    ((DateFormat*)fmt)->adoptNumberFormat((NumberFormat*)numberFormatToAdopt);
 }
 
 U_CAPI const char* U_EXPORT2
 udat_getAvailable(int32_t index)
 {
 }
 
 U_CAPI const char* U_EXPORT2
 udat_getAvailable(int32_t index)
 {
-  return uloc_getAvailable(index);
+    return uloc_getAvailable(index);
 }
 
 U_CAPI int32_t U_EXPORT2
 udat_countAvailable()
 {
 }
 
 U_CAPI int32_t U_EXPORT2
 udat_countAvailable()
 {
-
-  return uloc_countAvailable();
+    return uloc_countAvailable();
 }
 
 U_CAPI UDate U_EXPORT2
 udat_get2DigitYearStart(    const   UDateFormat     *fmt,
 }
 
 U_CAPI UDate U_EXPORT2
 udat_get2DigitYearStart(    const   UDateFormat     *fmt,
-                UErrorCode      *status)
+                        UErrorCode      *status)
 {
 {
-
-  if(U_FAILURE(*status)) return (UDate)0;
-  return ((SimpleDateFormat*)fmt)->get2DigitYearStart(*status);
+    verifyIsSimpleDateFormat(fmt, status);
+    if(U_FAILURE(*status)) return (UDate)0;
+    return ((SimpleDateFormat*)fmt)->get2DigitYearStart(*status);
 }
 
 U_CAPI void U_EXPORT2
 udat_set2DigitYearStart(    UDateFormat     *fmt,
 }
 
 U_CAPI void U_EXPORT2
 udat_set2DigitYearStart(    UDateFormat     *fmt,
-                UDate           d,
-                UErrorCode      *status)
+                        UDate           d,
+                        UErrorCode      *status)
 {
 {
-
-  if(U_FAILURE(*status)) return;
-  ((SimpleDateFormat*)fmt)->set2DigitYearStart(d, *status);
+    verifyIsSimpleDateFormat(fmt, status);
+    if(U_FAILURE(*status)) return;
+    ((SimpleDateFormat*)fmt)->set2DigitYearStart(d, *status);
 }
 
 U_CAPI int32_t U_EXPORT2
 }
 
 U_CAPI int32_t U_EXPORT2
@@ -290,156 +531,435 @@ udat_toPattern(    const   UDateFormat     *fmt,
         int32_t         resultLength,
         UErrorCode      *status)
 {
         int32_t         resultLength,
         UErrorCode      *status)
 {
+    if(U_FAILURE(*status)) {
+        return -1;
+    }
+    if (result == NULL ? resultLength != 0 : resultLength < 0) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return -1;
+    }
 
 
-  if(U_FAILURE(*status)) return -1;
-
-  UnicodeString res;
-  if(!(result==NULL && resultLength==0)) {
-    // NULL destination for pure preflighting: empty dummy string
-    // otherwise, alias the destination buffer
-    res.setTo(result, 0, resultLength);
-  }
+    UnicodeString res;
+    if (result != NULL) {
+        // NULL destination for pure preflighting: empty dummy string
+        // otherwise, alias the destination buffer
+        res.setTo(result, 0, resultLength);
+    }
 
 
-  if(localized)
-    ((SimpleDateFormat*)fmt)->toLocalizedPattern(res, *status);
-  else
-    ((SimpleDateFormat*)fmt)->toPattern(res);
+    const DateFormat *df=reinterpret_cast<const DateFormat *>(fmt);
+    const SimpleDateFormat *sdtfmt=dynamic_cast<const SimpleDateFormat *>(df);
+    const RelativeDateFormat *reldtfmt;
+    if (sdtfmt!=NULL) {
+        if(localized)
+            sdtfmt->toLocalizedPattern(res, *status);
+        else
+            sdtfmt->toPattern(res);
+    } else if (!localized && (reldtfmt=dynamic_cast<const RelativeDateFormat *>(df))!=NULL) {
+        reldtfmt->toPattern(res, *status);
+    } else {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return -1;
+    }
 
 
-  return res.extract(result, resultLength, *status);
+    return res.extract(result, resultLength, *status);
 }
 
 }
 
-// TBD: should this take an UErrorCode?
+// TODO: should this take an UErrorCode?
+// A: Yes. Of course.
 U_CAPI void U_EXPORT2
 U_CAPI void U_EXPORT2
-udat_applyPattern(            UDateFormat     *format,
+udat_applyPattern(  UDateFormat     *format,
                     UBool          localized,
                     const   UChar           *pattern,
                     int32_t         patternLength)
 {
                     UBool          localized,
                     const   UChar           *pattern,
                     int32_t         patternLength)
 {
+    const UnicodeString pat((UBool)(patternLength == -1), pattern, patternLength);
+    UErrorCode status = U_ZERO_ERROR;
 
 
-  const UnicodeString pat((UBool)(patternLength == -1), pattern, patternLength);
-  UErrorCode status = U_ZERO_ERROR;
+    verifyIsSimpleDateFormat(format, &status);
+    if(U_FAILURE(status)) {
+        return;
+    }
+    
+    if(localized)
+        ((SimpleDateFormat*)format)->applyLocalizedPattern(pat, status);
+    else
+        ((SimpleDateFormat*)format)->applyPattern(pat);
+}
 
 
-  if(localized)
-    ((SimpleDateFormat*)format)->applyLocalizedPattern(pat, status);
-  else
-    ((SimpleDateFormat*)format)->applyPattern(pat);
+// Apple addition
+static DateFormatSymbols::ECapitalizationContextUsageType capUsageFromSymbolType(UDateFormatSymbolType type)
+{
+    DateFormatSymbols::ECapitalizationContextUsageType capContextUsageType = DateFormatSymbols::kCapContextUsageOther;
+    switch (type) {
+        case UDAT_ERA_NAMES:
+            capContextUsageType = DateFormatSymbols::kCapContextUsageEraWide;
+            break;
+        case UDAT_ERAS:
+            capContextUsageType = DateFormatSymbols::kCapContextUsageEraAbbrev;
+            break;
+        case UDAT_MONTHS:
+        case UDAT_SHORT_MONTHS:
+            capContextUsageType = DateFormatSymbols::kCapContextUsageMonthFormat;
+            break;
+        case UDAT_STANDALONE_MONTHS:
+        case UDAT_STANDALONE_SHORT_MONTHS:
+            capContextUsageType = DateFormatSymbols::kCapContextUsageMonthStandalone;
+            break;
+        case UDAT_NARROW_MONTHS:
+        case UDAT_STANDALONE_NARROW_MONTHS:
+            capContextUsageType = DateFormatSymbols::kCapContextUsageMonthNarrow;
+            break;
+        case UDAT_WEEKDAYS:
+        case UDAT_SHORT_WEEKDAYS:
+        case UDAT_SHORTER_WEEKDAYS:
+            capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat;
+            break;
+        case UDAT_STANDALONE_WEEKDAYS:
+        case UDAT_STANDALONE_SHORT_WEEKDAYS:
+        case UDAT_STANDALONE_SHORTER_WEEKDAYS:
+            capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone;
+            break;
+        case UDAT_STANDALONE_NARROW_WEEKDAYS:
+        case UDAT_NARROW_WEEKDAYS:
+            capContextUsageType = DateFormatSymbols::kCapContextUsageDayNarrow;
+            break;
+        default:
+            break;
+    }
+    return capContextUsageType;
 }
 
 }
 
+
+
 U_CAPI int32_t U_EXPORT2
 U_CAPI int32_t U_EXPORT2
-udat_getSymbols(const   UDateFormat             *fmt,
-        UDateFormatSymbolType   type,
-        int32_t                 index,
-        UChar                   *result,
-        int32_t                 resultLength,
-        UErrorCode              *status)
+udat_getSymbols(const   UDateFormat     *fmt,
+                UDateFormatSymbolType   type,
+                int32_t                 index,
+                UChar                   *result,
+                int32_t                 resultLength,
+                UErrorCode              *status)
 {
 {
+    const DateFormatSymbols *syms;
+    const SimpleDateFormat* sdtfmt;
+    const RelativeDateFormat* rdtfmt;
+    BreakIterator* capitalizationBrkIter;
+    if ((sdtfmt = dynamic_cast<const SimpleDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))) != NULL) {
+        syms = sdtfmt->getDateFormatSymbols();
+        capitalizationBrkIter = sdtfmt->getCapitalizationBrkIter();
+    } else if ((rdtfmt = dynamic_cast<const RelativeDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))) != NULL) {
+        syms = rdtfmt->getDateFormatSymbols();
+        capitalizationBrkIter = rdtfmt->getCapitalizationBrkIter();
+    } else {
+        return -1;
+    }
+    int32_t count = 0;
+    const UnicodeString *res = NULL;
+
+    switch(type) {
+    case UDAT_ERAS:
+        res = syms->getEras(count);
+        break;
+
+    case UDAT_ERA_NAMES:
+        res = syms->getEraNames(count);
+        break;
+
+    case UDAT_MONTHS:
+        res = syms->getMonths(count);
+        break;
+
+    case UDAT_SHORT_MONTHS:
+        res = syms->getShortMonths(count);
+        break;
+
+    case UDAT_WEEKDAYS:
+        res = syms->getWeekdays(count);
+        break;
+
+    case UDAT_SHORT_WEEKDAYS:
+        res = syms->getShortWeekdays(count);
+        break;
+
+    case UDAT_AM_PMS:
+        res = syms->getAmPmStrings(count);
+        break;
+
+    case UDAT_LOCALIZED_CHARS:
+        {
+            UnicodeString res1;
+            if(!(result==NULL && resultLength==0)) {
+                // NULL destination for pure preflighting: empty dummy string
+                // otherwise, alias the destination buffer
+                res1.setTo(result, 0, resultLength);
+            }
+            syms->getLocalPatternChars(res1);
+            return res1.extract(result, resultLength, *status);
+        }
 
 
-  if(U_FAILURE(*status)) return -1;
+    case UDAT_NARROW_MONTHS:
+        res = syms->getMonths(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
+        break;
 
 
-  const DateFormatSymbols *syms = 
-    ((SimpleDateFormat*)fmt)->getDateFormatSymbols();
-  int32_t count;
-  const UnicodeString *res;
+    case UDAT_SHORTER_WEEKDAYS:
+        res = syms->getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::SHORT);
+        break;
 
 
-  switch(type) {
-  case UDAT_ERAS:
-    res = syms->getEras(count);
-    if(index < count) {
-      return res[index].extract(result, resultLength, *status);
-    }
-    break;
+    case UDAT_NARROW_WEEKDAYS:
+        res = syms->getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
+        break;
 
 
-  case UDAT_MONTHS:
-    res = syms->getMonths(count);
-    if(index < count) {
-      return res[index].extract(result, resultLength, *status);
-    }
-    break;
+    case UDAT_STANDALONE_MONTHS:
+        res = syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+        break;
 
 
-  case UDAT_SHORT_MONTHS:
-    res = syms->getShortMonths(count);
-    if(index < count) {
-      return res[index].extract(result, resultLength, *status);
-    }
-    break;
+    case UDAT_STANDALONE_SHORT_MONTHS:
+        res = syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+        break;
 
 
-  case UDAT_WEEKDAYS:
-    res = syms->getWeekdays(count);
-    if(index < count) {
-      return res[index].extract(result, resultLength, *status);
-    }
-    break;
+    case UDAT_STANDALONE_NARROW_MONTHS:
+        res = syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
+        break;
 
 
-  case UDAT_SHORT_WEEKDAYS:
-    res = syms->getShortWeekdays(count);
-    if(index < count) {
-      return res[index].extract(result, resultLength, *status);
-    }
-    break;
+    case UDAT_STANDALONE_WEEKDAYS:
+        res = syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+        break;
+
+    case UDAT_STANDALONE_SHORT_WEEKDAYS:
+        res = syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+        break;
+
+    case UDAT_STANDALONE_SHORTER_WEEKDAYS:
+        res = syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::SHORT);
+        break;
+
+    case UDAT_STANDALONE_NARROW_WEEKDAYS:
+        res = syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
+        break;
+
+    case UDAT_QUARTERS:
+        res = syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
+        break;
+
+    case UDAT_SHORT_QUARTERS:
+        res = syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
+        break;
+
+    case UDAT_STANDALONE_QUARTERS:
+        res = syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+        break;
+
+    case UDAT_STANDALONE_SHORT_QUARTERS:
+        res = syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+        break;
+
+    case UDAT_CYCLIC_YEARS_WIDE:
+        res = syms->getYearNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
+        break;
+
+    case UDAT_CYCLIC_YEARS_ABBREVIATED:
+        res = syms->getYearNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
+        break;
+
+    case UDAT_CYCLIC_YEARS_NARROW:
+        res = syms->getYearNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
+        break;
+
+    case UDAT_ZODIAC_NAMES_WIDE:
+        res = syms->getZodiacNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
+        break;
+
+    case UDAT_ZODIAC_NAMES_ABBREVIATED:
+        res = syms->getZodiacNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
+        break;
+
+    case UDAT_ZODIAC_NAMES_NARROW:
+        res = syms->getZodiacNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
+        break;
+
+    case UADAT_CYCLIC_ZODIAC_NAMES:
+        res = syms->getZodiacNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
+        index = (index > 0)? (index - 1) % 12: 0;
+        break;
 
 
-  case UDAT_AM_PMS:
-    res = syms->getAmPmStrings(count);
-    if(index < count) {
-      return res[index].extract(result, resultLength, *status);
     }
     }
-    break;
 
 
-  case UDAT_LOCALIZED_CHARS:
-    {
-      UnicodeString res1;
-      if(!(result==NULL && resultLength==0)) {
-        // NULL destination for pure preflighting: empty dummy string
-        // otherwise, alias the destination buffer
-        res1.setTo(result, 0, resultLength);
-      }
-      syms->getLocalPatternChars(res1);
-      return res1.extract(result, resultLength, *status);
+    if(index < count) {
+#if !UCONFIG_NO_BREAK_ITERATION
+        // Apple addition for <rdar://problem/27335144>
+        if (u_islower(res[index].char32At(0)) && capitalizationBrkIter != NULL) {
+            UDisplayContext capitalizationContext = ((const DateFormat*)fmt)->getContext(UDISPCTX_TYPE_CAPITALIZATION, *status);
+            UBool titlecase = FALSE;
+            switch (capitalizationContext) {
+                case UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE:
+                    titlecase = TRUE;
+                    break;
+                case UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU:
+                    titlecase = syms->capitalizeForUsage(capUsageFromSymbolType(type), 0);
+                    break;
+                case UDISPCTX_CAPITALIZATION_FOR_STANDALONE:
+                    titlecase = syms->capitalizeForUsage(capUsageFromSymbolType(type), 1);
+                    break;
+                default:
+                    // titlecase = FALSE;
+                    break;
+            }
+            if (titlecase) {
+                UnicodeString symbolToModify(res[index]);
+                BreakIterator* capBrkIterToUse = capitalizationBrkIter->clone();
+                if (capBrkIterToUse != NULL) {
+                    Locale locale = capBrkIterToUse->getLocale(ULOC_ACTUAL_LOCALE, *status);
+                    if (U_SUCCESS(*status)) {
+                        symbolToModify.toTitle(capBrkIterToUse, locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
+                        delete capBrkIterToUse;
+                        return symbolToModify.extract(result, resultLength, *status);
+                    }
+                    delete capBrkIterToUse;
+                }
+            }
+        }
+#endif
+        return res[index].extract(result, resultLength, *status);
     }
     }
-  }
-  
-  return 0;
+    return 0;
 }
 
 }
 
+// TODO: also needs an errorCode.
 U_CAPI int32_t U_EXPORT2
 udat_countSymbols(    const    UDateFormat                *fmt,
             UDateFormatSymbolType    type)
 {
 U_CAPI int32_t U_EXPORT2
 udat_countSymbols(    const    UDateFormat                *fmt,
             UDateFormatSymbolType    type)
 {
+    const DateFormatSymbols *syms;
+    const SimpleDateFormat* sdtfmt;
+    const RelativeDateFormat* rdtfmt;
+    if ((sdtfmt = dynamic_cast<const SimpleDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))) != NULL) {
+        syms = sdtfmt->getDateFormatSymbols();
+    } else if ((rdtfmt = dynamic_cast<const RelativeDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))) != NULL) {
+        syms = rdtfmt->getDateFormatSymbols();
+    } else {
+        return 0;
+    }
+    int32_t count = 0;
 
 
-  const DateFormatSymbols *syms = 
-    ((SimpleDateFormat*)fmt)->getDateFormatSymbols();
-  int32_t count = 0;
+    switch(type) {
+    case UDAT_ERAS:
+        syms->getEras(count);
+        break;
 
 
-  switch(type) {
-  case UDAT_ERAS:
-    syms->getEras(count);
-    break;
+    case UDAT_MONTHS:
+        syms->getMonths(count);
+        break;
 
 
-  case UDAT_MONTHS:
-    syms->getMonths(count);
-    break;
+    case UDAT_SHORT_MONTHS:
+        syms->getShortMonths(count);
+        break;
 
 
-  case UDAT_SHORT_MONTHS:
-    syms->getShortMonths(count);
-    break;
+    case UDAT_WEEKDAYS:
+        syms->getWeekdays(count);
+        break;
 
 
-  case UDAT_WEEKDAYS:
-    syms->getWeekdays(count);
-    break;
+    case UDAT_SHORT_WEEKDAYS:
+        syms->getShortWeekdays(count);
+        break;
 
 
-  case UDAT_SHORT_WEEKDAYS:
-    syms->getShortWeekdays(count);
-    break;
+    case UDAT_AM_PMS:
+        syms->getAmPmStrings(count);
+        break;
 
 
-  case UDAT_AM_PMS:
-    syms->getAmPmStrings(count);
-    break;
+    case UDAT_LOCALIZED_CHARS:
+        count = 1;
+        break;
 
 
-  case UDAT_LOCALIZED_CHARS:
-    count = 1;
-    break;
-  }
-  
-  return count;
+    case UDAT_ERA_NAMES:
+        syms->getEraNames(count);
+        break;
+
+    case UDAT_NARROW_MONTHS:
+        syms->getMonths(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
+        break;
+
+    case UDAT_SHORTER_WEEKDAYS:
+        syms->getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::SHORT);
+        break;
+
+    case UDAT_NARROW_WEEKDAYS:
+        syms->getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
+        break;
+
+    case UDAT_STANDALONE_MONTHS:
+        syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+        break;
+
+    case UDAT_STANDALONE_SHORT_MONTHS:
+        syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+        break;
+
+    case UDAT_STANDALONE_NARROW_MONTHS:
+        syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
+        break;
+
+    case UDAT_STANDALONE_WEEKDAYS:
+        syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+        break;
+
+    case UDAT_STANDALONE_SHORT_WEEKDAYS:
+        syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+        break;
+
+    case UDAT_STANDALONE_SHORTER_WEEKDAYS:
+        syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::SHORT);
+        break;
+
+    case UDAT_STANDALONE_NARROW_WEEKDAYS:
+        syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
+        break;
+
+    case UDAT_QUARTERS:
+        syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
+        break;
+
+    case UDAT_SHORT_QUARTERS:
+        syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
+        break;
+
+    case UDAT_STANDALONE_QUARTERS:
+        syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+        break;
+
+    case UDAT_STANDALONE_SHORT_QUARTERS:
+        syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+        break;
+
+    case UDAT_CYCLIC_YEARS_WIDE:
+        syms->getYearNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
+        break;
+
+    case UDAT_CYCLIC_YEARS_ABBREVIATED:
+        syms->getYearNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
+        break;
+
+    case UDAT_CYCLIC_YEARS_NARROW:
+        syms->getYearNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
+        break;
+
+    case UDAT_ZODIAC_NAMES_WIDE:
+        syms->getZodiacNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
+        break;
+
+    case UDAT_ZODIAC_NAMES_ABBREVIATED:
+        syms->getZodiacNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
+        break;
+
+    case UDAT_ZODIAC_NAMES_NARROW:
+        syms->getZodiacNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
+        break;
+
+     case UADAT_CYCLIC_ZODIAC_NAMES:
+        syms->getZodiacNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
+        break;
+
+    }
+
+    return count;
 }
 
 U_NAMESPACE_BEGIN
 }
 
 U_NAMESPACE_BEGIN
@@ -470,61 +990,188 @@ U_NAMESPACE_BEGIN
  */
 class DateFormatSymbolsSingleSetter /* not : public UObject because all methods are static */ {
 public:
  */
 class DateFormatSymbolsSingleSetter /* not : public UObject because all methods are static */ {
 public:
-  static void
-  setSymbol(UnicodeString *array, int32_t count, int32_t index,
-            const UChar *value, int32_t valueLength, UErrorCode &errorCode) {
-    if(array!=NULL) {
-      if(index>=count) {
-        errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
-      } else if(value==NULL) {
-        errorCode=U_ILLEGAL_ARGUMENT_ERROR;
-      } else {
-        array[index].setTo(value, valueLength);
-      }
+    static void
+        setSymbol(UnicodeString *array, int32_t count, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        if(array!=NULL) {
+            if(index>=count) {
+                errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+            } else if(value==NULL) {
+                errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+            } else {
+                array[index].setTo(value, valueLength);
+            }
+        }
     }
     }
-  }
 
 
-  static void
-  setEra(DateFormatSymbols *syms, int32_t index,
-         const UChar *value, int32_t valueLength, UErrorCode &errorCode) {
-    setSymbol(syms->fEras, syms->fErasCount, index, value, valueLength, errorCode);
-  }
+    static void
+        setEra(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fEras, syms->fErasCount, index, value, valueLength, errorCode);
+    }
 
 
-  static void
-  setMonth(DateFormatSymbols *syms, int32_t index,
-           const UChar *value, int32_t valueLength, UErrorCode &errorCode) {
-    setSymbol(syms->fMonths, syms->fMonthsCount, index, value, valueLength, errorCode);
-  }
+    static void
+        setEraName(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fEraNames, syms->fEraNamesCount, index, value, valueLength, errorCode);
+    }
 
 
-  static void
-  setShortMonth(DateFormatSymbols *syms, int32_t index,
-                const UChar *value, int32_t valueLength, UErrorCode &errorCode) {
-    setSymbol(syms->fShortMonths, syms->fShortMonthsCount, index, value, valueLength, errorCode);
-  }
+    static void
+        setMonth(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fMonths, syms->fMonthsCount, index, value, valueLength, errorCode);
+    }
 
 
-  static void
-  setWeekday(DateFormatSymbols *syms, int32_t index,
-             const UChar *value, int32_t valueLength, UErrorCode &errorCode) {
-    setSymbol(syms->fWeekdays, syms->fWeekdaysCount, index, value, valueLength, errorCode);
-  }
+    static void
+        setShortMonth(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fShortMonths, syms->fShortMonthsCount, index, value, valueLength, errorCode);
+    }
 
 
-  static void
-  setShortWeekday(DateFormatSymbols *syms, int32_t index,
-                  const UChar *value, int32_t valueLength, UErrorCode &errorCode) {
-    setSymbol(syms->fShortWeekdays, syms->fShortWeekdaysCount, index, value, valueLength, errorCode);
-  }
+    static void
+        setNarrowMonth(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fNarrowMonths, syms->fNarrowMonthsCount, index, value, valueLength, errorCode);
+    }
 
 
-  static void
-  setAmPm(DateFormatSymbols *syms, int32_t index,
-          const UChar *value, int32_t valueLength, UErrorCode &errorCode) {
-    setSymbol(syms->fAmPms, syms->fAmPmsCount, index, value, valueLength, errorCode);
-  }
+    static void
+        setStandaloneMonth(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fStandaloneMonths, syms->fStandaloneMonthsCount, index, value, valueLength, errorCode);
+    }
 
 
-  static void
-  setLocalPatternChars(DateFormatSymbols *syms,
-                       const UChar *value, int32_t valueLength, UErrorCode &errorCode) {
-    setSymbol(&syms->fLocalPatternChars, 1, 0, value, valueLength, errorCode);
-  }
+    static void
+        setStandaloneShortMonth(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fStandaloneShortMonths, syms->fStandaloneShortMonthsCount, index, value, valueLength, errorCode);
+    }
+
+    static void
+        setStandaloneNarrowMonth(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fStandaloneNarrowMonths, syms->fStandaloneNarrowMonthsCount, index, value, valueLength, errorCode);
+    }
+
+    static void
+        setWeekday(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fWeekdays, syms->fWeekdaysCount, index, value, valueLength, errorCode);
+    }
+
+    static void
+        setShortWeekday(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fShortWeekdays, syms->fShortWeekdaysCount, index, value, valueLength, errorCode);
+    }
+
+    static void
+        setShorterWeekday(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fShorterWeekdays, syms->fShorterWeekdaysCount, index, value, valueLength, errorCode);
+    }
+
+    static void
+        setNarrowWeekday(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fNarrowWeekdays, syms->fNarrowWeekdaysCount, index, value, valueLength, errorCode);
+    }
+
+    static void
+        setStandaloneWeekday(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fStandaloneWeekdays, syms->fStandaloneWeekdaysCount, index, value, valueLength, errorCode);
+    }
+
+    static void
+        setStandaloneShortWeekday(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fStandaloneShortWeekdays, syms->fStandaloneShortWeekdaysCount, index, value, valueLength, errorCode);
+    }
+
+    static void
+        setStandaloneShorterWeekday(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fStandaloneShorterWeekdays, syms->fStandaloneShorterWeekdaysCount, index, value, valueLength, errorCode);
+    }
+
+    static void
+        setStandaloneNarrowWeekday(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fStandaloneNarrowWeekdays, syms->fStandaloneNarrowWeekdaysCount, index, value, valueLength, errorCode);
+    }
+
+    static void
+        setQuarter(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fQuarters, syms->fQuartersCount, index, value, valueLength, errorCode);
+    }
+
+    static void
+        setShortQuarter(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fShortQuarters, syms->fShortQuartersCount, index, value, valueLength, errorCode);
+    }
+
+    static void
+        setStandaloneQuarter(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fStandaloneQuarters, syms->fStandaloneQuartersCount, index, value, valueLength, errorCode);
+    }
+
+    static void
+        setStandaloneShortQuarter(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fStandaloneShortQuarters, syms->fStandaloneShortQuartersCount, index, value, valueLength, errorCode);
+    }
+
+    static void
+        setShortYearNames(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fShortYearNames, syms->fShortYearNamesCount, index, value, valueLength, errorCode);
+    }
+
+    static void
+        setShortZodiacNames(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fShortZodiacNames, syms->fShortZodiacNamesCount, index, value, valueLength, errorCode);
+    }
+
+    static void
+        setAmPm(DateFormatSymbols *syms, int32_t index,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(syms->fAmPms, syms->fAmPmsCount, index, value, valueLength, errorCode);
+    }
+
+    static void
+        setLocalPatternChars(DateFormatSymbols *syms,
+        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+    {
+        setSymbol(&syms->fLocalPatternChars, 1, 0, value, valueLength, errorCode);
+    }
 };
 
 U_NAMESPACE_END
 };
 
 U_NAMESPACE_END
@@ -537,40 +1184,225 @@ udat_setSymbols(    UDateFormat             *format,
             int32_t                 valueLength,
             UErrorCode              *status)
 {
             int32_t                 valueLength,
             UErrorCode              *status)
 {
+    verifyIsSimpleDateFormat(format, status);
+    if(U_FAILURE(*status)) return;
 
 
-  if(U_FAILURE(*status)) return;
+    DateFormatSymbols *syms = (DateFormatSymbols *)((SimpleDateFormat *)format)->getDateFormatSymbols();
 
 
-  DateFormatSymbols *syms = (DateFormatSymbols *)((SimpleDateFormat *)format)->getDateFormatSymbols();
+    switch(type) {
+    case UDAT_ERAS:
+        DateFormatSymbolsSingleSetter::setEra(syms, index, value, valueLength, *status);
+        break;
 
 
-  switch(type) {
-  case UDAT_ERAS:
-    DateFormatSymbolsSingleSetter::setEra(syms, index, value, valueLength, *status);
-    break;
+    case UDAT_ERA_NAMES:
+        DateFormatSymbolsSingleSetter::setEraName(syms, index, value, valueLength, *status);
+        break;
 
 
-  case UDAT_MONTHS:
-    DateFormatSymbolsSingleSetter::setMonth(syms, index, value, valueLength, *status);
-    break;
+    case UDAT_MONTHS:
+        DateFormatSymbolsSingleSetter::setMonth(syms, index, value, valueLength, *status);
+        break;
 
 
-  case UDAT_SHORT_MONTHS:
-    DateFormatSymbolsSingleSetter::setShortMonth(syms, index, value, valueLength, *status);
-    break;
+    case UDAT_SHORT_MONTHS:
+        DateFormatSymbolsSingleSetter::setShortMonth(syms, index, value, valueLength, *status);
+        break;
 
 
-  case UDAT_WEEKDAYS:
-    DateFormatSymbolsSingleSetter::setWeekday(syms, index, value, valueLength, *status);
-    break;
+    case UDAT_NARROW_MONTHS:
+        DateFormatSymbolsSingleSetter::setNarrowMonth(syms, index, value, valueLength, *status);
+        break;
 
 
-  case UDAT_SHORT_WEEKDAYS:
-    DateFormatSymbolsSingleSetter::setShortWeekday(syms, index, value, valueLength, *status);
-    break;
+    case UDAT_STANDALONE_MONTHS:
+        DateFormatSymbolsSingleSetter::setStandaloneMonth(syms, index, value, valueLength, *status);
+        break;
 
 
-  case UDAT_AM_PMS:
-    DateFormatSymbolsSingleSetter::setAmPm(syms, index, value, valueLength, *status);
-    break;
+    case UDAT_STANDALONE_SHORT_MONTHS:
+        DateFormatSymbolsSingleSetter::setStandaloneShortMonth(syms, index, value, valueLength, *status);
+        break;
 
 
-  case UDAT_LOCALIZED_CHARS:
-    DateFormatSymbolsSingleSetter::setLocalPatternChars(syms, value, valueLength, *status);
-    break;
-  }
+    case UDAT_STANDALONE_NARROW_MONTHS:
+        DateFormatSymbolsSingleSetter::setStandaloneNarrowMonth(syms, index, value, valueLength, *status);
+        break;
+
+    case UDAT_WEEKDAYS:
+        DateFormatSymbolsSingleSetter::setWeekday(syms, index, value, valueLength, *status);
+        break;
+
+    case UDAT_SHORT_WEEKDAYS:
+        DateFormatSymbolsSingleSetter::setShortWeekday(syms, index, value, valueLength, *status);
+        break;
+
+    case UDAT_SHORTER_WEEKDAYS:
+        DateFormatSymbolsSingleSetter::setShorterWeekday(syms, index, value, valueLength, *status);
+        break;
+
+    case UDAT_NARROW_WEEKDAYS:
+        DateFormatSymbolsSingleSetter::setNarrowWeekday(syms, index, value, valueLength, *status);
+        break;
+
+    case UDAT_STANDALONE_WEEKDAYS:
+        DateFormatSymbolsSingleSetter::setStandaloneWeekday(syms, index, value, valueLength, *status);
+        break;
+
+    case UDAT_STANDALONE_SHORT_WEEKDAYS:
+        DateFormatSymbolsSingleSetter::setStandaloneShortWeekday(syms, index, value, valueLength, *status);
+        break;
+
+    case UDAT_STANDALONE_SHORTER_WEEKDAYS:
+        DateFormatSymbolsSingleSetter::setStandaloneShorterWeekday(syms, index, value, valueLength, *status);
+        break;
+
+    case UDAT_STANDALONE_NARROW_WEEKDAYS:
+        DateFormatSymbolsSingleSetter::setStandaloneNarrowWeekday(syms, index, value, valueLength, *status);
+        break;
+
+    case UDAT_QUARTERS:
+        DateFormatSymbolsSingleSetter::setQuarter(syms, index, value, valueLength, *status);
+        break;
+
+    case UDAT_SHORT_QUARTERS:
+        DateFormatSymbolsSingleSetter::setShortQuarter(syms, index, value, valueLength, *status);
+        break;
+
+    case UDAT_STANDALONE_QUARTERS:
+        DateFormatSymbolsSingleSetter::setStandaloneQuarter(syms, index, value, valueLength, *status);
+        break;
+
+    case UDAT_STANDALONE_SHORT_QUARTERS:
+        DateFormatSymbolsSingleSetter::setStandaloneShortQuarter(syms, index, value, valueLength, *status);
+        break;
+
+    case UDAT_CYCLIC_YEARS_ABBREVIATED:
+        DateFormatSymbolsSingleSetter::setShortYearNames(syms, index, value, valueLength, *status);
+        break;
+
+    case UDAT_ZODIAC_NAMES_ABBREVIATED:
+        DateFormatSymbolsSingleSetter::setShortZodiacNames(syms, index, value, valueLength, *status);
+        break;
+
+    case UDAT_AM_PMS:
+        DateFormatSymbolsSingleSetter::setAmPm(syms, index, value, valueLength, *status);
+        break;
+
+    case UDAT_LOCALIZED_CHARS:
+        DateFormatSymbolsSingleSetter::setLocalPatternChars(syms, value, valueLength, *status);
+        break;
+
+    default:
+        *status = U_UNSUPPORTED_ERROR;
+        break;
+        
+    }
+}
+
+U_CAPI const char* U_EXPORT2
+udat_getLocaleByType(const UDateFormat *fmt,
+                     ULocDataLocaleType type,
+                     UErrorCode* status)
+{
+    if (fmt == NULL) {
+        if (U_SUCCESS(*status)) {
+            *status = U_ILLEGAL_ARGUMENT_ERROR;
+        }
+        return NULL;
+    }
+    return ((Format*)fmt)->getLocaleID(type, *status);
+}
+
+U_CAPI void U_EXPORT2
+udat_setContext(UDateFormat* fmt, UDisplayContext value, UErrorCode* status)
+{
+    if (U_FAILURE(*status)) {
+        return;
+    }
+    ((DateFormat*)fmt)->setContext(value, *status);
+    return;
+}
+
+U_CAPI UDisplayContext U_EXPORT2
+udat_getContext(const UDateFormat* fmt, UDisplayContextType type, UErrorCode* status)
+{
+    if (U_FAILURE(*status)) {
+        return (UDisplayContext)0;
+    }
+    return ((const DateFormat*)fmt)->getContext(type, *status);
+}
+
+
+/**
+ * Verify that fmt is a RelativeDateFormat. Invalid error if not.
+ * @param fmt the UDateFormat, definitely a DateFormat, maybe something else
+ * @param status error code, will be set to failure if there is a familure or the fmt is NULL.
+ */
+static void verifyIsRelativeDateFormat(const UDateFormat* fmt, UErrorCode *status) {
+   if(U_SUCCESS(*status) &&
+       dynamic_cast<const RelativeDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))==NULL) {
+       *status = U_ILLEGAL_ARGUMENT_ERROR;
+   }
+}
+
+
+U_CAPI int32_t U_EXPORT2 
+udat_toPatternRelativeDate(const UDateFormat *fmt,
+                           UChar             *result,
+                           int32_t           resultLength,
+                           UErrorCode        *status)
+{
+    verifyIsRelativeDateFormat(fmt, status);
+    if(U_FAILURE(*status)) {
+        return -1;
+    }
+    if (result == NULL ? resultLength != 0 : resultLength < 0) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return -1;
+    }
+
+    UnicodeString datePattern;
+    if (result != NULL) {
+        // NULL destination for pure preflighting: empty dummy string
+        // otherwise, alias the destination buffer
+        datePattern.setTo(result, 0, resultLength);
+    }
+    ((RelativeDateFormat*)fmt)->toPatternDate(datePattern, *status);
+    return datePattern.extract(result, resultLength, *status);
+}
+
+U_CAPI int32_t U_EXPORT2 
+udat_toPatternRelativeTime(const UDateFormat *fmt,
+                           UChar             *result,
+                           int32_t           resultLength,
+                           UErrorCode        *status)
+{
+    verifyIsRelativeDateFormat(fmt, status);
+    if(U_FAILURE(*status)) {
+        return -1;
+    }
+    if (result == NULL ? resultLength != 0 : resultLength < 0) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return -1;
+    }
+
+    UnicodeString timePattern;
+    if (result != NULL) {
+        // NULL destination for pure preflighting: empty dummy string
+        // otherwise, alias the destination buffer
+        timePattern.setTo(result, 0, resultLength);
+    }
+    ((RelativeDateFormat*)fmt)->toPatternTime(timePattern, *status);
+    return timePattern.extract(result, resultLength, *status);
+}
+
+U_CAPI void U_EXPORT2 
+udat_applyPatternRelative(UDateFormat *format,
+                          const UChar *datePattern,
+                          int32_t     datePatternLength,
+                          const UChar *timePattern,
+                          int32_t     timePatternLength,
+                          UErrorCode  *status)
+{
+    verifyIsRelativeDateFormat(format, status);
+    if(U_FAILURE(*status)) return;
+    const UnicodeString datePat((UBool)(datePatternLength == -1), datePattern, datePatternLength);
+    const UnicodeString timePat((UBool)(timePatternLength == -1), timePattern, timePatternLength);
+    ((RelativeDateFormat*)format)->applyPatterns(datePat, timePat, *status);
 }
 
 #endif /* #if !UCONFIG_NO_FORMATTING */
 }
 
 #endif /* #if !UCONFIG_NO_FORMATTING */