mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-07 06:25:30 +00:00
ICU-11018 Support CLDR time separator (ICU4C)
This change will treat the ':' character in patterns as a symbol (instead of as a literal) and if the Locale defines timeSeparator then use that character instead when formatting and accept both when parsing. It will also define the '.' as an alternate time separator, that will be accepted when parsing in lenient mode. This is one character more strict than before, when in lenient mode also the '-' was accepted as time separator instead of ':'. R=rocketman@google.com Review URL: https://codereview.appspot.com/180610043 X-SVN-Rev: 36897
This commit is contained in:
parent
ea29e154b5
commit
17b8600e8e
12 changed files with 222 additions and 32 deletions
|
@ -30,6 +30,7 @@
|
|||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
#include "unicode/uchar.h"
|
||||
#include "unicode/gregocal.h"
|
||||
#include "unicode/basictz.h"
|
||||
#include "unicode/simpletz.h"
|
||||
|
@ -635,8 +636,9 @@ static const int32_t kCalendarLimits[UCAL_FIELD_COUNT][4] = {
|
|||
{ 1, 1, 7, 7 }, // DOW_LOCAL
|
||||
{/*N/A*/-1, /*N/A*/-1, /*N/A*/-1, /*N/A*/-1}, // EXTENDED_YEAR
|
||||
{ -0x7F000000, -0x7F000000, 0x7F000000, 0x7F000000 }, // JULIAN_DAY
|
||||
{ 0, 0, 24*kOneHour-1, 24*kOneHour-1 }, // MILLISECONDS_IN_DAY
|
||||
{ 0, 0, 1, 1 }, // IS_LEAP_MONTH
|
||||
{ 0, 0, 24*kOneHour-1, 24*kOneHour-1 }, // MILLISECONDS_IN_DAY
|
||||
{ 0, 0, 1, 1 }, // IS_LEAP_MONTH
|
||||
{ UCHAR_MIN_VALUE, UCHAR_MIN_VALUE, UCHAR_MAX_VALUE, UCHAR_MAX_VALUE }, // TIME_SEPARATOR
|
||||
};
|
||||
|
||||
// Resource bundle tags read by this class
|
||||
|
@ -2689,6 +2691,7 @@ int32_t Calendar::getLimit(UCalendarDateFields field, ELimitType limitType) cons
|
|||
case UCAL_JULIAN_DAY:
|
||||
case UCAL_MILLISECONDS_IN_DAY:
|
||||
case UCAL_IS_LEAP_MONTH:
|
||||
case UCAL_TIME_SEPARATOR:
|
||||
return kCalendarLimits[field][limitType];
|
||||
|
||||
case UCAL_WEEK_OF_MONTH:
|
||||
|
|
|
@ -23,9 +23,11 @@
|
|||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
#include "unicode/ustring.h"
|
||||
#include "unicode/localpointer.h"
|
||||
#include "unicode/dtfmtsym.h"
|
||||
#include "unicode/smpdtfmt.h"
|
||||
#include "unicode/msgfmt.h"
|
||||
#include "unicode/numsys.h"
|
||||
#include "unicode/tznames.h"
|
||||
#include "cpputils.h"
|
||||
#include "umutex.h"
|
||||
|
@ -49,18 +51,18 @@
|
|||
* resource data.
|
||||
*/
|
||||
|
||||
#define PATTERN_CHARS_LEN 35
|
||||
#define PATTERN_CHARS_LEN 36
|
||||
|
||||
/**
|
||||
* Unlocalized date-time pattern characters. For example: 'y', 'd', etc. All
|
||||
* locales use the same these unlocalized pattern characters.
|
||||
*/
|
||||
static const UChar gPatternChars[] = {
|
||||
// GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxr
|
||||
// GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxr:
|
||||
0x47, 0x79, 0x4D, 0x64, 0x6B, 0x48, 0x6D, 0x73, 0x53, 0x45,
|
||||
0x44, 0x46, 0x77, 0x57, 0x61, 0x68, 0x4B, 0x7A, 0x59, 0x65,
|
||||
0x75, 0x67, 0x41, 0x5A, 0x76, 0x63, 0x4c, 0x51, 0x71, 0x56,
|
||||
0x55, 0x4F, 0x58, 0x78, 0x72, 0
|
||||
0x55, 0x4F, 0x58, 0x78, 0x72, 0x3a, 0
|
||||
};
|
||||
|
||||
/* length of an array */
|
||||
|
@ -201,6 +203,9 @@ static const char gNamesStandaloneTag[]="stand-alone";
|
|||
static const char gNamesNumericTag[]="numeric";
|
||||
static const char gAmPmMarkersTag[]="AmPmMarkers";
|
||||
static const char gQuartersTag[]="quarters";
|
||||
static const char gNumberElementsTag[]="NumberElements";
|
||||
static const char gSymbolsTag[]="symbols";
|
||||
static const char gTimeSeparatorTag[]="timeSeparator";
|
||||
|
||||
// static const char gZoneStringsTag[]="zoneStrings";
|
||||
|
||||
|
@ -363,6 +368,7 @@ DateFormatSymbols::copyData(const DateFormatSymbols& other) {
|
|||
assignArray(fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount, other.fStandaloneShorterWeekdays, other.fStandaloneShorterWeekdaysCount);
|
||||
assignArray(fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, other.fStandaloneNarrowWeekdays, other.fStandaloneNarrowWeekdaysCount);
|
||||
assignArray(fAmPms, fAmPmsCount, other.fAmPms, other.fAmPmsCount);
|
||||
fTimeSeparator.fastCopyFrom(other.fTimeSeparator); // fastCopyFrom() - see assignArray comments
|
||||
assignArray(fQuarters, fQuartersCount, other.fQuarters, other.fQuartersCount);
|
||||
assignArray(fShortQuarters, fShortQuartersCount, other.fShortQuarters, other.fShortQuartersCount);
|
||||
assignArray(fStandaloneQuarters, fStandaloneQuartersCount, other.fStandaloneQuarters, other.fStandaloneQuartersCount);
|
||||
|
@ -541,6 +547,7 @@ DateFormatSymbols::operator==(const DateFormatSymbols& other) const
|
|||
arrayCompare(fStandaloneShorterWeekdays, other.fStandaloneShorterWeekdays, fStandaloneShorterWeekdaysCount) &&
|
||||
arrayCompare(fStandaloneNarrowWeekdays, other.fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount) &&
|
||||
arrayCompare(fAmPms, other.fAmPms, fAmPmsCount) &&
|
||||
fTimeSeparator == other.fTimeSeparator &&
|
||||
arrayCompare(fQuarters, other.fQuarters, fQuartersCount) &&
|
||||
arrayCompare(fShortQuarters, other.fShortQuarters, fShortQuartersCount) &&
|
||||
arrayCompare(fStandaloneQuarters, other.fStandaloneQuarters, fStandaloneQuartersCount) &&
|
||||
|
@ -776,6 +783,13 @@ DateFormatSymbols::getQuarters(int32_t &count, DtContextType context, DtWidthTyp
|
|||
return returnValue;
|
||||
}
|
||||
|
||||
UnicodeString&
|
||||
DateFormatSymbols::getTimeSeparatorString(UnicodeString& result) const
|
||||
{
|
||||
// fastCopyFrom() - see assignArray comments
|
||||
return result.fastCopyFrom(fTimeSeparator);
|
||||
}
|
||||
|
||||
const UnicodeString*
|
||||
DateFormatSymbols::getAmPmStrings(int32_t &count) const
|
||||
{
|
||||
|
@ -1165,6 +1179,12 @@ DateFormatSymbols::setAmPmStrings(const UnicodeString* amPmsArray, int32_t count
|
|||
fAmPmsCount = count;
|
||||
}
|
||||
|
||||
void
|
||||
DateFormatSymbols::setTimeSeparatorString(const UnicodeString& newTimeSeparator)
|
||||
{
|
||||
fTimeSeparator = newTimeSeparator;
|
||||
}
|
||||
|
||||
const UnicodeString**
|
||||
DateFormatSymbols::getZoneStrings(int32_t& rowCount, int32_t& columnCount) const
|
||||
{
|
||||
|
@ -1481,6 +1501,7 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
|
|||
fStandaloneNarrowWeekdaysCount=0;
|
||||
fAmPms = NULL;
|
||||
fAmPmsCount=0;
|
||||
fTimeSeparator.setToBogus();
|
||||
fQuarters = NULL;
|
||||
fQuartersCount = 0;
|
||||
fShortQuarters = NULL;
|
||||
|
@ -1628,9 +1649,34 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
|
|||
}
|
||||
ures_close(contextTransforms);
|
||||
}
|
||||
|
||||
tempStatus = U_ZERO_ERROR;
|
||||
const LocalPointer<NumberingSystem> numberingSystem(
|
||||
NumberingSystem::createInstance(locale, tempStatus), tempStatus);
|
||||
if (U_SUCCESS(tempStatus)) {
|
||||
// These functions all fail gracefully if passed NULL pointers and
|
||||
// do nothing unless U_SUCCESS(tempStatus), so it's only necessary
|
||||
// to check for errors once after all calls are made.
|
||||
const LocalUResourceBundlePointer numberElementsData(ures_getByKeyWithFallback(
|
||||
localeBundle, gNumberElementsTag, NULL, &tempStatus));
|
||||
const LocalUResourceBundlePointer nsNameData(ures_getByKeyWithFallback(
|
||||
numberElementsData.getAlias(), numberingSystem->getName(), NULL, &tempStatus));
|
||||
const LocalUResourceBundlePointer symbolsData(ures_getByKeyWithFallback(
|
||||
nsNameData.getAlias(), gSymbolsTag, NULL, &tempStatus));
|
||||
fTimeSeparator = ures_getUnicodeStringByKey(
|
||||
symbolsData.getAlias(), gTimeSeparatorTag, &tempStatus);
|
||||
if (U_FAILURE(tempStatus)) {
|
||||
fTimeSeparator.setToBogus();
|
||||
}
|
||||
}
|
||||
|
||||
ures_close(localeBundle);
|
||||
}
|
||||
|
||||
if (fTimeSeparator.isBogus()) {
|
||||
fTimeSeparator.setTo(DateFormatSymbols::DEFAULT_TIME_SEPARATOR);
|
||||
}
|
||||
|
||||
UResourceBundle *weekdaysData = NULL; // Data closed by calData
|
||||
UResourceBundle *abbrWeekdaysData = NULL; // Data closed by calData
|
||||
UResourceBundle *shorterWeekdaysData = NULL; // Data closed by calData
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 1997-2013, International Business Machines Corporation and
|
||||
* Copyright (C) 1997-2014, International Business Machines Corporation and
|
||||
* others. All Rights Reserved.
|
||||
*******************************************************************************
|
||||
*
|
||||
|
@ -99,6 +99,7 @@ static const int32_t kGregorianCalendarLimits[UCAL_FIELD_COUNT][4] = {
|
|||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
|
||||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY
|
||||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
|
||||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // TIME_SEPARATOR
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
static const UChar PATTERN_CHAR_BASE = 0x40;
|
||||
static const UChar PATTERN_CHAR_BASE = 0x3a;
|
||||
|
||||
/**
|
||||
* Last-resort string to use for "GMT" when constructing time zone strings.
|
||||
|
@ -140,8 +140,9 @@ static const UDateFormatField kTimeFields[] = {
|
|||
UDAT_HOUR0_FIELD,
|
||||
UDAT_MILLISECONDS_IN_DAY_FIELD,
|
||||
UDAT_TIMEZONE_RFC_FIELD,
|
||||
UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD };
|
||||
static const int8_t kTimeFieldsCount = 10;
|
||||
UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD,
|
||||
UDAT_TIME_SEPARATOR_FIELD };
|
||||
static const int8_t kTimeFieldsCount = 11;
|
||||
|
||||
|
||||
// This is a pattern-of-last-resort used when we can't load a usable pattern out
|
||||
|
@ -210,6 +211,7 @@ static const int32_t gFieldRangeBias[] = {
|
|||
-1, // 'X' - UDAT_TIMEZONE_ISO_FIELD
|
||||
-1, // 'x' - UDAT_TIMEZONE_ISO_LOCAL_FIELD
|
||||
-1, // 'r' - UDAT_RELATED_YEAR_FIELD
|
||||
-1, // ':' - UDAT_TIME_SEPARATOR_FIELD
|
||||
};
|
||||
|
||||
// When calendar uses hebr numbering (i.e. he@calendar=hebrew),
|
||||
|
@ -1030,8 +1032,9 @@ SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo,
|
|||
inQuote = ! inQuote;
|
||||
}
|
||||
}
|
||||
else if ( ! inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/)
|
||||
|| (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) {
|
||||
else if ( ! inQuote && ((ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/)
|
||||
|| (ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/)
|
||||
|| (ch == 0x003A /*':'*/))) {
|
||||
// ch is a date-time pattern character to be interpreted
|
||||
// by subFormat(); count the number of times it is repeated
|
||||
prevCh = ch;
|
||||
|
@ -1073,24 +1076,28 @@ SimpleDateFormat::fgCalendarFieldToLevel[] =
|
|||
/*sS*/ 70, 80,
|
||||
/*z?Y*/ 0, 0, 10,
|
||||
/*eug*/ 30, 10, 0,
|
||||
/*A?.*/ 40, 0, 0
|
||||
/*A?.*/ 40, 0, 0,
|
||||
/*:*/ 0
|
||||
};
|
||||
|
||||
|
||||
/* Map calendar field LETTER into calendar field level.
|
||||
* the larger the level, the smaller the field unit.
|
||||
* NOTE: if new fields adds in, the table needs to update.
|
||||
* PATTERN_CHAR_BASE is the codepoint of the first entry in this array.
|
||||
*/
|
||||
const int32_t
|
||||
SimpleDateFormat::fgPatternCharToLevel[] = {
|
||||
// A B C D E F G H I J K L M N O
|
||||
// : ; < = > ?
|
||||
0, -1, -1, -1, -1, -1,
|
||||
// @ A B C D E F G H I J K L M N O
|
||||
-1, 40, -1, -1, 20, 30, 30, 0, 50, -1, -1, 50, 20, 20, -1, 0,
|
||||
// P Q R S T U V W X Y Z
|
||||
// P Q R S T U V W X Y Z [ \ ] ^ _
|
||||
-1, 20, -1, 80, -1, 10, 0, 30, 0, 10, 0, -1, -1, -1, -1, -1,
|
||||
// a b c d e f g h i j k l m n o
|
||||
-1, 40, -1, 30, 30, 30, -1, 0, 50, -1, -1, 50, -1, 60, -1, -1,
|
||||
// p q r s t u v w x y z
|
||||
-1, 20, 10, 70, -1, 10, 0, 20, 0, 10, 0, -1, -1, -1, -1, -1
|
||||
-1, 20, 10, 70, -1, 10, 0, 20, 0, 10, 0
|
||||
};
|
||||
|
||||
|
||||
|
@ -1116,6 +1123,7 @@ SimpleDateFormat::fgPatternIndexToCalendarField[] =
|
|||
/*O*/ UCAL_ZONE_OFFSET,
|
||||
/*Xx*/ UCAL_ZONE_OFFSET, UCAL_ZONE_OFFSET,
|
||||
/*r*/ UCAL_EXTENDED_YEAR,
|
||||
/*:*/ UCAL_TIME_SEPARATOR,
|
||||
};
|
||||
|
||||
// Map index into pattern character string to DateFormat field number
|
||||
|
@ -1139,6 +1147,7 @@ SimpleDateFormat::fgPatternIndexToDateFormatField[] = {
|
|||
/*O*/ UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD,
|
||||
/*Xx*/ UDAT_TIMEZONE_ISO_FIELD, UDAT_TIMEZONE_ISO_LOCAL_FIELD,
|
||||
/*r*/ UDAT_RELATED_YEAR_FIELD,
|
||||
/*:*/ UDAT_TIME_SEPARATOR_FIELD,
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
@ -1570,6 +1579,14 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
|
|||
fSymbols->fAmPmsCount);
|
||||
break;
|
||||
|
||||
// for ":", write out the time separator string
|
||||
case UDAT_TIME_SEPARATOR_FIELD:
|
||||
{
|
||||
UnicodeString separator;
|
||||
appendTo += fSymbols->getTimeSeparatorString(separator);
|
||||
}
|
||||
break;
|
||||
|
||||
// for "h" and "hh", write out the hour, adjusting noon and midnight to show up
|
||||
// as "12"
|
||||
case UDAT_HOUR1_FIELD:
|
||||
|
@ -1937,7 +1954,9 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
|
|||
UChar ch = fPattern.charAt(i);
|
||||
|
||||
// Handle alphabetic field characters.
|
||||
if (!inQuote && ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) { // [A-Za-z]
|
||||
if (!inQuote && ((ch >= 0x41 && ch <= 0x5A)
|
||||
|| (ch >= 0x61 && ch <= 0x7A)
|
||||
|| (ch == 0x3A))) { // [A-Za-z:]
|
||||
int32_t fieldPat = i;
|
||||
|
||||
// Count the length of this field specifier
|
||||
|
@ -2329,7 +2348,9 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
|
|||
for ( ; i < pattern.length(); i += 1) {
|
||||
UChar ch = pattern.charAt(i);
|
||||
|
||||
if (!inQuote && ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) { // unquoted [A-Za-z]
|
||||
if (!inQuote && ((ch >= 0x41 && ch <= 0x5A)
|
||||
|| (ch >= 0x61 && ch <= 0x7A)
|
||||
|| (ch == 0x3A))) { // unquoted [A-Za-z:]
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3236,6 +3257,28 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
|
|||
}
|
||||
return -start;
|
||||
}
|
||||
case UDAT_TIME_SEPARATOR_FIELD: // ':'
|
||||
{
|
||||
static const UChar def_sep = DateFormatSymbols::DEFAULT_TIME_SEPARATOR;
|
||||
static const UChar alt_sep = DateFormatSymbols::ALTERNATE_TIME_SEPARATOR;
|
||||
|
||||
// Try matching a time separator.
|
||||
int32_t count = 1;
|
||||
UnicodeString data[3];
|
||||
fSymbols->getTimeSeparatorString(data[0]);
|
||||
|
||||
// Add the default, if different from the locale.
|
||||
if (data[0].compare(&def_sep, 1) != 0) {
|
||||
data[count++].setTo(def_sep);
|
||||
}
|
||||
|
||||
// If lenient, add also the alternate, if different from the locale.
|
||||
if (isLenient() && data[0].compare(&alt_sep, 1) != 0) {
|
||||
data[count++].setTo(alt_sep);
|
||||
}
|
||||
|
||||
return matchString(text, start, UCAL_TIME_SEPARATOR, data, count, NULL, cal);
|
||||
}
|
||||
|
||||
default:
|
||||
// Handle "generic" fields
|
||||
|
@ -3395,8 +3438,9 @@ void SimpleDateFormat::translatePattern(const UnicodeString& originalPattern,
|
|||
else {
|
||||
if (c == QUOTE)
|
||||
inQuote = TRUE;
|
||||
else if ((c >= 0x0061 /*'a'*/ && c <= 0x007A) /*'z'*/
|
||||
|| (c >= 0x0041 /*'A'*/ && c <= 0x005A /*'Z'*/)) {
|
||||
else if ((c >= 0x0041 /*'A'*/ && c <= 0x005A /*'Z'*/)
|
||||
|| (c >= 0x0061 /*'a'*/ && c <= 0x007A /*'z'*/)
|
||||
|| (c == 0x003A /*':'*/)) {
|
||||
int32_t ci = from.indexOf(c);
|
||||
if (ci == -1) {
|
||||
status = U_INVALID_FORMAT_ERROR;
|
||||
|
@ -3581,8 +3625,9 @@ SimpleDateFormat::isFieldUnitIgnored(const UnicodeString& pattern,
|
|||
inQuote = ! inQuote;
|
||||
}
|
||||
}
|
||||
else if ( ! inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/)
|
||||
|| (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) {
|
||||
else if ( ! inQuote && ((ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/)
|
||||
|| (ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/)
|
||||
|| (ch == 0x003A /*':'*/))) {
|
||||
prevCh = ch;
|
||||
++count;
|
||||
}
|
||||
|
|
|
@ -408,6 +408,36 @@ public:
|
|||
*/
|
||||
void setAmPmStrings(const UnicodeString* ampms, int32_t count);
|
||||
|
||||
#ifndef U_HIDE_INTERNAL_API
|
||||
/**
|
||||
* This default time separator is used for formatting when the locale
|
||||
* doesn't specify any time separator, and always recognized when parsing.
|
||||
* @internal
|
||||
*/
|
||||
static const UChar DEFAULT_TIME_SEPARATOR = 0x003a; // ':'
|
||||
|
||||
/**
|
||||
* This alternate time separator is always recognized when parsing.
|
||||
* @internal
|
||||
*/
|
||||
static const UChar ALTERNATE_TIME_SEPARATOR = 0x002e; // '.'
|
||||
|
||||
/**
|
||||
* Gets the time separator string. For example: ":".
|
||||
* @param result Output param which will receive the time separator string.
|
||||
* @return A reference to 'result'.
|
||||
* @internal
|
||||
*/
|
||||
UnicodeString& getTimeSeparatorString(UnicodeString& result) const;
|
||||
|
||||
/**
|
||||
* Sets the time separator string. For example: ":".
|
||||
* @param newTimeSeparator the new time separator string.
|
||||
* @internal
|
||||
*/
|
||||
void setTimeSeparatorString(const UnicodeString& newTimeSeparator);
|
||||
#endif /* U_HIDE_INTERNAL_API */
|
||||
|
||||
#ifndef U_HIDE_DRAFT_API
|
||||
/**
|
||||
* Gets cyclic year name strings if the calendar has them, by width and context.
|
||||
|
@ -710,6 +740,11 @@ private:
|
|||
UnicodeString* fAmPms;
|
||||
int32_t fAmPmsCount;
|
||||
|
||||
/**
|
||||
* Time separator string. For example: ":".
|
||||
*/
|
||||
UnicodeString fTimeSeparator;
|
||||
|
||||
/**
|
||||
* Quarter strings. For example: "1st quarter", "2nd quarter", etc.
|
||||
*/
|
||||
|
|
|
@ -422,7 +422,18 @@ enum UCalendarDateFields {
|
|||
* an example of this.
|
||||
*/
|
||||
UCAL_IS_LEAP_MONTH,
|
||||
|
||||
|
||||
/**
|
||||
* Field number indicating the separator between
|
||||
* <code>HOUR</code>, <code>MINUTE</code> and <code>SECOND</code>.
|
||||
* E.g., at 10:04 the <code>TIME_SEPARATOR</code> is <code>:</code>.
|
||||
* @see #UCAL_HOUR
|
||||
* @see #UCAL_MINUTE
|
||||
* @see #UCAL_SECOND
|
||||
* @internal
|
||||
*/
|
||||
UCAL_TIME_SEPARATOR,
|
||||
|
||||
/**
|
||||
* Field count
|
||||
* @stable ICU 2.6
|
||||
|
|
|
@ -758,6 +758,13 @@ typedef enum UDateFormatField {
|
|||
* @internal ICU 53
|
||||
*/
|
||||
UDAT_RELATED_YEAR_FIELD = 34,
|
||||
|
||||
/**
|
||||
* FieldPosition and UFieldPosition selector for ':' time separator,
|
||||
* corresponding to the UCAL_TIME_SEPARATOR field.
|
||||
* @internal
|
||||
*/
|
||||
UDAT_TIME_SEPARATOR_FIELD = 35,
|
||||
#endif /* U_HIDE_INTERNAL_API */
|
||||
|
||||
/**
|
||||
|
@ -768,7 +775,7 @@ typedef enum UDateFormatField {
|
|||
* in the future.
|
||||
* @stable ICU 3.0
|
||||
*/
|
||||
UDAT_FIELD_COUNT = 35
|
||||
UDAT_FIELD_COUNT = 36
|
||||
|
||||
} UDateFormatField;
|
||||
|
||||
|
|
|
@ -673,7 +673,7 @@ static void TestSymbols()
|
|||
VerifygetSymbols(zhChiCal, UDAT_CYCLIC_YEARS_NARROW, 59, "\\u7678\\u4EA5");
|
||||
VerifygetSymbols(zhChiCal, UDAT_ZODIAC_NAMES_ABBREVIATED, 0, "\\u9F20");
|
||||
VerifygetSymbols(zhChiCal, UDAT_ZODIAC_NAMES_WIDE, 11, "\\u732A");
|
||||
VerifygetSymbols(def,UDAT_LOCALIZED_CHARS, 0, "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxr");
|
||||
VerifygetSymbols(def,UDAT_LOCALIZED_CHARS, 0, "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxr:");
|
||||
|
||||
|
||||
if(result != NULL) {
|
||||
|
|
|
@ -1531,7 +1531,7 @@ void DateFormatRegressionTest::TestParsing(void) {
|
|||
|
||||
void DateFormatRegressionTest::TestT10334(void) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
UnicodeString pattern("--: EEE-WW-MMMM-yyyy");
|
||||
UnicodeString pattern("'--: 'EEE-WW-MMMM-yyyy");
|
||||
UnicodeString text("--mon-02-march-2011");
|
||||
SimpleDateFormat format(pattern, status);
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ void DateFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &nam
|
|||
TESTCASE_AUTO(TestDateFormatZone061);
|
||||
TESTCASE_AUTO(TestDateFormatZone146);
|
||||
TESTCASE_AUTO(TestLocaleDateFormat);
|
||||
TESTCASE_AUTO(TestFormattingLocaleTimeSeparator);
|
||||
TESTCASE_AUTO(TestWallyWedel);
|
||||
TESTCASE_AUTO(TestDateFormatCalendar);
|
||||
TESTCASE_AUTO(TestSpaceParsing);
|
||||
|
@ -432,7 +433,7 @@ DateFormatTest::escape(UnicodeString& s)
|
|||
/**
|
||||
* This MUST be kept in sync with DateFormatSymbols.gPatternChars.
|
||||
*/
|
||||
static const char* PATTERN_CHARS = "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxr";
|
||||
static const char* PATTERN_CHARS = "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxr:";
|
||||
|
||||
/**
|
||||
* A list of the names of all the fields in DateFormat.
|
||||
|
@ -474,6 +475,7 @@ static const char* DATEFORMAT_FIELD_NAMES[] = {
|
|||
"TIMEZONE_ISO_FIELD",
|
||||
"TIMEZONE_ISO_LOCAL_FIELD",
|
||||
"RELATED_YEAR_FIELD",
|
||||
"UDAT_TIME_SEPARATOR_FIELD",
|
||||
};
|
||||
|
||||
static const int32_t DATEFORMAT_FIELD_NAMES_LENGTH =
|
||||
|
@ -529,22 +531,22 @@ void DateFormatTest::TestFieldPosition() {
|
|||
"", "1997", "August", "13", "", "", "34", "12", "", "Wednesday",
|
||||
"", "", "", "", "PM", "2", "", "Pacific Daylight Time", "", "",
|
||||
"", "", "", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "",
|
||||
"", "", "", "", "", ":",
|
||||
|
||||
"", "1997", "ao\\u00FBt", "13", "", "14", "34", "12", "", "mercredi",
|
||||
"", "", "", "", "", "", "", "heure d\\u2019\\u00E9t\\u00E9 du Pacifique", "", "",
|
||||
"", "", "", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "",
|
||||
"", "", "", "", "", ":",
|
||||
|
||||
"AD", "1997", "8", "13", "14", "14", "34", "12", "5", "Wed",
|
||||
"225", "2", "33", "3", "PM", "2", "2", "PDT", "1997", "4",
|
||||
"1997", "2450674", "52452513", "-0700", "PT", "4", "8", "3", "3", "uslax",
|
||||
"1997", "GMT-7", "-07", "-07", "1997",
|
||||
"1997", "GMT-7", "-07", "-07", "1997", ":",
|
||||
|
||||
"Anno Domini", "1997", "August", "0013", "0014", "0014", "0034", "0012", "5130", "Wednesday",
|
||||
"0225", "0002", "0033", "0003", "PM", "0002", "0002", "Pacific Daylight Time", "1997", "Wednesday",
|
||||
"1997", "2450674", "52452513", "GMT-07:00", "Pacific Time", "Wednesday", "August", "3rd quarter", "3rd quarter", "Los Angeles Time",
|
||||
"1997", "GMT-07:00", "-0700", "-0700","1997",
|
||||
"1997", "GMT-07:00", "-0700", "-0700", "1997", ":",
|
||||
};
|
||||
|
||||
const int32_t EXPECTED_LENGTH = sizeof(EXPECTED)/sizeof(EXPECTED[0]);
|
||||
|
@ -1313,6 +1315,44 @@ DateFormatTest::TestLocaleDateFormat() // Bug 495
|
|||
delete dfFrench;
|
||||
}
|
||||
|
||||
void
|
||||
DateFormatTest::TestFormattingLocaleTimeSeparator()
|
||||
{
|
||||
const UDate testDate = 874266720000.; // Sun Sep 14 21:52:00 CET 1997
|
||||
logln((UnicodeString)"Date set to : " + dateToString(testDate));
|
||||
|
||||
const LocalPointer<const TimeZone> tz(TimeZone::createTimeZone("CET"));
|
||||
|
||||
const LocalPointer<DateFormat> dfArab(DateFormat::createTimeInstance(
|
||||
DateFormat::SHORT, Locale("ar")));
|
||||
|
||||
const LocalPointer<DateFormat> dfLatn(DateFormat::createTimeInstance(
|
||||
DateFormat::SHORT, Locale("ar", NULL, NULL, "numbers=latn")));
|
||||
|
||||
if (dfLatn.isNull() || dfArab.isNull()) {
|
||||
dataerrln("Error calling DateFormat::createTimeInstance()");
|
||||
return;
|
||||
}
|
||||
|
||||
dfArab->setTimeZone(*tz);
|
||||
dfLatn->setTimeZone(*tz);
|
||||
|
||||
const UnicodeString expectedArab = UnicodeString(
|
||||
"\\u0669\\u060C\\u0665\\u0662 \\u0645", -1, US_INV).unescape();
|
||||
|
||||
const UnicodeString expectedLatn = UnicodeString(
|
||||
"9:52 \\u0645", -1, US_INV).unescape();
|
||||
|
||||
UnicodeString actualArab;
|
||||
UnicodeString actualLatn;
|
||||
|
||||
dfArab->format(testDate, actualArab);
|
||||
dfLatn->format(testDate, actualLatn);
|
||||
|
||||
assertEquals("Arab", expectedArab, actualArab);
|
||||
assertEquals("Latn", expectedLatn, actualLatn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test DateFormat(Calendar) API
|
||||
*/
|
||||
|
@ -1425,7 +1465,6 @@ void DateFormatTest::TestSpaceParsing() {
|
|||
"hh:mm:ss a", "12:34:56 PM", "1970 01 01 12:34:56",
|
||||
NULL, "12:34:56PM", "1970 01 01 12:34:56",
|
||||
NULL, "12.34.56PM", "1970 01 01 12:34:56",
|
||||
NULL, "12-34-56 PM", "1970 01 01 12:34:56",
|
||||
NULL, "12 : 34 : 56 PM", "1970 01 01 12:34:56",
|
||||
|
||||
"MM d yy 'at' hh:mm:ss a", "04/05/06 12:34:56 PM", "2006 04 05 12:34:56",
|
||||
|
|
|
@ -150,6 +150,8 @@ public: // package
|
|||
*/
|
||||
virtual void TestLocaleDateFormat(void);
|
||||
|
||||
virtual void TestFormattingLocaleTimeSeparator(void);
|
||||
|
||||
virtual void TestDateFormatCalendar(void);
|
||||
|
||||
virtual void TestSpaceParsing(void);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/********************************************************************
|
||||
* COPYRIGHT:
|
||||
* Copyright (c) 2007-2013, International Business Machines Corporation and
|
||||
* Copyright (c) 2007-2014, International Business Machines Corporation and
|
||||
* others. All Rights Reserved.
|
||||
********************************************************************/
|
||||
|
||||
|
@ -106,6 +106,7 @@ static const Field names_UCalendarDateFields[] =
|
|||
FIELD_NAME_STR( LEN_UCAL, UCAL_JULIAN_DAY ),
|
||||
FIELD_NAME_STR( LEN_UCAL, UCAL_MILLISECONDS_IN_DAY ),
|
||||
FIELD_NAME_STR( LEN_UCAL, UCAL_IS_LEAP_MONTH ),
|
||||
FIELD_NAME_STR( LEN_UCAL, UCAL_TIME_SEPARATOR ),
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue