]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/dtitvfmt.cpp
ICU-57166.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / dtitvfmt.cpp
index 985176e03c2446d9417f38889c4c981a77b96606..dc4a0274eb2e8e0338c56c860dd346e96abfe615 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
-* Copyright (C) 2008, International Business Machines Corporation and
+* Copyright (C) 2008-2016, International Business Machines Corporation and
 * others. All Rights Reserved.
 *******************************************************************************
 *
@@ -8,27 +8,30 @@
 *******************************************************************************
 */
 
+#include "utypeinfo.h"  // for 'typeid' to work
+
 #include "unicode/dtitvfmt.h"
 
 #if !UCONFIG_NO_FORMATTING
 
-//FIXME: put in compilation
+//TODO: put in compilation
 //#define DTITVFMT_DEBUG 1
 
-#include "cstring.h"
-#include "unicode/msgfmt.h"
+#include "unicode/calendar.h"
 #include "unicode/dtptngen.h"
 #include "unicode/dtitvinf.h"
-#include "unicode/calendar.h"
+#include "unicode/udateintervalformat.h"
+#include "unicode/simpleformatter.h"
+#include "cmemory.h"
+#include "cstring.h"
 #include "dtitv_impl.h"
+#include "gregoimp.h"
+#include "mutex.h"
 
 #ifdef DTITVFMT_DEBUG 
 #include <iostream>
-#include "cstring.h"
 #endif
 
-#include "gregoimp.h"
-
 U_NAMESPACE_BEGIN
 
 
@@ -53,15 +56,18 @@ static const char gDateTimePatternsTag[]="DateTimePatterns";
 
 
 // latestFirst:
-static const UChar gLaterFirstPrefix[] = {LOW_L, LOW_A, LOW_T, LOW_E, LOW_S,LOW_T, CAP_F, LOW_I, LOW_R, LOW_S, LOW_T, COLON, 0};
+static const UChar gLaterFirstPrefix[] = {LOW_L, LOW_A, LOW_T, LOW_E, LOW_S,LOW_T, CAP_F, LOW_I, LOW_R, LOW_S, LOW_T, COLON};
 
 // earliestFirst:
-static const UChar gEarlierFirstPrefix[] = {LOW_E, LOW_A, LOW_R, LOW_L, LOW_I, LOW_E, LOW_S, LOW_T, CAP_F, LOW_I, LOW_R, LOW_S, LOW_T, COLON, 0};
+static const UChar gEarlierFirstPrefix[] = {LOW_E, LOW_A, LOW_R, LOW_L, LOW_I, LOW_E, LOW_S, LOW_T, CAP_F, LOW_I, LOW_R, LOW_S, LOW_T, COLON};
 
 
 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalFormat)
 
+// Mutex, protects access to fDateFormat, fFromCalendar and fToCalendar. 
+//        Needed because these data members are modified by const methods of DateIntervalFormat.
 
+static UMutex gFormatterMutex = U_MUTEX_INITIALIZER;
 
 DateIntervalFormat* U_EXPORT2
 DateIntervalFormat::createInstance(const UnicodeString& skeleton, 
@@ -74,8 +80,6 @@ DateIntervalFormat* U_EXPORT2
 DateIntervalFormat::createInstance(const UnicodeString& skeleton, 
                                    const Locale& locale, 
                                    UErrorCode& status) {
-    DateFormat* dtfmt = DateFormat::createPatternInstance(skeleton, locale, status);
-
 #ifdef DTITVFMT_DEBUG
     char result[1000];
     char result_1[1000];
@@ -89,7 +93,7 @@ DateIntervalFormat::createInstance(const UnicodeString& skeleton,
 #endif
 
     DateIntervalInfo* dtitvinf = new DateIntervalInfo(locale, status);
-    return create(dtfmt, dtitvinf, &skeleton, status);
+    return create(locale, dtitvinf, &skeleton, status);
 }
 
 
@@ -107,9 +111,8 @@ DateIntervalFormat::createInstance(const UnicodeString& skeleton,
                                    const Locale& locale,
                                    const DateIntervalInfo& dtitvinf,
                                    UErrorCode& status) {
-    DateFormat* dtfmt = DateFormat::createPatternInstance(skeleton, locale, status);
     DateIntervalInfo* ptn = dtitvinf.clone();
-    return create(dtfmt, ptn, &skeleton, status);
+    return create(locale, ptn, &skeleton, status);
 }
 
 
@@ -117,7 +120,12 @@ DateIntervalFormat::DateIntervalFormat()
 :   fInfo(NULL),
     fDateFormat(NULL),
     fFromCalendar(NULL),
-    fToCalendar(NULL)
+    fToCalendar(NULL),
+    fLocale(Locale::getRoot()),
+    fDatePattern(NULL),
+    fTimePattern(NULL),
+    fDateTimeFormat(NULL),
+    fMinimizeType(UDTITVFMT_MINIMIZE_NONE)
 {}
 
 
@@ -126,7 +134,12 @@ DateIntervalFormat::DateIntervalFormat(const DateIntervalFormat& itvfmt)
     fInfo(NULL),
     fDateFormat(NULL),
     fFromCalendar(NULL),
-    fToCalendar(NULL) {
+    fToCalendar(NULL),
+    fLocale(itvfmt.fLocale),
+    fDatePattern(NULL),
+    fTimePattern(NULL),
+    fDateTimeFormat(NULL),
+    fMinimizeType(UDTITVFMT_MINIMIZE_NONE) {
     *this = itvfmt;
 }
 
@@ -138,31 +151,41 @@ DateIntervalFormat::operator=(const DateIntervalFormat& itvfmt) {
         delete fInfo;
         delete fFromCalendar;
         delete fToCalendar;
-        if ( itvfmt.fDateFormat ) {
-            fDateFormat = (SimpleDateFormat*)itvfmt.fDateFormat->clone();
-        } else {
-            fDateFormat = NULL;
+        delete fDatePattern;
+        delete fTimePattern;
+        delete fDateTimeFormat;
+        {
+            Mutex lock(&gFormatterMutex);
+            if ( itvfmt.fDateFormat ) {
+                fDateFormat = (SimpleDateFormat*)itvfmt.fDateFormat->clone();
+            } else {
+                fDateFormat = NULL;
+            }
+            if ( itvfmt.fFromCalendar ) {
+                fFromCalendar = itvfmt.fFromCalendar->clone();
+            } else {
+                fFromCalendar = NULL;
+            }
+            if ( itvfmt.fToCalendar ) {
+                fToCalendar = itvfmt.fToCalendar->clone();
+            } else {
+                fToCalendar = NULL;
+            }
         }
         if ( itvfmt.fInfo ) {
             fInfo = itvfmt.fInfo->clone();
         } else {
             fInfo = NULL;
         }
-        if ( itvfmt.fFromCalendar ) {
-            fFromCalendar = itvfmt.fFromCalendar->clone();
-        } else {
-            fFromCalendar = NULL;
-        }
-        if ( itvfmt.fToCalendar ) {
-            fToCalendar = itvfmt.fToCalendar->clone();
-        } else {
-            fToCalendar = NULL;
-        }
         fSkeleton = itvfmt.fSkeleton;
         int8_t i;
         for ( i = 0; i< DateIntervalInfo::kIPI_MAX_INDEX; ++i ) {
             fIntervalPatterns[i] = itvfmt.fIntervalPatterns[i];
         }
+        fLocale = itvfmt.fLocale;
+        fDatePattern    = (itvfmt.fDatePattern)?    (UnicodeString*)itvfmt.fDatePattern->clone(): NULL;
+        fTimePattern    = (itvfmt.fTimePattern)?    (UnicodeString*)itvfmt.fTimePattern->clone(): NULL;
+        fDateTimeFormat = (itvfmt.fDateTimeFormat)? (UnicodeString*)itvfmt.fDateTimeFormat->clone(): NULL;
     }
     return *this;
 }
@@ -173,6 +196,9 @@ DateIntervalFormat::~DateIntervalFormat() {
     delete fDateFormat;
     delete fFromCalendar;
     delete fToCalendar;
+    delete fDatePattern;
+    delete fTimePattern;
+    delete fDateTimeFormat;
 }
 
 
@@ -184,44 +210,41 @@ DateIntervalFormat::clone(void) const {
 
 UBool
 DateIntervalFormat::operator==(const Format& other) const {
-    if ( other.getDynamicClassID() == DateIntervalFormat::getStaticClassID() ) {
-        DateIntervalFormat* fmt = (DateIntervalFormat*)&other;
-#ifdef DTITVFMT_DEBUG
-    UBool equal;
-    equal = (this == fmt);
-    
-    equal = (*fInfo == *fmt->fInfo);
-    equal = (*fDateFormat == *fmt->fDateFormat);
-    equal = fFromCalendar->isEquivalentTo(*fmt->fFromCalendar) ;
-    equal = fToCalendar->isEquivalentTo(*fmt->fToCalendar) ;
-    equal = (fSkeleton == fmt->fSkeleton);
-#endif
-        UBool res;
-        res =  ( this == fmt ) ||
-               ( Format::operator==(other) && 
-                 fInfo && 
-                 ( *fInfo == *fmt->fInfo ) &&
-                 fDateFormat &&
-                 ( *fDateFormat == *fmt->fDateFormat ) &&
-                 fFromCalendar &&
-                 fFromCalendar->isEquivalentTo(*fmt->fFromCalendar) &&
-                 fToCalendar &&
-                 fToCalendar->isEquivalentTo(*fmt->fToCalendar) &&
-                 fSkeleton == fmt->fSkeleton );
-        int8_t i;
-        for (i = 0; i< DateIntervalInfo::kIPI_MAX_INDEX && res == TRUE; ++i ) {
-            res =   ( fIntervalPatterns[i].firstPart ==
-                      fmt->fIntervalPatterns[i].firstPart) &&
-                    ( fIntervalPatterns[i].secondPart ==
-                      fmt->fIntervalPatterns[i].secondPart ) &&
-                    ( fIntervalPatterns[i].laterDateFirst ==
-                      fmt->fIntervalPatterns[i].laterDateFirst) ;
-        }
-        return res;
-    } 
-    return FALSE;
-}
+    if (typeid(*this) != typeid(other)) {return FALSE;}
+    const DateIntervalFormat* fmt = (DateIntervalFormat*)&other;
+    if (this == fmt) {return TRUE;}
+    if (!Format::operator==(other)) {return FALSE;}
+    if ((fInfo != fmt->fInfo) && (fInfo == NULL || fmt->fInfo == NULL)) {return FALSE;}
+    if (fInfo && fmt->fInfo && (*fInfo != *fmt->fInfo )) {return FALSE;}
+    {
+        Mutex lock(&gFormatterMutex);
+        if (fDateFormat != fmt->fDateFormat && (fDateFormat == NULL || fmt->fDateFormat == NULL)) {return FALSE;}
+        if (fDateFormat && fmt->fDateFormat && (*fDateFormat != *fmt->fDateFormat)) {return FALSE;}
 
+        // TODO: should operator == ignore the From and ToCalendar? They hold transient values during
+        //       formatting of a DateInterval.
+        if (fFromCalendar != fmt->fFromCalendar && (fFromCalendar == NULL || fmt->fFromCalendar == NULL)) {return FALSE;}
+        if (fFromCalendar && fmt->fFromCalendar && !fFromCalendar->isEquivalentTo(*fmt->fFromCalendar)) {return FALSE;}
+
+        if (fToCalendar != fmt->fToCalendar && (fToCalendar == NULL || fmt->fToCalendar == NULL)) {return FALSE;}
+        if (fToCalendar && fmt->fToCalendar && !fToCalendar->isEquivalentTo(*fmt->fToCalendar)) {return FALSE;}
+    }
+    if (fSkeleton != fmt->fSkeleton) {return FALSE;}
+    if (fDatePattern != fmt->fDatePattern && (fDatePattern == NULL || fmt->fDatePattern == NULL)) {return FALSE;}
+    if (fDatePattern && fmt->fDatePattern && (*fDatePattern != *fmt->fDatePattern)) {return FALSE;}
+    if (fTimePattern != fmt->fTimePattern && (fTimePattern == NULL || fmt->fTimePattern == NULL)) {return FALSE;}
+    if (fTimePattern && fmt->fTimePattern && (*fTimePattern != *fmt->fTimePattern)) {return FALSE;}
+    if (fDateTimeFormat != fmt->fDateTimeFormat && (fDateTimeFormat == NULL || fmt->fDateTimeFormat == NULL)) {return FALSE;}
+    if (fDateTimeFormat && fmt->fDateTimeFormat && (*fDateTimeFormat != *fmt->fDateTimeFormat)) {return FALSE;}
+    if (fLocale != fmt->fLocale) {return FALSE;}
+
+    for (int32_t i = 0; i< DateIntervalInfo::kIPI_MAX_INDEX; ++i ) {
+        if (fIntervalPatterns[i].firstPart != fmt->fIntervalPatterns[i].firstPart) {return FALSE;}
+        if (fIntervalPatterns[i].secondPart != fmt->fIntervalPatterns[i].secondPart ) {return FALSE;}
+        if (fIntervalPatterns[i].laterDateFirst != fmt->fIntervalPatterns[i].laterDateFirst) {return FALSE;}
+    }
+    return TRUE;
+}
 
 
 UnicodeString&
@@ -235,8 +258,9 @@ DateIntervalFormat::format(const Formattable& obj,
 
     if ( obj.getType() == Formattable::kObject ) {
         const UObject* formatObj = obj.getObject();
-        if (formatObj->getDynamicClassID() == DateInterval::getStaticClassID()){
-            return format((DateInterval*)formatObj, appendTo, fieldPosition, status);
+        const DateInterval* interval = dynamic_cast<const DateInterval*>(formatObj);
+        if (interval != NULL) {
+            return format(interval, appendTo, fieldPosition, status);
         }
     }
     status = U_ILLEGAL_ARGUMENT_ERROR;
@@ -252,16 +276,15 @@ DateIntervalFormat::format(const DateInterval* dtInterval,
     if ( U_FAILURE(status) ) {
         return appendTo;
     }
-
-    if ( fFromCalendar != NULL && fToCalendar != NULL && 
-         fDateFormat != NULL && fInfo != NULL ) {
-        fFromCalendar->setTime(dtInterval->getFromDate(), status);
-        fToCalendar->setTime(dtInterval->getToDate(), status);
-        if ( U_SUCCESS(status) ) {
-            return format(*fFromCalendar, *fToCalendar, appendTo,fieldPosition, status);
-        }
+    if (fFromCalendar == NULL || fToCalendar == NULL || fDateFormat == NULL || fInfo == NULL) {
+        status = U_INVALID_STATE_ERROR;
+        return appendTo;
     }
-    return appendTo;
+
+    Mutex lock(&gFormatterMutex);
+    fFromCalendar->setTime(dtInterval->getFromDate(), status);
+    fToCalendar->setTime(dtInterval->getToDate(), status);
+    return formatImpl(*fFromCalendar, *fToCalendar, appendTo,fieldPosition, status);
 }
 
 
@@ -271,32 +294,79 @@ DateIntervalFormat::format(Calendar& fromCalendar,
                            UnicodeString& appendTo,
                            FieldPosition& pos,
                            UErrorCode& status) const {
+    Mutex lock(&gFormatterMutex);
+    return formatImpl(fromCalendar, toCalendar, appendTo, pos, status);
+}
+
+UnicodeString&
+DateIntervalFormat::formatImpl(Calendar& fromCalendar,
+                           Calendar& toCalendar,
+                           UnicodeString& appendTo,
+                           FieldPosition& pos,
+                           UErrorCode& status) const {
     if ( U_FAILURE(status) ) {
         return appendTo;
     }
 
     // not support different calendar types and time zones
     //if ( fromCalendar.getType() != toCalendar.getType() ) {
-    if ( !fromCalendar.isEquivalentTo(toCalendar) ||
-         uprv_strcmp(fromCalendar.getType(), "gregorian") ) {
+    if ( !fromCalendar.isEquivalentTo(toCalendar) ) {
         status = U_ILLEGAL_ARGUMENT_ERROR;
         return appendTo;
     }
 
     // First, find the largest different calendar field.
     UCalendarDateFields field = UCAL_FIELD_COUNT;
+    UChar patternDay  = 0x0064; // d
+    UChar patternYear = 0x0079; // y
 
     if ( fromCalendar.get(UCAL_ERA,status) != toCalendar.get(UCAL_ERA,status)) {
         field = UCAL_ERA;
     } else if ( fromCalendar.get(UCAL_YEAR, status) != 
                 toCalendar.get(UCAL_YEAR, status) ) {
         field = UCAL_YEAR;
+        if (fMinimizeType == UDTITVFMT_MINIMIZE_ADJACENT_MONTHS && fSkeleton.indexOf(patternDay) >= 0 && fSkeleton.indexOf(patternYear) < 0) {
+            UDate fromDate = fromCalendar.getTime(status);
+            UDate toDate = toCalendar.getTime(status);
+            int32_t fromDay = fromCalendar.get(UCAL_DATE, status);
+            int32_t toDay = toCalendar.get(UCAL_DATE, status);
+            fromCalendar.add(UCAL_MONTH, 1, status);
+            if ( fromDate < toDate && fromCalendar.getTime(status) > toDate && fromDay > toDay ) {
+                field = UCAL_DATE;
+            }
+            fromCalendar.setTime(fromDate, status);
+        }
     } else if ( fromCalendar.get(UCAL_MONTH, status) !=
                 toCalendar.get(UCAL_MONTH, status) ) {
         field = UCAL_MONTH;
+        if (fMinimizeType == UDTITVFMT_MINIMIZE_ADJACENT_MONTHS && fSkeleton.indexOf(patternDay) >= 0) {
+            UDate fromDate = fromCalendar.getTime(status);
+            UDate toDate = toCalendar.getTime(status);
+            int32_t fromDay = fromCalendar.get(UCAL_DATE, status);
+            int32_t toDay = toCalendar.get(UCAL_DATE, status);
+            fromCalendar.add(UCAL_MONTH, 1, status);
+            if ( fromDate < toDate && fromCalendar.getTime(status) > toDate && fromDay > toDay ) {
+                field = UCAL_DATE;
+            }
+            fromCalendar.setTime(fromDate, status);
+        }
     } else if ( fromCalendar.get(UCAL_DATE, status) !=
                 toCalendar.get(UCAL_DATE, status) ) {
         field = UCAL_DATE;
+        if (fMinimizeType == UDTITVFMT_MINIMIZE_ADJACENT_DAYS &&
+                // check normalized skeleton for 'H', 'h', 'j'
+                (fSkeleton.indexOf(0x0048) >= 0 || fSkeleton.indexOf(0x0068) >= 0 || fSkeleton.indexOf(0x006A) >= 0)) {
+            UDate fromDate = fromCalendar.getTime(status);
+            UDate toDate = toCalendar.getTime(status);
+            int32_t fromHour = fromCalendar.get(UCAL_HOUR, status);
+            int32_t toHour = toCalendar.get(UCAL_HOUR, status);
+            fromCalendar.add(UCAL_HOUR_OF_DAY, 12, status);
+            if ( fromDate < toDate && fromCalendar.getTime(status) > toDate && fromHour > toHour ) {
+                field = UCAL_AM_PM;
+            }
+            fromCalendar.setTime(fromDate, status);
+        }
     } else if ( fromCalendar.get(UCAL_AM_PM, status) !=
                 toCalendar.get(UCAL_AM_PM, status) ) {
         field = UCAL_AM_PM;
@@ -306,17 +376,21 @@ DateIntervalFormat::format(Calendar& fromCalendar,
     } else if ( fromCalendar.get(UCAL_MINUTE, status) !=
                 toCalendar.get(UCAL_MINUTE, status) ) {
         field = UCAL_MINUTE;
+    } else if ( fromCalendar.get(UCAL_SECOND, status) !=
+                toCalendar.get(UCAL_SECOND, status) ) {
+        field = UCAL_SECOND;
     }
 
     if ( U_FAILURE(status) ) {
         return appendTo;
     }
     if ( field == UCAL_FIELD_COUNT ) {
-        /* ignore the second/millisecond etc. small fields' difference.
+        /* ignore the millisecond etc. small fields' difference.
          * use single date when all the above are the same.
          */
         return fDateFormat->format(fromCalendar, appendTo, pos);
     }
+    UBool fromToOnSameDay = (field==UCAL_AM_PM || field==UCAL_HOUR || field==UCAL_MINUTE || field==UCAL_SECOND);
     
     // following call should not set wrong status,
     // all the pass-in fields are valid till here
@@ -333,7 +407,7 @@ DateIntervalFormat::format(Calendar& fromCalendar,
              */
             return fDateFormat->format(fromCalendar, appendTo, pos);
         }
-        return fallbackFormat(fromCalendar, toCalendar, appendTo, pos, status);
+        return fallbackFormat(fromCalendar, toCalendar, fromToOnSameDay, appendTo, pos, status);
     }
     // If the first part in interval pattern is empty, 
     // the 2nd part of it saves the full-pattern used in fall-back.
@@ -343,7 +417,7 @@ DateIntervalFormat::format(Calendar& fromCalendar,
         UnicodeString originalPattern;
         fDateFormat->toPattern(originalPattern);
         fDateFormat->applyPattern(intervalPattern.secondPart);
-        appendTo = fallbackFormat(fromCalendar, toCalendar, appendTo, pos, status);
+        appendTo = fallbackFormat(fromCalendar, toCalendar, fromToOnSameDay, appendTo, pos, status);
         fDateFormat->applyPattern(originalPattern);
         return appendTo;
     }
@@ -364,7 +438,12 @@ DateIntervalFormat::format(Calendar& fromCalendar,
     fDateFormat->format(*firstCal, appendTo, pos);
     if ( !intervalPattern.secondPart.isEmpty() ) {
         fDateFormat->applyPattern(intervalPattern.secondPart);
-        fDateFormat->format(*secondCal, appendTo, pos);
+        FieldPosition otherPos;
+        otherPos.setField(pos.getField());
+        fDateFormat->format(*secondCal, appendTo, otherPos);
+        if (pos.getEndIndex() == 0 && otherPos.getEndIndex() > 0) {
+            pos = otherPos;
+        }
     }
     fDateFormat->applyPattern(originalPattern);
     return appendTo;
@@ -395,7 +474,16 @@ DateIntervalFormat::setDateIntervalInfo(const DateIntervalInfo& newItvPattern,
                                         UErrorCode& status) {
     delete fInfo;
     fInfo = new DateIntervalInfo(newItvPattern);
-    if ( fDateFormat ) {
+
+    // Delete patterns that get reset by initializePattern
+    delete fDatePattern;
+    fDatePattern = NULL;
+    delete fTimePattern;
+    fTimePattern = NULL;
+    delete fDateTimeFormat;
+    fDateTimeFormat = NULL;
+
+    if (fDateFormat) {
         initializePattern(status);
     }
 }
@@ -408,54 +496,108 @@ DateIntervalFormat::getDateFormat() const {
 }
 
 
-DateIntervalFormat::DateIntervalFormat(DateFormat* dtfmt,
-                                       DateIntervalInfo* dtItvInfo,
-                                       const UnicodeString* skeleton,
-                                       UErrorCode& status) 
-:   fInfo(0),
-    fDateFormat(0),
-    fFromCalendar(0),
-    fToCalendar(0)
+void
+DateIntervalFormat::adoptTimeZone(TimeZone* zone)
+{
+    if (fDateFormat != NULL) {
+        fDateFormat->adoptTimeZone(zone);
+    }
+    // The fDateFormat has the master calendar for the DateIntervalFormat and has
+    // ownership of any adopted TimeZone; fFromCalendar and fToCalendar are internal
+    // work clones of that calendar (and should not also be given ownership of the
+    // adopted TimeZone).
+    if (fFromCalendar) {
+        fFromCalendar->setTimeZone(*zone);
+    }
+    if (fToCalendar) {
+        fToCalendar->setTimeZone(*zone);
+    }
+}
+
+void
+DateIntervalFormat::setTimeZone(const TimeZone& zone)
+{
+    if (fDateFormat != NULL) {
+        fDateFormat->setTimeZone(zone);
+    }
+    // The fDateFormat has the master calendar for the DateIntervalFormat;
+    // fFromCalendar and fToCalendar are internal work clones of that calendar.
+    if (fFromCalendar) {
+        fFromCalendar->setTimeZone(zone);
+    }
+    if (fToCalendar) {
+        fToCalendar->setTimeZone(zone);
+    }
+}
+
+const TimeZone&
+DateIntervalFormat::getTimeZone() const
+{
+    if (fDateFormat != NULL) {
+        Mutex lock(&gFormatterMutex);
+        return fDateFormat->getTimeZone();
+    }
+    // If fDateFormat is NULL (unexpected), create default timezone.
+    return *(TimeZone::createDefault());
+}
+
+void
+DateIntervalFormat::setAttribute(UDateIntervalFormatAttribute attr,
+                                 UDateIntervalFormatAttributeValue value,
+                                 UErrorCode &status)
 {
     if ( U_FAILURE(status) ) {
-        delete dtfmt;
-        delete dtItvInfo;
         return;
     }
-    if ( dtfmt == NULL || dtItvInfo == NULL ) {
-        status = U_MEMORY_ALLOCATION_ERROR;
-        // safe to delete NULL
-        delete dtfmt;
-        delete dtItvInfo;
+    if (attr == UDTITVFMT_MINIMIZE_TYPE) {
+        fMinimizeType = value;
+    } else {
+        status = U_ILLEGAL_ARGUMENT_ERROR; 
+    }
+}
+
+DateIntervalFormat::DateIntervalFormat(const Locale& locale,
+                                       DateIntervalInfo* dtItvInfo,
+                                       const UnicodeString* skeleton,
+                                       UErrorCode& status) 
+:   fInfo(NULL),
+    fDateFormat(NULL),
+    fFromCalendar(NULL),
+    fToCalendar(NULL),
+    fLocale(locale),
+    fDatePattern(NULL),
+    fTimePattern(NULL),
+    fDateTimeFormat(NULL),
+    fMinimizeType(UDTITVFMT_MINIMIZE_NONE)
+{
+    LocalPointer<DateIntervalInfo> info(dtItvInfo, status);
+    LocalPointer<SimpleDateFormat> dtfmt(static_cast<SimpleDateFormat *>(
+            DateFormat::createInstanceForSkeleton(*skeleton, locale, status)), status);
+    if (U_FAILURE(status)) {
         return;
     }
+
     if ( skeleton ) {
         fSkeleton = *skeleton;
     }
-    fInfo = dtItvInfo;
-    fDateFormat = (SimpleDateFormat*)dtfmt;
-    if ( dtfmt->getCalendar() ) {
-        fFromCalendar = dtfmt->getCalendar()->clone();
-        fToCalendar = dtfmt->getCalendar()->clone();
-    } else {
-        fFromCalendar = NULL;
-        fToCalendar = NULL;
+    fInfo = info.orphan();
+    fDateFormat = dtfmt.orphan();
+    if ( fDateFormat->getCalendar() ) {
+        fFromCalendar = fDateFormat->getCalendar()->clone();
+        fToCalendar = fDateFormat->getCalendar()->clone();
     }
     initializePattern(status);
 }
 
-
-
 DateIntervalFormat* U_EXPORT2
-DateIntervalFormat::create(DateFormat* dtfmt,
+DateIntervalFormat::create(const Locale& locale,
                            DateIntervalInfo* dtitvinf,
                            const UnicodeString* skeleton,
                            UErrorCode& status) {
-    DateIntervalFormat* f = new DateIntervalFormat(dtfmt, dtitvinf, 
+    DateIntervalFormat* f = new DateIntervalFormat(locale, dtitvinf, 
                                                    skeleton, status);
     if ( f == NULL ) {
         status = U_MEMORY_ALLOCATION_ERROR;
-        delete dtfmt;
         delete dtitvinf;
     } else if ( U_FAILURE(status) ) {
         // safe to delete f, although nothing acutally is saved
@@ -499,7 +641,7 @@ DateIntervalFormat::create(DateFormat* dtfmt,
  *    includes year, month, and date when year, month, and date differs.
  * 
  * @param status          output param set to success/failure code on exit
- * @draft ICU 4.0 
+ * @stable ICU 4.0 
  */
 void 
 DateIntervalFormat::initializePattern(UErrorCode& status) {
@@ -507,11 +649,6 @@ DateIntervalFormat::initializePattern(UErrorCode& status) {
         return;
     }
     const Locale& locale = fDateFormat->getSmpFmtLocale();
-    DateTimePatternGenerator* dtpng = DateTimePatternGenerator::createInstance(locale, status);
-    if ( U_FAILURE(status) ) {
-        delete dtpng;
-        return;    
-    }
     if ( fSkeleton.isEmpty() ) {
         UnicodeString fullPattern;
         fDateFormat->toPattern(fullPattern);
@@ -525,9 +662,9 @@ DateIntervalFormat::initializePattern(UErrorCode& status) {
 #endif
         // fSkeleton is already set by createDateIntervalInstance()
         // or by createInstance(UnicodeString skeleton, .... )
-        fSkeleton = dtpng->getSkeleton(fullPattern, status);
+        fSkeleton = DateTimePatternGenerator::staticGetSkeleton(
+                fullPattern, status);
         if ( U_FAILURE(status) ) {
-            delete dtpng;
             return;    
         }
     }
@@ -548,9 +685,9 @@ DateIntervalFormat::initializePattern(UErrorCode& status) {
 
 
     /* the difference between time skeleton and normalizedTimeSkeleton are:
-     * 1. both 'H' and 'h' are normalized as 'h' in normalized time skeleton,
+     * 1. (Formerly, normalized time skeleton folded 'H' to 'h'; no longer true)
      * 2. 'a' is omitted in normalized time skeleton.
-     * 3. there is only one appearance for 'h', 'm','v', 'z' in normalized 
+     * 3. there is only one appearance for 'h' or 'H', 'm','v', 'z' in normalized 
      *    time skeleton
      *
      * The difference between date skeleton and normalizedDateSkeleton are:
@@ -570,20 +707,49 @@ DateIntervalFormat::initializePattern(UErrorCode& status) {
     PRINTMESG(mesg)
 #endif
 
+    // move this up here since we need it for fallbacks
+    if ( timeSkeleton.length() > 0 && dateSkeleton.length() > 0 ) {
+        // Need the Date/Time pattern for concatenation of the date
+        // with the time interval.
+        // The date/time pattern ( such as {0} {1} ) is saved in
+        // calendar, that is why need to get the CalendarData here.
+        CalendarData* calData = new CalendarData(locale, NULL, status);
+        if ( U_FAILURE(status) ) {
+            delete calData;
+            return;
+        }
+        if ( calData == NULL ) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+             return;
+        }
+       
+        const UResourceBundle* dateTimePatternsRes = calData->getByKey(
+                                            gDateTimePatternsTag, status);
+        int32_t dateTimeFormatLength;
+        const UChar* dateTimeFormat = ures_getStringByIndex(
+                                            dateTimePatternsRes,
+                                            (int32_t)DateFormat::kDateTime,
+                                            &dateTimeFormatLength, &status);
+        if ( U_SUCCESS(status) && dateTimeFormatLength >= 3 ) {
+            fDateTimeFormat = new UnicodeString(dateTimeFormat, dateTimeFormatLength);
+        }
+        delete calData;
+    }
 
     UBool found = setSeparateDateTimePtn(normalizedDateSkeleton, 
                                          normalizedTimeSkeleton);
 
+    // for skeletons with seconds, found is false and we enter this block
     if ( found == false ) {
         // use fallback
         // TODO: if user asks "m"(minute), but "d"(day) differ
         if ( timeSkeleton.length() != 0 ) {
             if ( dateSkeleton.length() == 0 ) {
                 // prefix with yMd
-                timeSkeleton.insert(0, gDateFormatSkeleton[DateFormat::kShort]);
-                UnicodeString pattern =dtpng->getBestPattern(timeSkeleton, status);
+                timeSkeleton.insert(0, gDateFormatSkeleton[DateFormat::kShort], -1);
+                UnicodeString pattern = DateFormat::getBestPattern(
+                        locale, timeSkeleton, status);
                 if ( U_FAILURE(status) ) {
-                    delete dtpng;
                     return;    
                 }
                 // for fall back interval patterns,
@@ -599,7 +765,6 @@ DateIntervalFormat::initializePattern(UErrorCode& status) {
         } else {
             // TODO: fall back
         }
-        delete dtpng;
         return;
     } // end of skeleton not found
     // interval patterns for skeleton are found in resource 
@@ -607,10 +772,10 @@ DateIntervalFormat::initializePattern(UErrorCode& status) {
         // done
     } else if ( dateSkeleton.length() == 0 ) {
         // prefix with yMd
-        timeSkeleton.insert(0, gDateFormatSkeleton[DateFormat::kShort]);
-        UnicodeString pattern =dtpng->getBestPattern(timeSkeleton, status);
+        timeSkeleton.insert(0, gDateFormatSkeleton[DateFormat::kShort], -1);
+        UnicodeString pattern = DateFormat::getBestPattern(
+                locale, timeSkeleton, status);
         if ( U_FAILURE(status) ) {
-            delete dtpng;
             return;    
         }
         // for fall back interval patterns,
@@ -636,64 +801,36 @@ DateIntervalFormat::initializePattern(UErrorCode& status) {
         if ( !fieldExistsInSkeleton(UCAL_DATE, dateSkeleton) ) {
             // prefix skeleton with 'd'
             skeleton.insert(0, LOW_D);
-            setFallbackPattern(UCAL_DATE, skeleton, dtpng, status);
+            setFallbackPattern(UCAL_DATE, skeleton, status);
         }
         if ( !fieldExistsInSkeleton(UCAL_MONTH, dateSkeleton) ) {
             // then prefix skeleton with 'M'
             skeleton.insert(0, CAP_M);
-            setFallbackPattern(UCAL_MONTH, skeleton, dtpng, status);
+            setFallbackPattern(UCAL_MONTH, skeleton, status);
         }
         if ( !fieldExistsInSkeleton(UCAL_YEAR, dateSkeleton) ) {
             // then prefix skeleton with 'y'
             skeleton.insert(0, LOW_Y);
-            setFallbackPattern(UCAL_YEAR, skeleton, dtpng, status);
+            setFallbackPattern(UCAL_YEAR, skeleton, status);
         }
         
         /*
          * 2) otherwise, present the date followed by the 
          * range expression for the time. 
          */
-        // Need the Date/Time pattern for concatnation the date with
-        // the time interval.
-        // The date/time pattern ( such as {0} {1} ) is saved in
-        // calendar, that is why need to get the CalendarData here.
-        CalendarData* calData = new CalendarData(locale, NULL, status);
 
-        if ( U_FAILURE(status) ) {
-            delete calData;
-            delete dtpng;
-            return;
-        }
-
-        if ( calData == NULL ) {
-            status = U_MEMORY_ALLOCATION_ERROR;
-            delete dtpng;
-            return;
-        }
-       
-        const UResourceBundle* dateTimePatternsRes = calData->getByKey(
-                                           gDateTimePatternsTag, status);
-        int32_t dateTimeFormatLength;
-        const UChar* dateTimeFormat = ures_getStringByIndex(
-                                            dateTimePatternsRes,
-                                            (int32_t)DateFormat::kDateTime,
-                                            &dateTimeFormatLength, &status);
-        if ( U_FAILURE(status) ) {
-            delete dtpng;
+        if ( fDateTimeFormat == NULL ) {
+            // earlier failure getting dateTimeFormat
             return;
         }
 
-        UnicodeString datePattern = dtpng->getBestPattern(dateSkeleton, status);
+        UnicodeString datePattern = DateFormat::getBestPattern(
+                locale, dateSkeleton, status);
 
-        concatSingleDate2TimeInterval(dateTimeFormat, dateTimeFormatLength,
-                                      datePattern, UCAL_AM_PM, status);
-        concatSingleDate2TimeInterval(dateTimeFormat, dateTimeFormatLength,
-                                      datePattern, UCAL_HOUR, status);
-        concatSingleDate2TimeInterval(dateTimeFormat, dateTimeFormatLength,
-                                      datePattern, UCAL_MINUTE, status);
-        delete calData;
+        concatSingleDate2TimeInterval(*fDateTimeFormat, datePattern, UCAL_AM_PM, status);
+        concatSingleDate2TimeInterval(*fDateTimeFormat, datePattern, UCAL_HOUR, status);
+        concatSingleDate2TimeInterval(*fDateTimeFormat, datePattern, UCAL_MINUTE, status);
     }
-    delete dtpng;
 }
 
 
@@ -711,6 +848,7 @@ DateIntervalFormat::getDateTimeSkeleton(const UnicodeString& skeleton,
     int32_t MCount = 0;
     int32_t yCount = 0;
     int32_t hCount = 0;
+    int32_t HCount = 0;
     int32_t mCount = 0;
     int32_t vCount = 0;
     int32_t zCount = 0;
@@ -749,6 +887,8 @@ DateIntervalFormat::getDateTimeSkeleton(const UnicodeString& skeleton,
           case LOW_G:
           case LOW_E:
           case LOW_C:
+          case CAP_U:
+          case LOW_R:
             normalizedDateSkeleton.append(ch);
             dateSkeleton.append(ch);
             break;
@@ -757,10 +897,13 @@ DateIntervalFormat::getDateTimeSkeleton(const UnicodeString& skeleton,
             timeSkeleton.append(ch);
             break;
           case LOW_H:
-          case CAP_H:
             timeSkeleton.append(ch);
             ++hCount;
             break;
+          case CAP_H:
+            timeSkeleton.append(ch);
+            ++HCount;
+            break;
           case LOW_M:
             timeSkeleton.append(ch);
             ++mCount;
@@ -773,7 +916,6 @@ DateIntervalFormat::getDateTimeSkeleton(const UnicodeString& skeleton,
             ++vCount;
             timeSkeleton.append(ch);
             break;
-          // FIXME: what is the difference between CAP_V/Z and LOW_V/Z
           case CAP_V:
           case CAP_Z:
           case LOW_K:
@@ -790,7 +932,9 @@ DateIntervalFormat::getDateTimeSkeleton(const UnicodeString& skeleton,
 
     /* generate normalized form for date*/
     if ( yCount != 0 ) {
-        normalizedDateSkeleton.append(LOW_Y);
+        for (i = 0; i < yCount; ++i) {
+            normalizedDateSkeleton.append(LOW_Y);
+        }
     }
     if ( MCount != 0 ) {
         if ( MCount < 3 ) {
@@ -817,7 +961,10 @@ DateIntervalFormat::getDateTimeSkeleton(const UnicodeString& skeleton,
     }
 
     /* generate normalized form for time */
-    if ( hCount != 0 ) {
+    if ( HCount != 0 ) {
+        normalizedTimeSkeleton.append(CAP_H);
+    }
+    else if ( hCount != 0 ) {
         normalizedTimeSkeleton.append(LOW_H);
     }
     if ( mCount != 0 ) {
@@ -854,7 +1001,7 @@ DateIntervalFormat::getDateTimeSkeleton(const UnicodeString& skeleton,
  * @return               whether the resource is found for the skeleton.
  *                       TRUE if interval pattern found for the skeleton,
  *                       FALSE otherwise.
- * @draft ICU 4.0
+ * @stable ICU 4.0
  */
 UBool 
 DateIntervalFormat::setSeparateDateTimePtn(
@@ -897,11 +1044,27 @@ DateIntervalFormat::setSeparateDateTimePtn(
         return false; 
     } 
    
+    // Set patterns for fallback use, need to do this
+    // before returning if differenceInfo == -1
+    UErrorCode status;
+    if ( dateSkeleton.length() != 0) {
+        status = U_ZERO_ERROR;
+        fDatePattern = new UnicodeString(DateFormat::getBestPattern(
+                fLocale, dateSkeleton, status));
+    }
+    if ( timeSkeleton.length() != 0) {
+        status = U_ZERO_ERROR;
+        fTimePattern = new UnicodeString(DateFormat::getBestPattern(
+                fLocale, timeSkeleton, status));
+    }
+
     // difference:
     // 0 means the best matched skeleton is the same as input skeleton
     // 1 means the fields are the same, but field width are different
     // 2 means the only difference between fields are v/z,
     // -1 means there are other fields difference 
+    // (this will happen, for instance, if the supplied skeleton has seconds,
+    //  but no skeletons in the intervalFormats data do)
     if ( differenceInfo == -1 ) { 
         // skeleton has different fields, not only  v/z difference
         return false;
@@ -937,12 +1100,12 @@ DateIntervalFormat::setSeparateDateTimePtn(
 void
 DateIntervalFormat::setFallbackPattern(UCalendarDateFields field,
                                        const UnicodeString& skeleton,
-                                       DateTimePatternGenerator* dtpng,
                                        UErrorCode& status) {
     if ( U_FAILURE(status) ) {
         return;
     }
-    UnicodeString pattern =dtpng->getBestPattern(skeleton, status);
+    UnicodeString pattern = DateFormat::getBestPattern(
+            fLocale, skeleton, status);
     if ( U_FAILURE(status) ) {
         return;
     }
@@ -993,8 +1156,8 @@ DateIntervalFormat::setIntervalPattern(UCalendarDateFields field,
     const UnicodeString* pattern = &intervalPattern;
     UBool order = laterDateFirst;
     // check for "latestFirst:" or "earliestFirst:" prefix
-    int8_t prefixLength = sizeof(gLaterFirstPrefix)/sizeof(gLaterFirstPrefix[0]);
-    int8_t earliestFirstLength = sizeof(gEarlierFirstPrefix)/sizeof(gEarlierFirstPrefix[0]);
+    int8_t prefixLength = UPRV_LENGTHOF(gLaterFirstPrefix);
+    int8_t earliestFirstLength = UPRV_LENGTHOF(gEarlierFirstPrefix);
     UnicodeString realPattern;
     if ( intervalPattern.startsWith(gLaterFirstPrefix, prefixLength) ) {
         order = true;
@@ -1047,7 +1210,7 @@ DateIntervalFormat::setIntervalPattern(UCalendarDateFields field,
  *                              through extending skeleton or not.
  *                              TRUE if interval pattern is found by
  *                              extending skeleton, FALSE otherwise.
- * @draft ICU 4.0
+ * @stable ICU 4.0
  */
 UBool
 DateIntervalFormat::setIntervalPattern(UCalendarDateFields field,
@@ -1196,33 +1359,95 @@ DateIntervalFormat::splitPatternInto2Part(const UnicodeString& intervalPattern)
     return (i - count);
 }
 
+static const UChar bracketedZero[] = {0x7B,0x30,0x7D};
+static const UChar bracketedOne[]  = {0x7B,0x31,0x7D};
 
+void
+DateIntervalFormat::adjustPosition(UnicodeString& combiningPattern, // has {0} and {1} in it
+                                   UnicodeString& pat0, FieldPosition& pos0, // pattern and pos corresponding to {0}
+                                   UnicodeString& pat1, FieldPosition& pos1, // pattern and pos corresponding to {1}
+                                   FieldPosition& posResult)  {
+    int32_t index0 = combiningPattern.indexOf(bracketedZero, 3, 0);
+    int32_t index1 = combiningPattern.indexOf(bracketedOne,  3, 0);
+    if (index0 < 0 || index1 < 0) {
+        return;
+    }
+    int32_t placeholderLen = 3; // length of "{0}" or "{1}"
+    if (index0 < index1) {
+        if (pos0.getEndIndex() > 0) {
+            posResult.setBeginIndex(pos0.getBeginIndex() + index0);
+            posResult.setEndIndex(pos0.getEndIndex() + index0);
+        } else if (pos1.getEndIndex() > 0) {
+            // here index1 >= 3
+            index1 += pat0.length() - placeholderLen; // adjust for pat0 replacing {0}
+            posResult.setBeginIndex(pos1.getBeginIndex() + index1);
+            posResult.setEndIndex(pos1.getEndIndex() + index1);
+        }
+    } else {
+        if (pos1.getEndIndex() > 0) {
+            posResult.setBeginIndex(pos1.getBeginIndex() + index1);
+            posResult.setEndIndex(pos1.getEndIndex() + index1);
+        } else if (pos0.getEndIndex() > 0) {
+            // here index0 >= 3
+            index0 += pat1.length() - placeholderLen; // adjust for pat1 replacing {1}
+            posResult.setBeginIndex(pos0.getBeginIndex() + index0);
+            posResult.setEndIndex(pos0.getEndIndex() + index0);
+        }
+    }
+}
 
 UnicodeString& 
 DateIntervalFormat::fallbackFormat(Calendar& fromCalendar,
                                    Calendar& toCalendar,
+                                   UBool fromToOnSameDay, // new
                                    UnicodeString& appendTo,
                                    FieldPosition& pos,
                                    UErrorCode& status) const {
     if ( U_FAILURE(status) ) {
         return appendTo;
     }
+    UnicodeString fullPattern; // for saving the pattern in fDateFormat
+    UBool formatDatePlusTimeRange = (fromToOnSameDay && fDatePattern && fTimePattern);
     // the fall back
-    // no need delete earlierDate and laterDate since they are adopted
-    UnicodeString* earlierDate = new UnicodeString();
-    *earlierDate = fDateFormat->format(fromCalendar, *earlierDate, pos);
-    UnicodeString* laterDate = new UnicodeString();
-    *laterDate = fDateFormat->format(toCalendar, *laterDate, pos);
+    if (formatDatePlusTimeRange) {
+        fDateFormat->toPattern(fullPattern); // save current pattern, restore later
+        fDateFormat->applyPattern(*fTimePattern);
+    }
+    FieldPosition otherPos;
+    otherPos.setField(pos.getField());
+    UnicodeString earlierDate;
+    fDateFormat->format(fromCalendar, earlierDate, pos);
+    UnicodeString laterDate;
+    fDateFormat->format(toCalendar, laterDate, otherPos);
     UnicodeString fallbackPattern;
     fInfo->getFallbackIntervalPattern(fallbackPattern);
-    Formattable fmtArray[2];
-    fmtArray[0].adoptString(earlierDate);
-    fmtArray[1].adoptString(laterDate);
-    
-    UnicodeString fallback;
-    MessageFormat::format(fallbackPattern, fmtArray, 2, fallback, status);
+    adjustPosition(fallbackPattern, earlierDate, pos, laterDate, otherPos, pos);
+    UnicodeString fallbackRange;
+    SimpleFormatter(fallbackPattern, 2, 2, status).
+            format(earlierDate, laterDate, fallbackRange, status);
+    if ( U_SUCCESS(status) && formatDatePlusTimeRange ) {
+        // fallbackRange has just the time range, need to format the date part and combine that
+        UnicodeString dateTimeFormatNoQuote(*fDateTimeFormat);
+        dateTimeFormatNoQuote.findAndReplace(UnicodeString(0x0027), UnicodeString());
+        fDateFormat->applyPattern(*fDatePattern);
+        UnicodeString datePortion;
+        otherPos.setBeginIndex(0);
+        otherPos.setEndIndex(0);
+        fDateFormat->format(fromCalendar, datePortion, otherPos);
+        adjustPosition(dateTimeFormatNoQuote, fallbackRange, pos, datePortion, otherPos, pos);
+        const UnicodeString *values[2] = {
+            &fallbackRange,  // {0} is time range
+            &datePortion,  // {1} is single date portion
+        };
+        SimpleFormatter(dateTimeFormatNoQuote, 2, 2, status).
+                formatAndReplace(values, 2, fallbackRange, NULL, 0, status);
+    }
     if ( U_SUCCESS(status) ) {
-        appendTo.append(fallback);
+        appendTo.append(fallbackRange);
+    }
+    if (formatDatePlusTimeRange) {
+        // restore full pattern
+        fDateFormat->applyPattern(fullPattern);
     }
     return appendTo;
 }
@@ -1274,7 +1499,8 @@ DateIntervalFormat::adjustFieldWidth(const UnicodeString& inputSkeleton,
     DateIntervalInfo::parseSkeleton(inputSkeleton, inputSkeletonFieldWidth);
     DateIntervalInfo::parseSkeleton(bestMatchSkeleton, bestMatchSkeletonFieldWidth);
     if ( differenceInfo == 2 ) {
-        adjustedPtn.findAndReplace("v", "z");
+        adjustedPtn.findAndReplace(UnicodeString((UChar)0x76 /* v */),
+                                   UnicodeString((UChar)0x7a /* z */));
     }
 
     UBool inQuote = false;
@@ -1351,8 +1577,7 @@ DateIntervalFormat::adjustFieldWidth(const UnicodeString& inputSkeleton,
 
 
 void 
-DateIntervalFormat::concatSingleDate2TimeInterval(const UChar* format,
-                                              int32_t formatLen,
+DateIntervalFormat::concatSingleDate2TimeInterval(UnicodeString& format,
                                               const UnicodeString& datePattern,
                                               UCalendarDateFields field,
                                               UErrorCode& status) {
@@ -1364,16 +1589,11 @@ DateIntervalFormat::concatSingleDate2TimeInterval(const UChar* format,
     }
     PatternInfo&  timeItvPtnInfo = fIntervalPatterns[itvPtnIndex];
     if ( !timeItvPtnInfo.firstPart.isEmpty() ) {
-        // UnicodeString allocated here is adopted, so no need to delete
-        UnicodeString* timeIntervalPattern = new UnicodeString(timeItvPtnInfo.firstPart);
-        timeIntervalPattern->append(timeItvPtnInfo.secondPart);
-        UnicodeString* dateStr = new UnicodeString(datePattern);
-        Formattable fmtArray[2];
-        fmtArray[0].adoptString(timeIntervalPattern);
-        fmtArray[1].adoptString(dateStr);
+        UnicodeString timeIntervalPattern(timeItvPtnInfo.firstPart);
+        timeIntervalPattern.append(timeItvPtnInfo.secondPart);
         UnicodeString combinedPattern;
-        MessageFormat::format(UnicodeString(TRUE, format, formatLen),
-                              fmtArray, 2, combinedPattern, status);
+        SimpleFormatter(format, 2, 2, status).
+                format(timeIntervalPattern, datePattern, combinedPattern, status);
         if ( U_FAILURE(status) ) {
             return;
         }
@@ -1392,7 +1612,10 @@ DateIntervalFormat::fgCalendarFieldToPatternLetter[] =
     /*wWd*/ LOW_W, CAP_W, LOW_D,
     /*DEF*/ CAP_D, CAP_E, CAP_F,
     /*ahH*/ LOW_A, LOW_H, CAP_H,
-    /*m..*/ LOW_M,
+    /*msS*/ LOW_M, LOW_S, CAP_S, // MINUTE, SECOND, MILLISECOND
+    /*z.Y*/ LOW_Z, SPACE, CAP_Y, // ZONE_OFFSET, DST_OFFSET, YEAR_WOY,
+    /*eug*/ LOW_E, LOW_U, LOW_G, // DOW_LOCAL, EXTENDED_YEAR, JULIAN_DAY,
+    /*A..*/ CAP_A, SPACE, SPACE, // MILLISECONDS_IN_DAY, IS_LEAP_MONTH, FIELD_COUNT
 };