ICU-11872 new time formatting pattern chars b/B

Merging from the branch.

X-SVN-Rev: 38370
This commit is contained in:
kazède king 2016-02-25 19:51:53 +00:00
parent 15ed0f801d
commit f713c0687c
18 changed files with 2044 additions and 406 deletions

View file

@ -18,7 +18,7 @@
#define __LOCALPOINTER_H__
/**
* \file
* \file
* \brief C++ API: "Smart pointers" for use with and in ICU4C C++ code.
*
* These classes are inspired by
@ -52,7 +52,7 @@ U_NAMESPACE_BEGIN
* Destructor and adoptInstead().
*
* There is no operator T *() provided because the programmer must decide
* whether to use getAlias() (without transfer of ownership) or orpan()
* whether to use getAlias() (without transfer of ownership) or orphan()
* (with transfer of ownership and NULLing of the pointer).
*
* @see LocalPointer

View file

@ -12,7 +12,7 @@
* 04/01/97 aliu Creation.
* 02/22/99 damiba overhaul.
* 04/04/99 helena Fixed internal header inclusion.
* 04/15/99 Madhu Updated Javadoc
* 04/15/99 Madhu Updated Javadoc
* 06/14/99 stephen Removed functions taking a filename suffix.
* 07/20/99 stephen Language-independent ypedef to void*
* 11/09/99 weiv Added ures_getLocale()
@ -29,7 +29,7 @@
/**
* \file
* \brief C API: Resource Bundle
* \brief C API: Resource Bundle
*
* <h2>C API: Resource Bundle</h2>
*
@ -40,7 +40,7 @@
* <P>
* Resource bundles in ICU4C are currently defined using text files which conform to the following
* <a href="http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt">BNF definition</a>.
* More on resource bundle concepts and syntax can be found in the
* More on resource bundle concepts and syntax can be found in the
* <a href="http://icu-project.org/userguide/ResourceManagement.html">Users Guide</a>.
* <P>
*/
@ -801,6 +801,7 @@ U_NAMESPACE_BEGIN
*/
inline UnicodeString
ures_getUnicodeString(const UResourceBundle *resB, UErrorCode* status) {
UnicodeString result;
UnicodeString result;
int32_t len = 0;
const UChar *r = ures_getString(resB, &len, status);
@ -848,6 +849,7 @@ ures_getNextUnicodeString(UResourceBundle *resB, const char ** key, UErrorCode*
*/
inline UnicodeString
ures_getUnicodeStringByIndex(const UResourceBundle *resB, int32_t indexS, UErrorCode* status) {
UnicodeString result;
UnicodeString result;
int32_t len = 0;
const UChar* r = ures_getStringByIndex(resB, indexS, &len, status);
@ -871,6 +873,7 @@ ures_getUnicodeStringByIndex(const UResourceBundle *resB, int32_t indexS, UError
*/
inline UnicodeString
ures_getUnicodeStringByKey(const UResourceBundle *resB, const char* key, UErrorCode* status) {
UnicodeString result;
UnicodeString result;
int32_t len = 0;
const UChar* r = ures_getStringByKey(resB, key, &len, status);

View file

@ -1,6 +1,6 @@
/*
**********************************************************************
* Copyright (C) 1999-2013, International Business Machines
* Copyright (C) 1999-2016, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Date Name Description
@ -59,7 +59,7 @@ U_NAMESPACE_BEGIN
*
* <p>In order to implement methods such as contains() and indexOf(),
* UVector needs a way to compare objects for equality. To do so, it
* uses a comparison frunction, or "comparer." If the comparer is not
* uses a comparison function, or "comparer." If the comparer is not
* set, or is set to zero, then all such methods will act as if the
* vector contains no element. That is, indexOf() will always return
* -1, contains() will always return FALSE, etc.

View file

@ -99,7 +99,7 @@ sharedbreakiterator.o scientificnumberformatter.o digitgrouping.o \
digitinterval.o digitformatter.o digitaffix.o valueformatter.o \
digitaffixesandpadding.o pluralaffix.o precision.o \
affixpatternparser.o smallintformatter.o decimfmtimpl.o \
visibledigits.o
visibledigits.o dayperiodrules.o
## Header files to install
HEADERS = $(srcdir)/unicode/*.h

View file

@ -0,0 +1,547 @@
/*
*******************************************************************************
* Copyright (C) 2016, International Business Machines
* Corporation and others. All Rights Reserved.
*******************************************************************************
* dayperiodrules.cpp
*
* created on: 2016-01-20
* created by: kazede
*/
#include "dayperiodrules.h"
#include "unicode/ures.h"
#include "cstr.h"
#include "cstring.h"
#include "ucln_in.h"
#include "uhash.h"
#include "umutex.h"
#include "uresimp.h"
U_NAMESPACE_BEGIN
namespace {
struct DayPeriodRulesData {
DayPeriodRulesData() : localeToRuleSetNumMap(NULL), rules(NULL), maxRuleSetNum(0) {}
UHashtable *localeToRuleSetNumMap;
DayPeriodRules *rules;
int32_t maxRuleSetNum;
} *data = NULL;
enum CutoffType {
CUTOFF_TYPE_UNKNOWN = -1,
CUTOFF_TYPE_BEFORE,
CUTOFF_TYPE_AFTER, // TODO: AFTER is deprecated in CLDR 29. Remove.
CUTOFF_TYPE_FROM,
CUTOFF_TYPE_AT,
};
} // namespace
struct DayPeriodRulesDataSink : public ResourceTableSink {
// Initialize sub-sinks.
DayPeriodRulesDataSink() :
rulesSink(*this), ruleSetSink(*this), periodSink(*this), cutoffSink(*this) {
for (int32_t i = 0; i < UPRV_LENGTHOF(cutoffs); ++i) { cutoffs[i] = 0; }
}
virtual ~DayPeriodRulesDataSink();
// Entry point.
virtual ResourceTableSink *getOrCreateTableSink(const char *key, int32_t, UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return NULL; }
if (uprv_strcmp(key, "locales") == 0) {
return &localesSink;
} else if (uprv_strcmp(key, "rules") == 0) {
// Allocate one more than needed to skip [0]. See comment in parseSetNum().
data->rules = new DayPeriodRules[data->maxRuleSetNum + 1];
if (data->rules == NULL) {
errorCode = U_MEMORY_ALLOCATION_ERROR;
return NULL;
} else {
return &rulesSink;
}
}
return NULL;
}
// Data root -> locales.
struct LocalesSink : public ResourceTableSink {
virtual ~LocalesSink();
virtual void put(const char *key, const ResourceValue &value, UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return; }
UnicodeString setNum_str = value.getUnicodeString(errorCode);
int32_t setNum = parseSetNum(setNum_str, errorCode);
uhash_puti(data->localeToRuleSetNumMap, const_cast<char *>(key), setNum, &errorCode);
}
} localesSink;
// Data root -> rules.
struct RulesSink : public ResourceTableSink {
DayPeriodRulesDataSink &outer;
RulesSink(DayPeriodRulesDataSink &outer) : outer(outer) {}
virtual ~RulesSink();
virtual ResourceTableSink *getOrCreateTableSink(const char *key, int32_t, UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return NULL; }
outer.ruleSetNum = parseSetNum(key, errorCode);
return &outer.ruleSetSink;
}
} rulesSink;
// Data root -> rules -> a rule set.
struct RuleSetSink : public ResourceTableSink {
DayPeriodRulesDataSink &outer;
RuleSetSink(DayPeriodRulesDataSink &outer) : outer(outer) {}
virtual ~RuleSetSink();
virtual ResourceTableSink *getOrCreateTableSink(const char *key, int32_t, UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return NULL; }
outer.period = DayPeriodRules::getDayPeriodFromString(key);
if (outer.period == DayPeriodRules::DAYPERIOD_UNKNOWN) {
errorCode = U_INVALID_FORMAT_ERROR;
return NULL;
}
return &outer.periodSink;
}
virtual void leave(UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return; }
if (!data->rules[outer.ruleSetNum].allHoursAreSet()) {
errorCode = U_INVALID_FORMAT_ERROR;
}
}
} ruleSetSink;
// Data root -> rules -> a rule set -> a period (e.g. "morning1").
// Key-value pairs (e.g. before{6:00}) will be captured here.
// Arrays (e.g. before{6:00, 24:00}) will be redirected to the next sink.
struct PeriodSink : public ResourceTableSink {
DayPeriodRulesDataSink &outer;
PeriodSink(DayPeriodRulesDataSink &outer) : outer(outer) {}
virtual ~PeriodSink();
virtual void put(const char *key, const ResourceValue &value, UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return; }
CutoffType type = getCutoffTypeFromString(key);
outer.addCutoff(type, value.getUnicodeString(errorCode), errorCode);
}
virtual ResourceArraySink *getOrCreateArraySink(const char *key, int32_t, UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return NULL; }
outer.cutoffType = getCutoffTypeFromString(key);
return &outer.cutoffSink;
}
virtual void leave(UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return; }
outer.setDayPeriodForHoursFromCutoffs(errorCode);
for (int32_t i = 0; i < UPRV_LENGTHOF(outer.cutoffs); ++i) {
outer.cutoffs[i] = 0;
}
}
} periodSink;
// Data root -> rules -> a rule set -> a period -> a cutoff type.
// Will enter this sink if 2+ times appear in a single cutoff type (e.g. before{6:00, 24:00}).
struct CutoffSink : public ResourceArraySink {
DayPeriodRulesDataSink &outer;
CutoffSink(DayPeriodRulesDataSink &outer) : outer(outer) {}
virtual ~CutoffSink();
virtual void put(int32_t, const ResourceValue &value, UErrorCode &errorCode) {
outer.addCutoff(outer.cutoffType, value.getUnicodeString(errorCode), errorCode);
}
} cutoffSink;
// Members.
int32_t cutoffs[25]; // [0] thru [24]: 24 is allowed in "before 24".
// "Path" to data.
int32_t ruleSetNum;
DayPeriodRules::DayPeriod period;
CutoffType cutoffType;
// Helpers.
static int32_t parseSetNum(const UnicodeString &setNumStr, UErrorCode &errorCode) {
return parseSetNum(CStr(setNumStr)(), errorCode);
}
static int32_t parseSetNum(const char *setNumStr, UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return -1; }
if (uprv_strncmp(setNumStr, "set", 3) != 0) {
errorCode = U_INVALID_FORMAT_ERROR;
return -1;
}
int32_t i = 3;
int32_t setNum = 0;
while (setNumStr[i] != 0) {
int32_t digit = setNumStr[i] - '0';
if (digit < 0 || 9 < digit) {
errorCode = U_INVALID_FORMAT_ERROR;
return -1;
}
setNum = 10 * setNum + digit;
++i;
}
// Rule set number must not be zero. (0 is used to indicate "not found" by hashmap.)
// Currently ICU data conveniently starts numbering rule sets from 1.
if (setNum == 0) {
errorCode = U_INVALID_FORMAT_ERROR;
return -1;
} else {
return setNum;
}
}
void addCutoff(CutoffType type, UnicodeString hour_str, UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return; }
if (type == CUTOFF_TYPE_UNKNOWN) {
errorCode = U_INVALID_FORMAT_ERROR;
return;
}
int32_t hour = parseHour(hour_str, errorCode);
if (U_FAILURE(errorCode)) { return; }
cutoffs[hour] |= 1 << type;
}
// Translate the cutoffs[] array to day period rules.
void setDayPeriodForHoursFromCutoffs(UErrorCode &errorCode) {
DayPeriodRules &rule = data->rules[ruleSetNum];
for (int32_t startHour = 0; startHour <= 24; ++startHour) {
// AT cutoffs must be either midnight or noon.
if (cutoffs[startHour] & (1 << CUTOFF_TYPE_AT)) {
if (startHour == 0 && period == DayPeriodRules::DAYPERIOD_MIDNIGHT) {
rule.fHasMidnight = TRUE;
} else if (startHour == 12 && period == DayPeriodRules::DAYPERIOD_NOON) {
rule.fHasNoon = TRUE;
} else {
errorCode = U_INVALID_FORMAT_ERROR; // Bad data.
return;
}
}
// FROM/AFTER and BEFORE must come in a pair.
if (cutoffs[startHour] & (1 << CUTOFF_TYPE_FROM) ||
cutoffs[startHour] & (1 << CUTOFF_TYPE_AFTER)) {
for (int32_t hour = startHour + 1;; ++hour) {
if (hour == startHour) {
// We've gone around the array once and can't find a BEFORE.
errorCode = U_INVALID_FORMAT_ERROR;
return;
}
if (hour == 25) { hour = 0; }
if (cutoffs[hour] & (1 << CUTOFF_TYPE_BEFORE)) {
rule.add(startHour, hour, period);
break;
}
}
}
}
}
// Translate "before" to CUTOFF_TYPE_BEFORE, for example.
static CutoffType getCutoffTypeFromString(const char *type_str) {
if (uprv_strcmp(type_str, "from") == 0) {
return CUTOFF_TYPE_FROM;
} else if (uprv_strcmp(type_str, "before") == 0) {
return CUTOFF_TYPE_BEFORE;
} else if (uprv_strcmp(type_str, "after") == 0) {
return CUTOFF_TYPE_AFTER;
} else if (uprv_strcmp(type_str, "at") == 0) {
return CUTOFF_TYPE_AT;
} else {
return CUTOFF_TYPE_UNKNOWN;
}
}
// Gets the numerical value of the hour from the Unicode string.
static int32_t parseHour(const UnicodeString &time, UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) {
return 0;
}
int32_t hourLimit = time.length() - 3;
// `time` must look like "x:00" or "xx:00".
// If length is wrong or `time` doesn't end with ":00", error out.
if ((hourLimit != 1 && hourLimit != 2) ||
time[hourLimit] != 0x3A || time[hourLimit + 1] != 0x30 ||
time[hourLimit + 2] != 0x30) {
errorCode = U_INVALID_FORMAT_ERROR;
return 0;
}
// If `time` doesn't begin with a number in [0, 24], error out.
// Note: "24:00" is possible in "before 24:00".
int32_t hour = time[0] - 0x30;
if (hour < 0 || 9 < hour) {
errorCode = U_INVALID_FORMAT_ERROR;
return 0;
}
if (hourLimit == 2) {
int32_t hourDigit2 = time[1] - 0x30;
if (hourDigit2 < 0 || 9 < hourDigit2) {
errorCode = U_INVALID_FORMAT_ERROR;
return 0;
}
hour = hour * 10 + hourDigit2;
if (hour > 24) {
errorCode = U_INVALID_FORMAT_ERROR;
return 0;
}
}
return hour;
}
}; // struct DayPeriodRulesDataSink
struct DayPeriodRulesCountSink : public ResourceTableSink {
virtual ResourceTableSink *getOrCreateTableSink(const char *key, int32_t, UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return NULL; }
int32_t setNum = DayPeriodRulesDataSink::parseSetNum(key, errorCode);
if (setNum > data->maxRuleSetNum) {
data->maxRuleSetNum = setNum;
}
return NULL;
}
};
// Out-of-line virtual destructors.
DayPeriodRulesDataSink::LocalesSink::~LocalesSink() {}
DayPeriodRulesDataSink::CutoffSink::~CutoffSink() {}
DayPeriodRulesDataSink::PeriodSink::~PeriodSink() {}
DayPeriodRulesDataSink::RuleSetSink::~RuleSetSink() {}
DayPeriodRulesDataSink::RulesSink::~RulesSink() {}
DayPeriodRulesDataSink::~DayPeriodRulesDataSink() {}
namespace {
UInitOnce initOnce = U_INITONCE_INITIALIZER;
UBool dayPeriodRulesCleanup() {
delete[] data->rules;
uhash_close(data->localeToRuleSetNumMap);
delete data;
data = NULL;
return TRUE;
}
} // namespace
void DayPeriodRules::load(UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) {
return;
}
data = new DayPeriodRulesData();
data->localeToRuleSetNumMap = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &errorCode);
LocalUResourceBundlePointer rb_dayPeriods(ures_openDirect(NULL, "dayPeriods", &errorCode));
// Get the largest rule set number (so we allocate enough objects).
DayPeriodRulesCountSink countSink;
ures_getAllTableItemsWithFallback(rb_dayPeriods.getAlias(), "rules", countSink, errorCode);
// Populate rules.
DayPeriodRulesDataSink sink;
ures_getAllTableItemsWithFallback(rb_dayPeriods.getAlias(), "", sink, errorCode);
ucln_i18n_registerCleanup(UCLN_I18N_DAYPERIODRULES, dayPeriodRulesCleanup);
}
const DayPeriodRules *DayPeriodRules::getInstance(const Locale &locale, UErrorCode &errorCode) {
umtx_initOnce(initOnce, DayPeriodRules::load, errorCode);
// If the entire day period rules data doesn't conform to spec (even if the part we want
// does), return NULL.
if(U_FAILURE(errorCode)) { return NULL; }
const char *localeCode = locale.getName();
char name[ULOC_FULLNAME_CAPACITY];
char parentName[ULOC_FULLNAME_CAPACITY];
if (uprv_strlen(localeCode) < ULOC_FULLNAME_CAPACITY) {
uprv_strcpy(name, localeCode);
// Treat empty string as root.
if (*name == '\0') {
uprv_strcpy(name, "root");
}
} else {
errorCode = U_BUFFER_OVERFLOW_ERROR;
return NULL;
}
int32_t ruleSetNum = 0; // NB there is no rule set 0 and 0 is returned upon lookup failure.
while (*name != '\0') {
ruleSetNum = uhash_geti(data->localeToRuleSetNumMap, name);
if (ruleSetNum == 0) {
// name and parentName can't be the same pointer, so fill in parent then copy to child.
uloc_getParent(name, parentName, ULOC_FULLNAME_CAPACITY, &errorCode);
if (*parentName == '\0') {
// Saves a lookup in the hash table.
break;
}
uprv_strcpy(name, parentName);
} else {
break;
}
}
if (ruleSetNum <= 0 || data->rules[ruleSetNum].getDayPeriodForHour(0) == DAYPERIOD_UNKNOWN) {
// If day period for hour 0 is UNKNOWN then day period for all hours are UNKNOWN.
// Data doesn't exist even with fallback.
return NULL;
} else {
return &data->rules[ruleSetNum];
}
}
DayPeriodRules::DayPeriodRules() : fHasMidnight(FALSE), fHasNoon(FALSE) {
for (int32_t i = 0; i < 24; ++i) {
fDayPeriodForHour[i] = DayPeriodRules::DAYPERIOD_UNKNOWN;
}
}
double DayPeriodRules::getMidPointForDayPeriod(
DayPeriodRules::DayPeriod dayPeriod, UErrorCode &errorCode) const {
if (U_FAILURE(errorCode)) { return -1; }
int32_t startHour = getStartHourForDayPeriod(dayPeriod, errorCode);
int32_t endHour = getEndHourForDayPeriod(dayPeriod, errorCode);
// Can't obtain startHour or endHour; bail out.
if (U_FAILURE(errorCode)) { return -1; }
double midPoint = (startHour + endHour) / 2.0;
if (startHour > endHour) {
// dayPeriod wraps around midnight. Shift midPoint by 12 hours, in the direction that
// lands it in [0, 24).
midPoint += 12;
if (midPoint >= 24) {
midPoint -= 24;
}
}
return midPoint;
}
int32_t DayPeriodRules::getStartHourForDayPeriod(
DayPeriodRules::DayPeriod dayPeriod, UErrorCode &errorCode) const {
if (U_FAILURE(errorCode)) { return -1; }
if (dayPeriod == DAYPERIOD_MIDNIGHT) { return 0; }
if (dayPeriod == DAYPERIOD_NOON) { return 12; }
if (fDayPeriodForHour[0] == dayPeriod && fDayPeriodForHour[23] == dayPeriod) {
// dayPeriod wraps around midnight. Start hour is later than end hour.
for (int32_t i = 22; i >= 1; --i) {
if (fDayPeriodForHour[i] != dayPeriod) {
return (i + 1);
}
}
} else {
for (int32_t i = 0; i <= 23; ++i) {
if (fDayPeriodForHour[i] == dayPeriod) {
return i;
}
}
}
// dayPeriod doesn't exist in rule set; set error and exit.
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
return -1;
}
int32_t DayPeriodRules::getEndHourForDayPeriod(
DayPeriodRules::DayPeriod dayPeriod, UErrorCode &errorCode) const {
if (U_FAILURE(errorCode)) { return -1; }
if (dayPeriod == DAYPERIOD_MIDNIGHT) { return 0; }
if (dayPeriod == DAYPERIOD_NOON) { return 12; }
if (fDayPeriodForHour[0] == dayPeriod && fDayPeriodForHour[23] == dayPeriod) {
// dayPeriod wraps around midnight. End hour is before start hour.
for (int32_t i = 1; i <= 22; ++i) {
if (fDayPeriodForHour[i] != dayPeriod) {
// i o'clock is when a new period starts, therefore when the old period ends.
return i;
}
}
} else {
for (int32_t i = 23; i >= 0; --i) {
if (fDayPeriodForHour[i] == dayPeriod) {
return (i + 1);
}
}
}
// dayPeriod doesn't exist in rule set; set error and exit.
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
return -1;
}
DayPeriodRules::DayPeriod DayPeriodRules::getDayPeriodFromString(const char *type_str) {
if (uprv_strcmp(type_str, "midnight") == 0) {
return DAYPERIOD_MIDNIGHT;
} else if (uprv_strcmp(type_str, "noon") == 0) {
return DAYPERIOD_NOON;
} else if (uprv_strcmp(type_str, "morning1") == 0) {
return DAYPERIOD_MORNING1;
} else if (uprv_strcmp(type_str, "afternoon1") == 0) {
return DAYPERIOD_AFTERNOON1;
} else if (uprv_strcmp(type_str, "evening1") == 0) {
return DAYPERIOD_EVENING1;
} else if (uprv_strcmp(type_str, "night1") == 0) {
return DAYPERIOD_NIGHT1;
} else if (uprv_strcmp(type_str, "morning2") == 0) {
return DAYPERIOD_MORNING2;
} else if (uprv_strcmp(type_str, "afternoon2") == 0) {
return DAYPERIOD_AFTERNOON2;
} else if (uprv_strcmp(type_str, "evening2") == 0) {
return DAYPERIOD_EVENING2;
} else if (uprv_strcmp(type_str, "night2") == 0) {
return DAYPERIOD_NIGHT2;
} else {
return DAYPERIOD_UNKNOWN;
}
}
void DayPeriodRules::add(int32_t startHour, int32_t limitHour, DayPeriod period) {
for (int32_t i = startHour; i != limitHour; ++i) {
if (i == 24) { i = 0; }
fDayPeriodForHour[i] = period;
}
}
UBool DayPeriodRules::allHoursAreSet() {
for (int32_t i = 0; i < 24; ++i) {
if (fDayPeriodForHour[i] == DAYPERIOD_UNKNOWN) { return FALSE; }
}
return TRUE;
}
U_NAMESPACE_END

View file

@ -0,0 +1,85 @@
/*
*******************************************************************************
* Copyright (C) 2016, International Business Machines
* Corporation and others. All Rights Reserved.
*******************************************************************************
* dayperiodrules.h
*
* created on: 2016-01-20
* created by: kazede
*/
#ifndef DAYPERIODRULES_H
#define DAYPERIODRULES_H
#include "unicode/locid.h"
#include "unicode/unistr.h"
#include "unicode/uobject.h"
#include "unicode/utypes.h"
#include "resource.h"
#include "uhash.h"
U_NAMESPACE_BEGIN
struct DayPeriodRulesDataSink;
class DayPeriodRules : public UMemory {
friend struct DayPeriodRulesDataSink;
public:
enum DayPeriod {
DAYPERIOD_UNKNOWN = -1,
DAYPERIOD_MIDNIGHT,
DAYPERIOD_NOON,
DAYPERIOD_MORNING1,
DAYPERIOD_AFTERNOON1,
DAYPERIOD_EVENING1,
DAYPERIOD_NIGHT1,
DAYPERIOD_MORNING2,
DAYPERIOD_AFTERNOON2,
DAYPERIOD_EVENING2,
DAYPERIOD_NIGHT2
};
static const DayPeriodRules *getInstance(const Locale &locale, UErrorCode &errorCode);
UBool hasMidnight() const { return fHasMidnight; }
UBool hasNoon() const { return fHasNoon; }
DayPeriod getDayPeriodForHour(int32_t hour) const { return fDayPeriodForHour[hour]; }
// Returns the center of dayPeriod. Half hours are indicated with a .5 .
double getMidPointForDayPeriod(DayPeriod dayPeriod, UErrorCode &errorCode) const;
private:
DayPeriodRules();
// Translates "morning1" to DAYPERIOD_MORNING1, for example.
static DayPeriod getDayPeriodFromString(const char *type_str);
static void load(UErrorCode &errorCode);
// Sets period type for all hours in [startHour, limitHour).
void add(int32_t startHour, int32_t limitHour, DayPeriod period);
// Returns TRUE if for all i, DayPeriodForHour[i] has a type other than UNKNOWN.
// Values of HasNoon and HasMidnight do not affect the return value.
UBool allHoursAreSet();
// Returns the hour that starts dayPeriod. Returns 0 for MIDNIGHT and 12 for NOON.
int32_t getStartHourForDayPeriod(DayPeriod dayPeriod, UErrorCode &errorCode) const;
// Returns the hour that ends dayPeriod, i.e. that starts the next period.
// E.g. if fDayPeriodForHour[13] thru [16] are AFTERNOON1, then this function returns 17 if
// queried with AFTERNOON1.
// Returns 0 for MIDNIGHT and 12 for NOON.
int32_t getEndHourForDayPeriod(DayPeriod dayPeriod, UErrorCode &errorCode) const;
UBool fHasMidnight;
UBool fHasNoon;
DayPeriod fDayPeriodForHour[24];
};
U_NAMESPACE_END
#endif /* DAYPERIODRULES_H */

View file

@ -1,7 +1,7 @@
/*
*******************************************************************************
* Copyright (C) 1997-2016, International Business Machines Corporation and
* others. All Rights Reserved.
* Copyright (C) 1997-2016, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
* File DTFMTSYM.CPP
@ -52,9 +52,9 @@
*/
#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
#define PATTERN_CHARS_LEN 36
#define PATTERN_CHARS_LEN 38
#else
#define PATTERN_CHARS_LEN 35
#define PATTERN_CHARS_LEN 37
#endif
/**
@ -62,19 +62,19 @@
* locales use the same these unlocalized pattern characters.
*/
static const UChar gPatternChars[] = {
#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
// GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxr:
#else
// GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxr
#endif
// if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR:
// GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB:
// else:
// GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB
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, 0x62, 0x42,
#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
0x55, 0x4F, 0x58, 0x78, 0x72, 0x3a, 0
#else
0x55, 0x4F, 0x58, 0x78, 0x72, 0
0x3a,
#endif
0
};
//------------------------------------------------------
@ -216,6 +216,7 @@ static const char gQuartersTag[]="quarters";
static const char gNumberElementsTag[]="NumberElements";
static const char gSymbolsTag[]="symbols";
static const char gTimeSeparatorTag[]="timeSeparator";
static const char gDayPeriodTag[]="dayPeriod";
// static const char gZoneStringsTag[]="zoneStrings";
@ -384,6 +385,18 @@ DateFormatSymbols::copyData(const DateFormatSymbols& other) {
assignArray(fShortQuarters, fShortQuartersCount, other.fShortQuarters, other.fShortQuartersCount);
assignArray(fStandaloneQuarters, fStandaloneQuartersCount, other.fStandaloneQuarters, other.fStandaloneQuartersCount);
assignArray(fStandaloneShortQuarters, fStandaloneShortQuartersCount, other.fStandaloneShortQuarters, other.fStandaloneShortQuartersCount);
assignArray(fWideDayPeriods, fWideDayPeriodsCount,
other.fWideDayPeriods, other.fWideDayPeriodsCount);
assignArray(fNarrowDayPeriods, fNarrowDayPeriodsCount,
other.fNarrowDayPeriods, other.fNarrowDayPeriodsCount);
assignArray(fAbbreviatedDayPeriods, fAbbreviatedDayPeriodsCount,
other.fAbbreviatedDayPeriods, other.fAbbreviatedDayPeriodsCount);
assignArray(fStandaloneWideDayPeriods, fStandaloneWideDayPeriodsCount,
other.fStandaloneWideDayPeriods, other.fStandaloneWideDayPeriodsCount);
assignArray(fStandaloneNarrowDayPeriods, fStandaloneNarrowDayPeriodsCount,
other.fStandaloneNarrowDayPeriods, other.fStandaloneNarrowDayPeriodsCount);
assignArray(fStandaloneAbbreviatedDayPeriods, fStandaloneAbbreviatedDayPeriodsCount,
other.fStandaloneAbbreviatedDayPeriods, other.fStandaloneAbbreviatedDayPeriodsCount);
if (other.fLeapMonthPatterns != NULL) {
assignArray(fLeapMonthPatterns, fLeapMonthPatternsCount, other.fLeapMonthPatterns, other.fLeapMonthPatternsCount);
} else {
@ -402,7 +415,7 @@ DateFormatSymbols::copyData(const DateFormatSymbols& other) {
fShortZodiacNames = NULL;
fShortZodiacNamesCount = 0;
}
if (other.fZoneStrings != NULL) {
fZoneStringsColCount = other.fZoneStringsColCount;
fZoneStringsRowCount = other.fZoneStringsRowCount;
@ -419,7 +432,7 @@ DateFormatSymbols::copyData(const DateFormatSymbols& other) {
// fastCopyFrom() - see assignArray comments
fLocalPatternChars.fastCopyFrom(other.fLocalPatternChars);
uprv_memcpy(fCapitalization, other.fCapitalization, sizeof(fCapitalization));
}
@ -441,32 +454,38 @@ DateFormatSymbols::~DateFormatSymbols()
void DateFormatSymbols::dispose()
{
if (fEras) delete[] fEras;
if (fEraNames) delete[] fEraNames;
if (fNarrowEras) delete[] fNarrowEras;
if (fMonths) delete[] fMonths;
if (fShortMonths) delete[] fShortMonths;
if (fNarrowMonths) delete[] fNarrowMonths;
if (fStandaloneMonths) delete[] fStandaloneMonths;
if (fStandaloneShortMonths) delete[] fStandaloneShortMonths;
if (fStandaloneNarrowMonths) delete[] fStandaloneNarrowMonths;
if (fWeekdays) delete[] fWeekdays;
if (fShortWeekdays) delete[] fShortWeekdays;
if (fShorterWeekdays) delete[] fShorterWeekdays;
if (fNarrowWeekdays) delete[] fNarrowWeekdays;
if (fStandaloneWeekdays) delete[] fStandaloneWeekdays;
if (fStandaloneShortWeekdays) delete[] fStandaloneShortWeekdays;
if (fStandaloneShorterWeekdays) delete[] fStandaloneShorterWeekdays;
if (fStandaloneNarrowWeekdays) delete[] fStandaloneNarrowWeekdays;
if (fAmPms) delete[] fAmPms;
if (fNarrowAmPms) delete[] fNarrowAmPms;
if (fQuarters) delete[] fQuarters;
if (fShortQuarters) delete[] fShortQuarters;
if (fStandaloneQuarters) delete[] fStandaloneQuarters;
if (fStandaloneShortQuarters) delete[] fStandaloneShortQuarters;
if (fLeapMonthPatterns) delete[] fLeapMonthPatterns;
if (fShortYearNames) delete[] fShortYearNames;
if (fShortZodiacNames) delete[] fShortZodiacNames;
delete[] fEras;
delete[] fEraNames;
delete[] fNarrowEras;
delete[] fMonths;
delete[] fShortMonths;
delete[] fNarrowMonths;
delete[] fStandaloneMonths;
delete[] fStandaloneShortMonths;
delete[] fStandaloneNarrowMonths;
delete[] fWeekdays;
delete[] fShortWeekdays;
delete[] fShorterWeekdays;
delete[] fNarrowWeekdays;
delete[] fStandaloneWeekdays;
delete[] fStandaloneShortWeekdays;
delete[] fStandaloneShorterWeekdays;
delete[] fStandaloneNarrowWeekdays;
delete[] fAmPms;
delete[] fNarrowAmPms;
delete[] fQuarters;
delete[] fShortQuarters;
delete[] fStandaloneQuarters;
delete[] fStandaloneShortQuarters;
delete[] fLeapMonthPatterns;
delete[] fShortYearNames;
delete[] fShortZodiacNames;
delete[] fAbbreviatedDayPeriods;
delete[] fWideDayPeriods;
delete[] fNarrowDayPeriods;
delete[] fStandaloneAbbreviatedDayPeriods;
delete[] fStandaloneWideDayPeriods;
delete[] fStandaloneNarrowDayPeriods;
disposeZoneStrings();
}
@ -539,6 +558,12 @@ DateFormatSymbols::operator==(const DateFormatSymbols& other) const
fLeapMonthPatternsCount == other.fLeapMonthPatternsCount &&
fShortYearNamesCount == other.fShortYearNamesCount &&
fShortZodiacNamesCount == other.fShortZodiacNamesCount &&
fAbbreviatedDayPeriodsCount == other.fAbbreviatedDayPeriodsCount &&
fWideDayPeriodsCount == other.fWideDayPeriodsCount &&
fNarrowDayPeriodsCount == other.fNarrowDayPeriodsCount &&
fStandaloneAbbreviatedDayPeriodsCount == other.fStandaloneAbbreviatedDayPeriodsCount &&
fStandaloneWideDayPeriodsCount == other.fStandaloneWideDayPeriodsCount &&
fStandaloneNarrowDayPeriodsCount == other.fStandaloneNarrowDayPeriodsCount &&
(uprv_memcmp(fCapitalization, other.fCapitalization, sizeof(fCapitalization))==0))
{
// Now compare the arrays themselves
@ -568,7 +593,16 @@ DateFormatSymbols::operator==(const DateFormatSymbols& other) const
arrayCompare(fStandaloneShortQuarters, other.fStandaloneShortQuarters, fStandaloneShortQuartersCount) &&
arrayCompare(fLeapMonthPatterns, other.fLeapMonthPatterns, fLeapMonthPatternsCount) &&
arrayCompare(fShortYearNames, other.fShortYearNames, fShortYearNamesCount) &&
arrayCompare(fShortZodiacNames, other.fShortZodiacNames, fShortZodiacNamesCount))
arrayCompare(fShortZodiacNames, other.fShortZodiacNames, fShortZodiacNamesCount) &&
arrayCompare(fAbbreviatedDayPeriods, other.fAbbreviatedDayPeriods, fAbbreviatedDayPeriodsCount) &&
arrayCompare(fWideDayPeriods, other.fWideDayPeriods, fWideDayPeriodsCount) &&
arrayCompare(fNarrowDayPeriods, other.fNarrowDayPeriods, fNarrowDayPeriodsCount) &&
arrayCompare(fStandaloneAbbreviatedDayPeriods, other.fStandaloneAbbreviatedDayPeriods,
fStandaloneAbbreviatedDayPeriodsCount) &&
arrayCompare(fStandaloneWideDayPeriods, other.fStandaloneWideDayPeriods,
fStandaloneWideDayPeriodsCount) &&
arrayCompare(fStandaloneNarrowDayPeriods, other.fStandaloneNarrowDayPeriods,
fStandaloneWideDayPeriodsCount))
{
// Compare the contents of fZoneStrings
if (fZoneStrings == NULL && other.fZoneStrings == NULL) {
@ -964,7 +998,7 @@ DateFormatSymbols::setMonths(const UnicodeString* monthsArray, int32_t count, Dt
fNarrowMonths = newUnicodeStringArray(count);
uprv_arrayCopy( monthsArray,fNarrowMonths,count);
fNarrowMonthsCount = count;
break;
break;
default :
break;
}
@ -991,7 +1025,7 @@ DateFormatSymbols::setMonths(const UnicodeString* monthsArray, int32_t count, Dt
fStandaloneNarrowMonths = newUnicodeStringArray(count);
uprv_arrayCopy( monthsArray,fStandaloneNarrowMonths,count);
fStandaloneNarrowMonthsCount = count;
break;
break;
default :
break;
}
@ -1065,7 +1099,7 @@ DateFormatSymbols::setWeekdays(const UnicodeString* weekdaysArray, int32_t count
fNarrowWeekdays = newUnicodeStringArray(count);
uprv_arrayCopy(weekdaysArray, fNarrowWeekdays, count);
fNarrowWeekdaysCount = count;
break;
break;
case DT_WIDTH_COUNT :
break;
}
@ -1099,7 +1133,7 @@ DateFormatSymbols::setWeekdays(const UnicodeString* weekdaysArray, int32_t count
fStandaloneNarrowWeekdays = newUnicodeStringArray(count);
uprv_arrayCopy(weekdaysArray, fStandaloneNarrowWeekdays, count);
fStandaloneNarrowWeekdaysCount = count;
break;
break;
case DT_WIDTH_COUNT :
break;
}
@ -1141,7 +1175,7 @@ DateFormatSymbols::setQuarters(const UnicodeString* quartersArray, int32_t count
uprv_arrayCopy( quartersArray,fNarrowQuarters,count);
fNarrowQuartersCount = count;
*/
break;
break;
default :
break;
}
@ -1170,7 +1204,7 @@ DateFormatSymbols::setQuarters(const UnicodeString* quartersArray, int32_t count
uprv_arrayCopy( quartersArray,fStandaloneNarrowQuarters,count);
fStandaloneNarrowQuartersCount = count;
*/
break;
break;
default :
break;
}
@ -1472,6 +1506,42 @@ static const ContextUsageTypeNameToEnumValue contextUsageTypeMap[] = {
{ NULL, (DateFormatSymbols::ECapitalizationContextUsageType)0 },
};
// Resource keys to look up localized strings for day periods.
// The first one must be midnight and the second must be noon, so that their indices coincide
// with the am/pm field. Formatting and parsing code for day periods relies on this coincidence.
static const char *dayPeriodKeys[] = {"midnight", "noon",
"morning1", "afternoon1", "evening1", "night1",
"morning2", "afternoon2", "evening2", "night2"};
UnicodeString* loadDayPeriodStrings(CalendarData &calData, const char *tag, UBool standalone,
int32_t &stringCount, UErrorCode &status) {
if (U_FAILURE(status)) {
return NULL;
}
UResourceBundle *dayPeriodData;
if (standalone) {
dayPeriodData = calData.getByKey3(gDayPeriodTag, gNamesStandaloneTag, tag, status);
} else {
dayPeriodData = calData.getByKey2(gDayPeriodTag, tag, status);
}
stringCount = UPRV_LENGTHOF(dayPeriodKeys);
UnicodeString *strings = new UnicodeString[stringCount];
for (int32_t i = 0; i < stringCount; ++i) {
//TODO: Check if there are fallbacks/aliases defined in the data; e.g., if there
//is no wide string, then use the narrow one?
strings[i].fastCopyFrom(ures_getUnicodeStringByKey(dayPeriodData, dayPeriodKeys[i], &status));
if (U_FAILURE(status)) {
// string[i] will be bogus if ures_getUnicodeString() returns with an error,
// which is just the behavior we want. Simply reset the error code.
status = U_ZERO_ERROR;
}
}
return strings;
}
void
DateFormatSymbols::initializeData(const Locale& locale, const char *type, UErrorCode& status, UBool useLastResortData)
{
@ -1536,6 +1606,18 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
fZoneStringsColCount = 0;
fZoneStrings = NULL;
fLocaleZoneStrings = NULL;
fAbbreviatedDayPeriods = NULL;
fAbbreviatedDayPeriodsCount = 0;
fWideDayPeriods = NULL;
fWideDayPeriodsCount = 0;
fNarrowDayPeriods = NULL;
fNarrowDayPeriodsCount = 0;
fStandaloneAbbreviatedDayPeriods = NULL;
fStandaloneAbbreviatedDayPeriodsCount = 0;
fStandaloneWideDayPeriods = NULL;
fStandaloneWideDayPeriodsCount = 0;
fStandaloneNarrowDayPeriods = NULL;
fStandaloneNarrowDayPeriodsCount = 0;
uprv_memset(fCapitalization, 0, sizeof(fCapitalization));
// We need to preserve the requested locale for
@ -1543,7 +1625,7 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
// is region sensitive, thus, bundle locale bundle's locale
// is not sufficient.
fZSFLocale = locale;
if (U_FAILURE(status)) return;
/**
@ -1693,6 +1775,19 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
fTimeSeparator.setTo(DateFormatSymbols::DEFAULT_TIME_SEPARATOR);
}
fWideDayPeriods = loadDayPeriodStrings(calData, gNamesWideTag, FALSE,
fWideDayPeriodsCount, status);
fNarrowDayPeriods = loadDayPeriodStrings(calData, gNamesNarrowTag, FALSE,
fNarrowDayPeriodsCount, status);
fAbbreviatedDayPeriods = loadDayPeriodStrings(calData, gNamesAbbrTag, FALSE,
fAbbreviatedDayPeriodsCount, status);
fStandaloneWideDayPeriods = loadDayPeriodStrings(calData, gNamesWideTag, TRUE,
fStandaloneWideDayPeriodsCount, status);
fStandaloneNarrowDayPeriods = loadDayPeriodStrings(calData, gNamesNarrowTag, TRUE,
fStandaloneNarrowDayPeriodsCount, status);
fStandaloneAbbreviatedDayPeriods = loadDayPeriodStrings(calData, gNamesAbbrTag, TRUE,
fStandaloneAbbreviatedDayPeriodsCount, status);
UResourceBundle *weekdaysData = NULL; // Data closed by calData
UResourceBundle *abbrWeekdaysData = NULL; // Data closed by calData
UResourceBundle *shorterWeekdaysData = NULL; // Data closed by calData
@ -1990,7 +2085,7 @@ cleanup:
ures_close(narrowEras);
}
Locale
Locale
DateFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
U_LOCALE_BASED(locBased, *this);
return locBased.getLocale(type, status);

View file

@ -310,6 +310,7 @@
<ClCompile Include="currunit.cpp" />
<ClCompile Include="dangical.cpp" />
<ClCompile Include="datefmt.cpp" />
<ClCompile Include="dayperiodrules.cpp" />
<ClCompile Include="dcfmtsym.cpp" />
<ClCompile Include="decContext.c" />
<ClCompile Include="decfmtst.cpp" />
@ -608,6 +609,7 @@
<ClInclude Include="collationsettings.h" />
<ClInclude Include="collationtailoring.h" />
<ClInclude Include="collationweights.h" />
<ClInclude Include="dayperiodrules.h" />
<ClInclude Include="dcfmtimp.h" />
<ClInclude Include="numsys_impl.h" />
<ClInclude Include="region_impl.h" />

View file

@ -57,6 +57,9 @@
<ClCompile Include="affixpatternparser.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="dayperiodrules.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="decimfmtimpl.cpp">
<Filter>formatting</Filter>
</ClCompile>
@ -691,6 +694,9 @@
<ClInclude Include="dangical.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="dayperiodrules.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="decContext.h">
<Filter>formatting</Filter>
</ClInclude>

View file

@ -1,7 +1,7 @@
/*
*******************************************************************************
* Copyright (C) 1997-2016, International Business Machines Corporation and
* others. All Rights Reserved.
* Copyright (C) 1997-2016, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
* File SMPDTFMT.CPP
@ -17,7 +17,7 @@
* Removed getZoneIndex (added in DateFormatSymbols)
* Removed subParseLong
* Removed chk
* 02/22/99 stephen Removed character literals for EBCDIC safety
* 02/22/99 stephen Removed character literals for EBCDIC safety
* 10/14/99 aliu Updated 2-digit year parsing so that only "00" thru
* "99" are recognized. {j28 4182066}
* 11/15/99 weiv Added support for week of year/day of week format
@ -63,6 +63,10 @@
#include "smpdtfst.h"
#include "sharednumberformat.h"
#include "ustr_imp.h"
#include "charstr.h"
#include "uvector.h"
#include "cstr.h"
#include "dayperiodrules.h"
#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
#include <stdio.h>
@ -622,6 +626,8 @@ SimpleDateFormat& SimpleDateFormat::operator=(const SimpleDateFormat& other)
fHaveDefaultCentury = other.fHaveDefaultCentury;
fPattern = other.fPattern;
fHasMinute = other.fHasMinute;
fHasSecond = other.fHasSecond;
// TimeZoneFormat in ICU4C only depends on a locale for now
if (fLocale != other.fLocale) {
@ -889,6 +895,8 @@ SimpleDateFormat::initialize(const Locale& locale,
{
status = U_MISSING_RESOURCE_ERROR;
}
parsePattern();
}
/* Initialize the fields we use to disambiguate ambiguous years. Separate
@ -969,7 +977,7 @@ SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo,
FieldPositionHandler& handler, UErrorCode& status) const
{
if ( U_FAILURE(status) ) {
return appendTo;
return appendTo;
}
Calendar* workCal = &cal;
Calendar* calClone = NULL;
@ -1161,6 +1169,7 @@ SimpleDateFormat::fgPatternIndexToCalendarField[] =
/*O*/ UCAL_ZONE_OFFSET,
/*Xx*/ UCAL_ZONE_OFFSET, UCAL_ZONE_OFFSET,
/*r*/ UCAL_EXTENDED_YEAR,
/*bB*/ UCAL_FIELD_COUNT, UCAL_FIELD_COUNT, // no mappings to calendar fields
#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
/*:*/ UCAL_FIELD_COUNT, /* => no useful mapping to any calendar field */
#else
@ -1189,6 +1198,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,
/*bB*/ UDAT_AM_PM_MIDNIGHT_NOON_FIELD, UDAT_FLEXIBLE_DAY_PERIOD_FIELD,
#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
/*:*/ UDAT_TIME_SEPARATOR_FIELD,
#else
@ -1419,7 +1429,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
return;
}
UnicodeString hebr("hebr", 4, US_INV);
switch (patternCharIndex) {
// for any "G" symbol, write out the appropriate era string
@ -1788,6 +1798,126 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
zeroPaddingNumber(currentNumberFormat,appendTo, (value/3) + 1, count, maxIntCount);
break;
case UDAT_AM_PM_MIDNIGHT_NOON_FIELD:
{
const UnicodeString *toAppend = NULL;
int32_t hour = cal.get(UCAL_HOUR_OF_DAY, status);
// For "midnight" and "noon":
// Time, as displayed, must be exactly noon or midnight.
// This means minutes and seconds, if present, must be zero.
if ((hour == 0 || hour == 12) &&
(!fHasMinute || cal.get(UCAL_MINUTE, status) == 0) &&
(!fHasSecond || cal.get(UCAL_SECOND, status) == 0)) {
// Stealing am/pm value to use as our array index.
// It works out: am/midnight are both 0, pm/noon are both 1,
// 12 am is 12 midnight, and 12 pm is 12 noon.
int32_t value = cal.get(UCAL_AM_PM, status);
if (count <= 3) {
toAppend = &fSymbols->fAbbreviatedDayPeriods[value];
} else if (count == 4 || count > 5) {
toAppend = &fSymbols->fWideDayPeriods[value];
} else { // count == 5
toAppend = &fSymbols->fNarrowDayPeriods[value];
}
}
// toAppend is NULL if time isn't exactly midnight or noon (as displayed).
// toAppend is bogus if time is midnight or noon, but no localized string exists.
// In either case, fall back to am/pm.
if (toAppend == NULL || toAppend->isBogus()) {
// Reformat with identical arguments except ch, now changed to 'a'.
subFormat(appendTo, 0x61, count, capitalizationContext, fieldNum,
handler, cal, mutableNFs, status);
} else {
appendTo += *toAppend;
}
break;
}
case UDAT_FLEXIBLE_DAY_PERIOD_FIELD:
{
// TODO: Maybe fetch the DayperiodRules during initialization (instead of at the first
// loading of an instance) if a relevant pattern character (b or B) is used.
const DayPeriodRules *ruleSet = DayPeriodRules::getInstance(this->getSmpFmtLocale(), status);
if (U_FAILURE(status)) {
// Data doesn't conform to spec, therefore loading failed.
break;
}
if (ruleSet == NULL) {
// Data doesn't exist for the locale we're looking for.
// Falling back to am/pm.
subFormat(appendTo, 0x61, count, capitalizationContext, fieldNum,
handler, cal, mutableNFs, status);
break;
}
// Get current display time.
int32_t hour = cal.get(UCAL_HOUR_OF_DAY, status);
int32_t minute = 0;
if (fHasMinute) {
minute = cal.get(UCAL_MINUTE, status);
}
int32_t second = 0;
if (fHasSecond) {
second = cal.get(UCAL_SECOND, status);
}
// Determine day period.
DayPeriodRules::DayPeriod periodType;
if (hour == 0 && minute == 0 && second == 0 && ruleSet->hasMidnight()) {
periodType = DayPeriodRules::DAYPERIOD_MIDNIGHT;
} else if (hour == 12 && minute == 0 && second == 0 && ruleSet->hasNoon()) {
periodType = DayPeriodRules::DAYPERIOD_NOON;
} else {
periodType = ruleSet->getDayPeriodForHour(hour);
}
// Rule set exists, therefore periodType can't be UNKNOWN.
// Get localized string.
U_ASSERT(periodType != DayPeriodRules::DAYPERIOD_UNKNOWN);
UnicodeString *toAppend = NULL;
int32_t index = (int32_t)periodType;
if (count <= 3) {
toAppend = &fSymbols->fAbbreviatedDayPeriods[index]; // i.e. short
} else if (count == 4 || count > 5) {
toAppend = &fSymbols->fWideDayPeriods[index];
} else { // count == 5
toAppend = &fSymbols->fNarrowDayPeriods[index];
}
// Fallback schedule:
// Midnight/Noon -> General Periods -> AM/PM.
// Midnight/Noon -> General Periods.
if (toAppend->isBogus() &&
(periodType == DayPeriodRules::DAYPERIOD_MIDNIGHT || periodType == DayPeriodRules::DAYPERIOD_NOON)) {
periodType = ruleSet->getDayPeriodForHour(hour);
index = (int32_t)periodType;
if (count <= 3) {
toAppend = &fSymbols->fAbbreviatedDayPeriods[index]; // i.e. short
} else if (count == 4 || count > 5) {
toAppend = &fSymbols->fWideDayPeriods[index];
} else { // count == 5
toAppend = &fSymbols->fNarrowDayPeriods[index];
}
}
// General Periods -> AM/PM.
if (toAppend->isBogus()) {
subFormat(appendTo, 0x61, count, capitalizationContext, fieldNum,
handler, cal, mutableNFs, status);
}
else {
appendTo += *toAppend;
}
break;
}
// all of the other pattern symbols can be formatted as simple numbers with
// appropriate zero padding
@ -1830,7 +1960,7 @@ void SimpleDateFormat::adoptNumberFormat(NumberFormat *formatToAdopt) {
fixNumberFormatForDates(*formatToAdopt);
delete fNumberFormat;
fNumberFormat = formatToAdopt;
// We successfully set the default number format. Now delete the overrides
// (can't fail).
if (fSharedNumberFormatters) {
@ -1956,6 +2086,9 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
}
int32_t start = pos;
// Hold the day period until everything else is parsed, because we need
// the hour to interpret time correctly.
int32_t dayPeriodInt = -1;
UBool ambiguousYear[] = { FALSE };
int32_t saveHebrewMonth = -1;
@ -1994,7 +2127,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
goto ExitParse;
}
}
if (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount) {
numericLeapMonthFormatter = new MessageFormat(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternNumeric], fLocale, status);
if (numericLeapMonthFormatter == NULL) {
@ -2070,7 +2203,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
// fields.
else if (ch != 0x6C) { // pattern char 'l' (SMALL LETTER L) just gets ignored
int32_t s = subParse(text, pos, ch, count,
FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType, mutableNFs);
FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType, mutableNFs, &dayPeriodInt);
if (s == -pos-1) {
// era not present, in special cases allow this to continue
@ -2106,7 +2239,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
else {
abutPat = -1; // End of any abutting fields
if (! matchLiterals(fPattern, i, text, pos, getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status), getBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, status), isLenient())) {
status = U_PARSE_ERROR;
goto ExitParse;
@ -2122,6 +2255,76 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
}
}
// If dayPeriod is set, use it in conjunction with hour-of-day to determine am/pm.
if (dayPeriodInt >= 0) {
DayPeriodRules::DayPeriod dayPeriod = (DayPeriodRules::DayPeriod)dayPeriodInt;
const DayPeriodRules *ruleSet = DayPeriodRules::getInstance(this->getSmpFmtLocale(), status);
if (!cal.isSet(UCAL_HOUR) && !cal.isSet(UCAL_HOUR_OF_DAY)) {
// If hour is not set, set time to the midpoint of current day period, overwriting
// minutes if it's set.
double midPoint = ruleSet->getMidPointForDayPeriod(dayPeriod, status);
// If we can't get midPoint we do nothing.
if (U_SUCCESS(status)) {
// Truncate midPoint toward zero to get the hour.
// Any leftover means it was a half-hour.
int32_t midPointHour = (int32_t) midPoint;
int32_t midPointMinute = (midPoint - midPointHour) > 0 ? 30 : 0;
// No need to set am/pm because hour-of-day is set last therefore takes precedence.
cal.set(UCAL_HOUR_OF_DAY, midPointHour);
cal.set(UCAL_MINUTE, midPointMinute);
}
} else {
int hourOfDay;
if (cal.isSet(UCAL_HOUR_OF_DAY)) { // Hour is parsed in 24-hour format.
hourOfDay = cal.get(UCAL_HOUR_OF_DAY, status);
} else { // Hour is parsed in 12-hour format.
hourOfDay = cal.get(UCAL_HOUR, status);
// cal.get() turns 12 to 0 for 12-hour time; change 0 to 12
// so 0 unambiguously means a 24-hour time from above.
if (hourOfDay == 0) { hourOfDay = 12; }
}
assert(0 <= hourOfDay && hourOfDay <= 23);
// If hour-of-day is 0 or 13 thru 23 then input time in unambiguously in 24-hour format.
if (hourOfDay == 0 || (13 <= hourOfDay && hourOfDay <= 23)) {
// Make hour-of-day take precedence over (hour + am/pm) by setting it again.
cal.set(UCAL_HOUR_OF_DAY, hourOfDay);
} else {
// We have a 12-hour time and need to choose between am and pm.
// Behave as if dayPeriod spanned 6 hours each way from its center point.
// This will parse correctly for consistent time + period (e.g. 10 at night) as
// well as provide a reasonable recovery for inconsistent time + period (e.g.
// 9 in the afternoon).
// Assume current time is in the AM.
// - Change 12 back to 0 for easier handling of 12am.
// - Append minutes as fractional hours because e.g. 8:15 and 8:45 could be parsed
// into different half-days if center of dayPeriod is at 14:30.
// - cal.get(MINUTE) will return 0 if MINUTE is unset, which works.
if (hourOfDay == 12) { hourOfDay = 0; }
double currentHour = hourOfDay + (cal.get(UCAL_MINUTE, status)) / 60.0;
double midPointHour = ruleSet->getMidPointForDayPeriod(dayPeriod, status);
if (U_SUCCESS(status)) {
double hoursAheadMidPoint = currentHour - midPointHour;
// Assume current time is in the AM.
if (-6 <= hoursAheadMidPoint && hoursAheadMidPoint < 6) {
// Assumption holds; set time as such.
cal.set(UCAL_AM_PM, 0);
} else {
cal.set(UCAL_AM_PM, 1);
}
}
}
}
}
// At this point the fields of Calendar have been set. Calendar
// will fill in default values for missing fields when the time
// is computed.
@ -2346,6 +2549,29 @@ int32_t SimpleDateFormat::matchQuarterString(const UnicodeString& text,
return -start;
}
int32_t SimpleDateFormat::matchDayPeriodStrings(const UnicodeString& text, int32_t start,
const UnicodeString* data, int32_t dataCount,
int32_t &dayPeriod) const
{
int32_t bestMatchLength = 0, bestMatch = -1;
for (int32_t i = 0; i < dataCount; ++i) {
int32_t matchLength = 0;
if ((matchLength = matchStringWithOptionalDot(text, start, data[i])) > bestMatchLength) {
bestMatchLength = matchLength;
bestMatch = i;
}
}
if (bestMatch >= 0) {
dayPeriod = bestMatch;
return start + bestMatchLength;
}
return -start;
}
//----------------------------------------------------------------------
UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
int32_t &patternOffset,
@ -2356,17 +2582,17 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
UBool oldLeniency)
{
UBool inQuote = FALSE;
UnicodeString literal;
UnicodeString literal;
int32_t i = patternOffset;
// scan pattern looking for contiguous literal characters
for ( ; i < pattern.length(); i += 1) {
UChar ch = pattern.charAt(i);
if (!inQuote && isSyntaxChar(ch)) {
break;
}
if (ch == QUOTE) {
// Match a quote literal ('') inside OR outside of quotes
if ((i + 1) < pattern.length() && pattern.charAt(i + 1) == QUOTE) {
@ -2376,47 +2602,47 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
continue;
}
}
literal += ch;
}
// at this point, literal contains the literal text
// and i is the index of the next non-literal pattern character.
int32_t p;
int32_t t = textOffset;
if (whitespaceLenient) {
// trim leading, trailing whitespace from
// the literal text
literal.trim();
// ignore any leading whitespace in the text
while (t < text.length() && u_isWhitespace(text.charAt(t))) {
t += 1;
}
}
for (p = 0; p < literal.length() && t < text.length();) {
UBool needWhitespace = FALSE;
while (p < literal.length() && PatternProps::isWhiteSpace(literal.charAt(p))) {
needWhitespace = TRUE;
p += 1;
}
if (needWhitespace) {
int32_t tStart = t;
while (t < text.length()) {
UChar tch = text.charAt(t);
if (!u_isUWhiteSpace(tch) && !PatternProps::isWhiteSpace(tch)) {
break;
}
t += 1;
}
// TODO: should we require internal spaces
// in lenient mode? (There won't be any
// leading or trailing spaces)
@ -2425,7 +2651,7 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
// an error in strict mode
return FALSE;
}
// In strict mode, this run of whitespace
// may have been at the end.
if (p >= literal.length()) {
@ -2443,26 +2669,26 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
++t;
continue; // Do not update p.
}
// if it is actual whitespace and we're whitespace lenient it's OK
// if it is actual whitespace and we're whitespace lenient it's OK
UChar wsc = text.charAt(t);
if(PatternProps::isWhiteSpace(wsc)) {
// Lenient mode and it's just whitespace we skip it
++t;
continue; // Do not update p.
}
}
}
// hack around oldleniency being a bit of a catch-all bucket and we're just adding support specifically for paritial matches
if(partialMatchLenient && oldLeniency) {
if(partialMatchLenient && oldLeniency) {
break;
}
return FALSE;
}
++p;
++t;
}
// At this point if we're in strict mode we have a complete match.
// If we're in lenient mode we may have a partial match, or no
// match at all.
@ -2474,20 +2700,20 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
if (patternCharIndex != UDAT_FIELD_COUNT) {
ignorables = SimpleDateFormatStaticSets::getIgnorables(patternCharIndex);
}
for (t = textOffset; t < text.length(); t += 1) {
UChar ch = text.charAt(t);
if (ignorables == NULL || !ignorables->contains(ch)) {
break;
}
}
}
// if we get here, we've got a complete match.
patternOffset = i - 1;
textOffset = t;
return TRUE;
}
@ -2595,7 +2821,8 @@ SimpleDateFormat::set2DigitYearStart(UDate d, UErrorCode& status)
*/
int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UChar ch, int32_t count,
UBool obeyCount, UBool allowNegative, UBool ambiguousYear[], int32_t& saveHebrewMonth, Calendar& cal,
int32_t patLoc, MessageFormat * numericLeapMonthFormatter, UTimeZoneFormatTimeType *tzTimeType, SimpleDateFormatMutableNFs &mutableNFs) const
int32_t patLoc, MessageFormat * numericLeapMonthFormatter, UTimeZoneFormatTimeType *tzTimeType, SimpleDateFormatMutableNFs &mutableNFs,
int32_t *dayPeriod) const
{
Formattable number;
int32_t value = 0;
@ -2702,7 +2929,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
if (txtLoc > parseStart) {
value = number.getLong();
gotNumber = TRUE;
// suffix processing
if (value < 0 ) {
txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, TRUE);
@ -2725,7 +2952,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
pos.setIndex(txtLoc);
}
}
// Make sure that we got a number if
// we want one, and didn't get one
// if we don't want one.
@ -2738,9 +2965,9 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
if (value < 0 || value > 24) {
return -start;
}
// fall through to gotNumber check
case UDAT_YEAR_FIELD:
case UDAT_YEAR_WOY_FIELD:
case UDAT_FRACTIONAL_SECOND_FIELD:
@ -2748,9 +2975,9 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
if (! gotNumber) {
return -start;
}
break;
default:
// we check the rest of the fields below.
break;
@ -2929,9 +3156,9 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
// [We computed 'value' above.]
if (value == cal.getMaximum(UCAL_HOUR_OF_DAY) + 1)
value = 0;
// fall through to set field
case UDAT_HOUR_OF_DAY0_FIELD:
cal.set(UCAL_HOUR_OF_DAY, value);
return pos.getIndex();
@ -3054,9 +3281,9 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
// [We computed 'value' above.]
if (value == cal.getLeastMaximum(UCAL_HOUR)+1)
value = 0;
// fall through to set field
case UDAT_HOUR0_FIELD:
cal.set(UCAL_HOUR, value);
return pos.getIndex();
@ -3246,7 +3473,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
}
// currently no pattern character is defined for UDAT_TIME_SEPARATOR_FIELD
// so we should not get here. Leave support in for future definition.
case UDAT_TIME_SEPARATOR_FIELD: //
case UDAT_TIME_SEPARATOR_FIELD:
{
static const UChar def_sep = DateFormatSymbols::DEFAULT_TIME_SEPARATOR;
static const UChar alt_sep = DateFormatSymbols::ALTERNATE_TIME_SEPARATOR;
@ -3269,6 +3496,70 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
return matchString(text, start, UCAL_FIELD_COUNT /* => nothing to set */, data, count, NULL, cal);
}
case UDAT_AM_PM_MIDNIGHT_NOON_FIELD:
{
U_ASSERT(dayPeriod != NULL);
int32_t ampmStart = subParse(text, start, 0x61, count,
obeyCount, allowNegative, ambiguousYear, saveHebrewMonth, cal,
patLoc, numericLeapMonthFormatter, tzTimeType, mutableNFs);
if (ampmStart > 0) {
return ampmStart;
} else {
int32_t newStart = 0;
// Only match the first two strings from the day period strings array.
if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fAbbreviatedDayPeriods,
2, *dayPeriod)) > 0) {
return newStart;
}
}
if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) {
if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fNarrowDayPeriods,
2, *dayPeriod)) > 0) {
return newStart;
}
}
// count == 4, but allow other counts
if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status)) {
if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fWideDayPeriods,
2, *dayPeriod)) > 0) {
return newStart;
}
}
return -start;
}
}
case UDAT_FLEXIBLE_DAY_PERIOD_FIELD:
{
U_ASSERT(dayPeriod != NULL);
int32_t newStart = 0;
if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fAbbreviatedDayPeriods,
fSymbols->fAbbreviatedDayPeriodsCount, *dayPeriod)) > 0) {
return newStart;
}
}
if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) {
if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fNarrowDayPeriods,
fSymbols->fNarrowDayPeriodsCount, *dayPeriod)) > 0) {
return newStart;
}
}
if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fWideDayPeriods,
fSymbols->fWideDayPeriodsCount, *dayPeriod)) > 0) {
return newStart;
}
}
return -start;
}
default:
// Handle "generic" fields
// this is now handled below, outside the switch block
@ -3408,7 +3699,7 @@ void SimpleDateFormat::translatePattern(const UnicodeString& originalPattern,
UErrorCode& status)
{
// run through the pattern and convert any pattern symbols from the version
// in "from" to the corresponding character ion "to". This code takes
// in "from" to the corresponding character in "to". This code takes
// quoted strings into account (it doesn't try to translate them), and it signals
// an error if a particular "pattern character" doesn't appear in "from".
// Depending on the values of "from" and "to" this can convert from generic
@ -3472,6 +3763,7 @@ void
SimpleDateFormat::applyPattern(const UnicodeString& pattern)
{
fPattern = pattern;
parsePattern();
}
//----------------------------------------------------------------------
@ -3799,6 +4091,28 @@ SimpleDateFormat::tzFormat() const {
return fTimeZoneFormat;
}
void SimpleDateFormat::parsePattern() {
fHasMinute = FALSE;
fHasSecond = FALSE;
int len = fPattern.length();
UBool inQuote = FALSE;
for (int32_t i = 0; i < len; ++i) {
UChar ch = fPattern[i];
if (ch == QUOTE) {
inQuote = !inQuote;
}
if (!inQuote) {
if (ch == 0x6D) { // 0x6D == 'm'
fHasMinute = TRUE;
}
if (ch == 0x73) { // 0x73 == 's'
fHasSecond = TRUE;
}
}
}
}
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -3,7 +3,7 @@
* Copyright (C) 2001-2016, International Business Machines
* Corporation and others. All Rights Reserved.
******************************************************************************
* file name: ucln_cmn.h
* file name: ucln_in.h
* encoding: US-ASCII
* tab size: 8 (not used)
* indentation:4
@ -42,6 +42,7 @@ typedef enum ECleanupI18NType {
UCLN_I18N_TIMEZONE,
UCLN_I18N_DECFMT,
UCLN_I18N_NUMFMT,
UCLN_I18N_DAYPERIODRULES,
UCLN_I18N_SMPDTFMT,
UCLN_I18N_USEARCH,
UCLN_I18N_COLLATOR,

View file

@ -1,4 +1,4 @@
/*
/*
********************************************************************************
* Copyright (C) 1997-2016, International Business Machines
* Corporation and others. All Rights Reserved.
@ -14,10 +14,10 @@
* Changed to match C++ conventions
********************************************************************************
*/
#ifndef DTFMTSYM_H
#define DTFMTSYM_H
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
@ -29,7 +29,7 @@
#include "unicode/ures.h"
/**
* \file
* \file
* \brief C++ API: Symbols for formatting dates.
*/
@ -115,7 +115,7 @@ public:
* data for the default locale, it will return a last-resort object
* based on hard-coded strings.
*
* @param type Type of calendar (as returned by Calendar::getType).
* @param type Type of calendar (as returned by Calendar::getType).
* Will be used to access the correct set of strings.
* (NULL or empty string defaults to "gregorian".)
* @param status Status code. Failure
@ -130,7 +130,7 @@ public:
* resources for the given locale, in the default calendar (Gregorian).
*
* @param locale Locale to load format data from.
* @param type Type of calendar (as returned by Calendar::getType).
* @param type Type of calendar (as returned by Calendar::getType).
* Will be used to access the correct set of strings.
* (NULL or empty string defaults to "gregorian".)
* @param status Status code. Failure
@ -850,6 +850,42 @@ private:
*/
UBool fCapitalization[kCapContextUsageTypeCount][2];
/**
* Abbreviated (== short) day period strings.
*/
UnicodeString *fAbbreviatedDayPeriods;
int32_t fAbbreviatedDayPeriodsCount;
/**
* Wide day period strings.
*/
UnicodeString *fWideDayPeriods;
int32_t fWideDayPeriodsCount;
/**
* Narrow day period strings.
*/
UnicodeString *fNarrowDayPeriods;
int32_t fNarrowDayPeriodsCount;
/**
* Stand-alone abbreviated (== short) day period strings.
*/
UnicodeString *fStandaloneAbbreviatedDayPeriods;
int32_t fStandaloneAbbreviatedDayPeriodsCount;
/**
* Stand-alone wide day period strings.
*/
UnicodeString *fStandaloneWideDayPeriods;
int32_t fStandaloneWideDayPeriodsCount;
/**
* Stand-alone narrow day period strings.
*/
UnicodeString *fStandaloneNarrowDayPeriods;
int32_t fStandaloneNarrowDayPeriodsCount;
private:
/** valid/actual locale information
* these are always ICU locales, so the length should not be a problem

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 1997-2015, International Business Machines Corporation and
* Copyright (C) 1997-2016, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*
@ -89,7 +89,7 @@ class SimpleDateFormatMutableNFs;
* <td style="text-align: center" rowspan="3">G</td>
* <td style="text-align: center">1..3</td>
* <td>AD</td>
* <td rowspan="3">Era - Replaced with the Era string for the current date. One to three letters for the
* <td rowspan="3">Era - Replaced with the Era string for the current date. One to three letters for the
* abbreviated form, four letters for the long (wide) form, five for the narrow form.</td>
* </tr>
* <tr>
@ -218,7 +218,7 @@ class SimpleDateFormatMutableNFs;
* <td rowspan="3" style="text-align: center">q</td>
* <td style="text-align: center">1..2</td>
* <td>02</td>
* <td rowspan="3"><b>Stand-Alone</b> Quarter - Use one or two for the numerical quarter, three for the abbreviation,
* <td rowspan="3"><b>Stand-Alone</b> Quarter - Use one or two for the numerical quarter, three for the abbreviation,
* or four for the full name (five for the narrow name is not yet supported).</td>
* </tr>
* <tr>
@ -254,7 +254,7 @@ class SimpleDateFormatMutableNFs;
* <td rowspan="4" style="text-align: center">L</td>
* <td style="text-align: center">1..2</td>
* <td>09</td>
* <td rowspan="4"><b>Stand-Alone</b> Month - Use one or two for the numerical month, three for the abbreviation,
* <td rowspan="4"><b>Stand-Alone</b> Month - Use one or two for the numerical month, three for the abbreviation,
* four for the full (wide) name, or 5 for the narrow name. With two ("LL"), the month number is zero-padded if
* necessary (e.g. "08")</td>
* </tr>
@ -310,7 +310,7 @@ class SimpleDateFormatMutableNFs;
* <td>2451334</td>
* <td>Modified Julian day. This is different from the conventional Julian day number in two regards.
* First, it demarcates days at local zone midnight, rather than noon GMT. Second, it is a local number;
* that is, it depends on the local time zone. It can be thought of as a single number that encompasses
* that is, it depends on the local time zone. It can be thought of as a single number that encompasses
* all the date-related fields.</td>
* </tr>
* <tr>
@ -319,7 +319,7 @@ class SimpleDateFormatMutableNFs;
* <td rowspan="4" style="text-align: center">E</td>
* <td style="text-align: center">1..3</td>
* <td>Tue</td>
* <td rowspan="4">Day of week - Use one through three letters for the short day, four for the full (wide) name,
* <td rowspan="4">Day of week - Use one through three letters for the short day, four for the full (wide) name,
* five for the narrow name, or six for the short name.</td>
* </tr>
* <tr>
@ -539,7 +539,7 @@ class SimpleDateFormatMutableNFs;
* <td>The <i>generic location format</i>.
* Where that is unavailable, falls back to the <i>long localized GMT format</i> ("OOOO";
* Note: Fallback is only necessary with a GMT-style Time Zone ID, like Etc/GMT-830.)<br>
* This is especially useful when presenting possible timezone choices for user selection,
* This is especially useful when presenting possible timezone choices for user selection,
* since the naming is more uniform than the "v" format.</td>
* </tr>
* <tr>
@ -1126,15 +1126,15 @@ public:
* @param value The UDisplayContext value to set.
* @param status Input/output status. If at entry this indicates a failure
* status, the function will do nothing; otherwise this will be
* updated with any new status from the function.
* updated with any new status from the function.
* @stable ICU 53
*/
virtual void setContext(UDisplayContext value, UErrorCode& status);
/**
* Overrides base class method and
* This method clears per field NumberFormat instances
* previously set by {@see adoptNumberFormat(const UnicodeString&, NumberFormat*, UErrorCode)}
* This method clears per field NumberFormat instances
* previously set by {@see adoptNumberFormat(const UnicodeString&, NumberFormat*, UErrorCode)}
* @param adoptNF the NumbeferFormat used
* @stable ICU 54
*/
@ -1144,7 +1144,7 @@ public:
* Allow the user to set the NumberFormat for several fields
* It can be a single field like: "y"(year) or "M"(month)
* It can be several field combined together: "yM"(year and month)
* Note:
* Note:
* 1 symbol field is enough for multiple symbol field (so "y" will override "yy", "yyy")
* If the field is not numeric, then override has no effect (like "MMM" will use abbreviation, not numerical field)
* Per field NumberFormat can also be cleared in {@see DateFormat::setNumberFormat(const NumberFormat& newNumberFormat)}
@ -1269,7 +1269,7 @@ private:
* having a number of digits between "minDigits" and
* "maxDigits". Uses the DateFormat's NumberFormat.
*
* @param currentNumberFormat
* @param currentNumberFormat
* @param appendTo Output parameter to receive result.
* Formatted number is appended to existing contents.
* @param value Value to format.
@ -1357,7 +1357,14 @@ private:
*/
int32_t matchQuarterString(const UnicodeString& text, int32_t start, UCalendarDateFields field,
const UnicodeString* stringArray, int32_t stringArrayCount, Calendar& cal) const;
/**
* Used by subParse() to match localized day period strings.
*/
int32_t matchDayPeriodStrings(const UnicodeString& text, int32_t start,
const UnicodeString* stringArray, int32_t stringArrayCount,
int32_t &dayPeriod) const;
/**
* Private function used by subParse to match literal pattern text.
*
@ -1374,9 +1381,9 @@ private:
* @return <code>TRUE</code> if the literal text could be matched, <code>FALSE</code> otherwise.
*/
static UBool matchLiterals(const UnicodeString &pattern, int32_t &patternOffset,
const UnicodeString &text, int32_t &textOffset,
const UnicodeString &text, int32_t &textOffset,
UBool whitespaceLenient, UBool partialMatchLenient, UBool oldLeniency);
/**
* Private member function that converts the parsed date strings into
* timeFields. Returns -start (for ParsePosition) if failed.
@ -1399,7 +1406,8 @@ private:
*/
int32_t subParse(const UnicodeString& text, int32_t& start, UChar ch, int32_t count,
UBool obeyCount, UBool allowNegative, UBool ambiguousYear[], int32_t& saveHebrewMonth, Calendar& cal,
int32_t patLoc, MessageFormat * numericLeapMonthFormatter, UTimeZoneFormatTimeType *tzTimeType, SimpleDateFormatMutableNFs &mutableNFs) const;
int32_t patLoc, MessageFormat * numericLeapMonthFormatter, UTimeZoneFormatTimeType *tzTimeType, SimpleDateFormatMutableNFs &mutableNFs,
int32_t *dayPeriod=NULL) const;
void parseInt(const UnicodeString& text,
Formattable& number,
@ -1556,6 +1564,14 @@ private:
*/
UDate fDefaultCenturyStart;
UBool fHasMinute;
UBool fHasSecond;
/**
* Sets fHasMinutes and fHasSeconds.
*/
void parsePattern();
/**
* See documentation for defaultCenturyStart.
*/

View file

@ -759,7 +759,21 @@ typedef enum UDateFormatField {
* @internal ICU 53
*/
UDAT_RELATED_YEAR_FIELD = 34,
#endif /* U_HIDE_INTERNAL_API */
#endif /* U_HIDE_INTERNAL_API */
/**
* FieldPosition selector for 'b' field alignment.
* Displays midnight and noon for 12am and 12pm, respectively, if available;
* otherwise fall back to AM / PM.
* @draft ICU 57
*/
UDAT_AM_PM_MIDNIGHT_NOON_FIELD = 35,
/* FieldPosition selector for 'B' field alignment.
* Displays flexible day periods, such as "in the morning", if available.
* @draft ICU 57
*/
UDAT_FLEXIBLE_DAY_PERIOD_FIELD = 36,
/**
* FieldPosition and UFieldPosition selector for time separator,
@ -767,7 +781,8 @@ typedef enum UDateFormatField {
* defined for this.
* @stable ICU 55
*/
UDAT_TIME_SEPARATOR_FIELD = 35,
UDAT_TIME_SEPARATOR_FIELD = 37,
/**
* Number of FieldPosition and UFieldPosition selectors for
@ -777,7 +792,7 @@ typedef enum UDateFormatField {
* in the future.
* @stable ICU 3.0
*/
UDAT_FIELD_COUNT = 36
UDAT_FIELD_COUNT = 38
} UDateFormatField;

View file

@ -1,5 +1,5 @@
/********************************************************************
* COPYRIGHT:
* COPYRIGHT:
* Copyright (c) 1997-2016, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
@ -8,7 +8,7 @@
* File CDATTST.C
*
* Modification History:
* Name Description
* Name Description
* Madhu Katragadda Creation
*********************************************************************************
*/
@ -90,24 +90,24 @@ static void TestDateFormat()
fr = udat_open(UDAT_FULL, UDAT_DEFAULT, "fr_FR", NULL,0, NULL, 0,&status);
if(U_FAILURE(status))
{
log_data_err("FAIL: error in creating the dateformat using full time style with french locale -> %s (Are you missing data?)\n",
log_data_err("FAIL: error in creating the dateformat using full time style with french locale -> %s (Are you missing data?)\n",
myErrorName(status) );
return;
}
/* this is supposed to open default date format, but later on it treats it like it is "en_US"
/* this is supposed to open default date format, but later on it treats it like it is "en_US"
- very bad if you try to run the tests on machine where default locale is NOT "en_US" */
/* def = udat_open(UDAT_SHORT, UDAT_SHORT, NULL, NULL, 0, &status); */
def = udat_open(UDAT_SHORT, UDAT_SHORT, "en_US", NULL, 0,NULL, 0, &status);
if(U_FAILURE(status))
{
log_err("FAIL: error in creating the dateformat using short date and time style\n %s\n",
log_err("FAIL: error in creating the dateformat using short date and time style\n %s\n",
myErrorName(status) );
return;
}
it = udat_open(UDAT_DEFAULT, UDAT_MEDIUM, "it_IT", NULL, 0, NULL, 0,&status);
if(U_FAILURE(status))
{
log_err("FAIL: error in creating the dateformat using medium date style with italian locale\n %s\n",
log_err("FAIL: error in creating the dateformat using medium date style with italian locale\n %s\n",
myErrorName(status) );
return;
}
@ -122,20 +122,20 @@ static void TestDateFormat()
def1 = udat_open(UDAT_SHORT, UDAT_SHORT, NULL, NULL, 0,NULL, 0, &status);
if(U_FAILURE(status))
{
log_err("FAIL: error in creating the dateformat using short date and time style\n %s\n",
log_err("FAIL: error in creating the dateformat using short date and time style\n %s\n",
myErrorName(status) );
return;
}
/*Testing udat_getAvailable() and udat_countAvailable()*/
/*Testing udat_getAvailable() and udat_countAvailable()*/
log_verbose("\nTesting getAvailableLocales and countAvailable()\n");
numlocales=udat_countAvailable();
/* use something sensible w/o hardcoding the count */
if(numlocales < 0)
log_data_err("FAIL: error in countAvailable\n");
log_verbose("The number of locales for which date/time formatting patterns are available is %d\n", numlocales);
for(i=0;i<numlocales;i++) {
UErrorCode subStatus = U_ZERO_ERROR;
log_verbose("Testing open of %s\n", udat_getAvailable(i));
@ -154,7 +154,7 @@ static void TestDateFormat()
}
/*if(def != copy)
log_err("Error in udat_clone");*/ /*how should i check for equality???? */
/*Testing udat_format()*/
log_verbose("\nTesting the udat_format() function of date format\n");
u_uastrcpy(temp, "7/10/96, 4:05 PM");
@ -189,7 +189,7 @@ static void TestDateFormat()
log_err("FAIL: Date Format for US locale failed using udat_format() - expected %s got %s\n", xbuf, gbuf);
}
/*format using fr */
u_unescape("10 juil. 1996 \\u00E0 16:05:28 heure d\\u2019\\u00E9t\\u00E9 du Pacifique", temp, 50);
if(result != NULL) {
free(result);
@ -203,12 +203,12 @@ static void TestDateFormat()
/*format using it */
u_uastrcpy(temp, "10 lug 1996, 16:05:28");
{
{
UChar *fmtted;
char g[100];
char x[100];
fmtted = myDateFormat(it,d);
u_austrcpy(g, fmtted);
u_austrcpy(x, temp);
@ -218,13 +218,13 @@ static void TestDateFormat()
log_data_err("FAIL: Date Format for italian locale failed using udat_format() - wanted %s, got %s\n", x, g);
}
}
/*Testing parsing using udat_parse()*/
log_verbose("\nTesting parsing using udat_parse()\n");
u_uastrcpy(temp,"2/3/76, 2:50 AM");
parsepos=0;
status=U_ZERO_ERROR;
d1=udat_parse(def, temp, u_strlen(temp), &parsepos, &status);
if(U_FAILURE(status))
{
@ -233,8 +233,8 @@ static void TestDateFormat()
else
log_verbose("PASS: parsing succesful\n");
/*format it back and check for equality */
if(u_strcmp(myDateFormat(def, d1),temp)!=0)
log_err("FAIL: error in parsing\n");
@ -242,7 +242,7 @@ static void TestDateFormat()
log_verbose("\nTesting parsing using udat_parse()\n");
u_uastrcpy(temp,"2/Don't parse this part");
status=U_ZERO_ERROR;
d1=udat_parse(def, temp, u_strlen(temp), NULL, &status);
if(status != U_PARSE_ERROR)
{
@ -250,9 +250,9 @@ static void TestDateFormat()
}
else
log_verbose("PASS: parsing succesful\n");
/*Testing udat_openPattern() */
status=U_ZERO_ERROR;
log_verbose("\nTesting the udat_openPattern with a specified pattern\n");
@ -260,13 +260,13 @@ static void TestDateFormat()
fr_pat=udat_open(UDAT_PATTERN, UDAT_PATTERN,"fr_FR",NULL,0,temp, u_strlen(temp), &status);
if(U_FAILURE(status))
{
log_err("FAIL: Error in creating a date format using udat_openPattern \n %s\n",
log_err("FAIL: Error in creating a date format using udat_openPattern \n %s\n",
myErrorName(status) );
}
else
log_verbose("PASS: creating dateformat using udat_openPattern() succesful\n");
/*Testing applyPattern and toPattern */
log_verbose("\nTesting applyPattern and toPattern()\n");
udat_applyPattern(def1, FALSE, temp, u_strlen(temp));
@ -283,25 +283,25 @@ static void TestDateFormat()
}
if(U_FAILURE(status))
{
log_err("FAIL: error in extracting the pattern from UNumberFormat\n %s\n",
log_err("FAIL: error in extracting the pattern from UNumberFormat\n %s\n",
myErrorName(status) );
}
if(u_strcmp(result, temp)!=0)
log_err("FAIL: Error in extracting the pattern\n");
else
log_verbose("PASS: applyPattern and toPattern work fine\n");
if(result != NULL) {
free(result);
free(result);
result = NULL;
}
/*Testing getter and setter functions*/
/*isLenient and setLenient()*/
log_verbose("\nTesting the isLenient and setLenient properties\n");
udat_setLenient(fr, udat_isLenient(it));
if(udat_isLenient(fr) != udat_isLenient(it))
if(udat_isLenient(fr) != udat_isLenient(it))
log_err("ERROR: setLenient() failed\n");
else
log_verbose("PASS: setLenient() successful\n");
@ -332,7 +332,7 @@ static void TestDateFormat()
else
log_verbose("PASS: set2DigitYearStart successful\n");
/*Test getNumberFormat() and setNumberFormat() */
log_verbose("\nTesting the get and set NumberFormat properties of date format\n");
@ -343,7 +343,7 @@ static void TestDateFormat()
log_err("FAIL: error in setNumberFormat or getNumberFormat()\n");
else
log_verbose("PASS:setNumberFormat and getNumberFormat succesful\n");
/*Test getNumberFormat() and adoptNumberFormat() */
log_verbose("\nTesting the get and adopt NumberFormat properties of date format\n");
adoptNF= unum_open(UNUM_DEFAULT, NULL, 0, NULL, NULL, &status);
@ -368,18 +368,18 @@ static void TestDateFormat()
/*Test getCalendar and setCalendar*/
log_verbose("\nTesting the udat_getCalendar() and udat_setCalendar() properties\n");
cal=udat_getCalendar(fr_pat);
udat_setCalendar(def1, cal);
if(!ucal_equivalentTo(udat_getCalendar(fr_pat), udat_getCalendar(def1)))
log_err("FAIL: Error in setting and getting the calendar\n");
else
log_verbose("PASS: getting and setting calendar successful\n");
if(result!=NULL) {
free(result);
}
/*Closing the UDateForamt */
udat_close(def);
udat_close(fr);
@ -388,7 +388,7 @@ static void TestDateFormat()
udat_close(def1);
udat_close(fr_pat);
udat_close(copy);
ctest_resetTimeZone();
}
@ -520,7 +520,7 @@ static void TestRelativeDateFormat()
log_err("udat_parse timeStyle SHORT dateStyle (%d | UDAT_RELATIVE) fails, error %s, expect approx %.1f, got %.1f, parsePos %d\n",
*stylePtr, myErrorName(status), dateToUse, dateResult, parsePos );
status = U_ZERO_ERROR;
}
}
udat_format(fmtRelDate, dateToUse, strDate, kDateOrTimeOutMax, NULL, &status);
if ( U_FAILURE(status) ) {
@ -536,7 +536,7 @@ static void TestRelativeDateFormat()
log_err("udat_parse timeStyle NONE dateStyle (%d | UDAT_RELATIVE) fails, error %s, expect approx %.1f, got %.1f, parsePos %d\n",
*stylePtr, myErrorName(status), dateToUse, dateResult, parsePos );
status = U_ZERO_ERROR;
}
}
}
udat_format(fmtTime, dateToUse, strTime, kDateOrTimeOutMax, NULL, &status);
@ -570,31 +570,31 @@ static void TestSymbols()
{
UDateFormat *def, *fr, *zhChiCal;
UErrorCode status = U_ZERO_ERROR;
UChar *value=NULL;
UChar *value=NULL;
UChar *result = NULL;
int32_t resultlength;
int32_t resultlengthout;
UChar *pattern;
/*creating a dateformat with french locale */
log_verbose("\ncreating a date format with french locale\n");
fr = udat_open(UDAT_FULL, UDAT_DEFAULT, "fr_FR", NULL, 0, NULL, 0, &status);
if(U_FAILURE(status))
{
log_data_err("error in creating the dateformat using full time style with french locale -> %s (Are you missing data?)\n",
log_data_err("error in creating the dateformat using full time style with french locale -> %s (Are you missing data?)\n",
myErrorName(status) );
return;
}
/*creating a default dateformat */
log_verbose("\ncreating a date format with default locale\n");
/* this is supposed to open default date format, but later on it treats it like it is "en_US"
/* this is supposed to open default date format, but later on it treats it like it is "en_US"
- very bad if you try to run the tests on machine where default locale is NOT "en_US" */
/* def = udat_open(UDAT_DEFAULT,UDAT_DEFAULT ,NULL, NULL, 0, &status); */
def = udat_open(UDAT_DEFAULT,UDAT_DEFAULT ,"en_US", NULL, 0, NULL, 0, &status);
if(U_FAILURE(status))
{
log_err("error in creating the dateformat using short date and time style\n %s\n",
log_err("error in creating the dateformat using short date and time style\n %s\n",
myErrorName(status) );
return;
}
@ -603,16 +603,16 @@ static void TestSymbols()
zhChiCal = udat_open(UDAT_NONE, UDAT_FULL, "zh@calendar=chinese", NULL, 0, NULL, 0, &status);
if(U_FAILURE(status))
{
log_data_err("error in creating the dateformat using full date, no time, locale zh@calendar=chinese -> %s (Are you missing data?)\n",
log_data_err("error in creating the dateformat using full date, no time, locale zh@calendar=chinese -> %s (Are you missing data?)\n",
myErrorName(status) );
return;
}
/*Testing countSymbols, getSymbols and setSymbols*/
log_verbose("\nTesting countSymbols\n");
/*since the month names has the last string empty and week names are 1 based 1.e first string in the weeknames array is empty */
if(udat_countSymbols(def, UDAT_ERAS)!=2 || udat_countSymbols(def, UDAT_MONTHS)!=12 ||
if(udat_countSymbols(def, UDAT_ERAS)!=2 || udat_countSymbols(def, UDAT_MONTHS)!=12 ||
udat_countSymbols(def, UDAT_SHORT_MONTHS)!=12 || udat_countSymbols(def, UDAT_WEEKDAYS)!=8 ||
udat_countSymbols(def, UDAT_SHORT_WEEKDAYS)!=8 || udat_countSymbols(def, UDAT_AM_PMS)!=2 ||
udat_countSymbols(def, UDAT_QUARTERS) != 4 || udat_countSymbols(def, UDAT_SHORT_QUARTERS) != 4 ||
@ -640,7 +640,7 @@ static void TestSymbols()
}
result=(UChar*)malloc(sizeof(UChar) * resultlength);
udat_getSymbols(fr, UDAT_WEEKDAYS, 5, result, resultlength, &status);
}
if(U_FAILURE(status))
{
@ -677,9 +677,9 @@ static void TestSymbols()
VerifygetSymbols(zhChiCal, UDAT_ZODIAC_NAMES_ABBREVIATED, 0, "\\u9F20");
VerifygetSymbols(zhChiCal, UDAT_ZODIAC_NAMES_WIDE, 11, "\\u732A");
#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
VerifygetSymbols(def,UDAT_LOCALIZED_CHARS, 0, "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxr:");
VerifygetSymbols(def,UDAT_LOCALIZED_CHARS, 0, "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB:");
#else
VerifygetSymbols(def,UDAT_LOCALIZED_CHARS, 0, "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxr");
VerifygetSymbols(def,UDAT_LOCALIZED_CHARS, 0, "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB");
#endif
@ -687,8 +687,8 @@ static void TestSymbols()
free(result);
result = NULL;
}
free(pattern);
free(pattern);
log_verbose("\nTesting setSymbols\n");
/*applying the pattern so that setSymbolss works */
resultlength=0;
@ -702,10 +702,10 @@ free(pattern);
}
if(U_FAILURE(status))
{
log_err("FAIL: error in extracting the pattern from UNumberFormat\n %s\n",
log_err("FAIL: error in extracting the pattern from UNumberFormat\n %s\n",
myErrorName(status) );
}
udat_applyPattern(def, FALSE, pattern, u_strlen(pattern));
resultlength=0;
resultlengthout=udat_toPattern(def, FALSE, NULL, resultlength,&status);
@ -722,7 +722,7 @@ free(pattern);
}
if(U_FAILURE(status))
{
log_err("FAIL: error in extracting the pattern from UNumberFormat\n %s\n",
log_err("FAIL: error in extracting the pattern from UNumberFormat\n %s\n",
myErrorName(status) );
}
if(u_strcmp(result, pattern)==0)
@ -743,12 +743,12 @@ free(pattern);
}
result=(UChar*)malloc(sizeof(UChar) * resultlength);
udat_getSymbols(fr, UDAT_MONTHS, 11, result, resultlength, &status);
}
if(U_FAILURE(status))
log_err("FAIL: error in getSymbols() %s\n", myErrorName(status) );
resultlength=resultlengthout+1;
udat_setSymbols(def, UDAT_MONTHS, 11, result, resultlength, &status);
if(U_FAILURE(status))
{
@ -756,7 +756,7 @@ free(pattern);
}
else
log_verbose("PASS: SetSymbols successful\n");
resultlength=0;
resultlengthout=udat_getSymbols(def, UDAT_MONTHS, 11, NULL, resultlength, &status);
if(status==U_BUFFER_OVERFLOW_ERROR){
@ -767,13 +767,13 @@ free(pattern);
}
if(U_FAILURE(status))
log_err("FAIL: error in retrieving the value using getSymbols i.e roundtrip\n");
if(u_strcmp(result, value)!=0)
log_data_err("FAIL: Error in settting and getting symbols\n");
else
log_verbose("PASS: setSymbols successful\n");
/*run series of tests to test setSymbols regressively*/
log_verbose("\nTesting setSymbols regressively\n");
VerifysetSymbols(def, UDAT_ERAS, 0, "BeforeChrist");
@ -812,7 +812,7 @@ free(pattern);
/*closing*/
udat_close(fr);
udat_close(def);
udat_close(zhChiCal);
@ -821,7 +821,7 @@ free(pattern);
result = NULL;
}
free(value);
}
/**
@ -845,7 +845,7 @@ static void TestDateFormatCalendar() {
/* Create a formatter for date fields. */
date = udat_open(UDAT_NONE, UDAT_SHORT, "en_US", NULL, 0, NULL, 0, &ec);
if (U_FAILURE(ec)) {
log_data_err("FAIL: udat_open(NONE, SHORT, en_US) failed with %s (Are you missing data?)\n",
log_data_err("FAIL: udat_open(NONE, SHORT, en_US) failed with %s (Are you missing data?)\n",
u_errorName(ec));
goto FAIL;
}
@ -853,7 +853,7 @@ static void TestDateFormatCalendar() {
/* Create a formatter for time fields. */
time = udat_open(UDAT_SHORT, UDAT_NONE, "en_US", NULL, 0, NULL, 0, &ec);
if (U_FAILURE(ec)) {
log_err("FAIL: udat_open(SHORT, NONE, en_US) failed with %s\n",
log_err("FAIL: udat_open(SHORT, NONE, en_US) failed with %s\n",
u_errorName(ec));
goto FAIL;
}
@ -861,7 +861,7 @@ static void TestDateFormatCalendar() {
/* Create a full format for output */
full = udat_open(UDAT_FULL, UDAT_FULL, "en_US", NULL, 0, NULL, 0, &ec);
if (U_FAILURE(ec)) {
log_err("FAIL: udat_open(FULL, FULL, en_US) failed with %s\n",
log_err("FAIL: udat_open(FULL, FULL, en_US) failed with %s\n",
u_errorName(ec));
goto FAIL;
}
@ -869,7 +869,7 @@ static void TestDateFormatCalendar() {
/* Create a calendar */
cal = ucal_open(NULL, 0, "en_US", UCAL_GREGORIAN, &ec);
if (U_FAILURE(ec)) {
log_err("FAIL: ucal_open(en_US) failed with %s\n",
log_err("FAIL: ucal_open(en_US) failed with %s\n",
u_errorName(ec));
goto FAIL;
}
@ -940,7 +940,7 @@ static void TestDateFormatCalendar() {
log_err("FAIL: Parsed result: %s, exp 4/5/2001 5:45 PM\n", cbuf);
}
FAIL:
FAIL:
udat_close(date);
udat_close(time);
udat_close(full);
@ -1057,7 +1057,7 @@ static void VerifygetSymbols(UDateFormat* datfor, UDateFormatSymbolType type, in
UChar *result=NULL;
int32_t resultlength, resultlengthout;
int32_t patternSize = strlen(expected) + 1;
pattern=(UChar*)malloc(sizeof(UChar) * patternSize);
u_unescape(expected, pattern, patternSize);
resultlength=0;
@ -1068,7 +1068,7 @@ static void VerifygetSymbols(UDateFormat* datfor, UDateFormatSymbolType type, in
resultlength=resultlengthout+1;
result=(UChar*)malloc(sizeof(UChar) * resultlength);
udat_getSymbols(datfor, type, idx, result, resultlength, &status);
}
if(U_FAILURE(status))
{
@ -1078,7 +1078,7 @@ static void VerifygetSymbols(UDateFormat* datfor, UDateFormatSymbolType type, in
if(u_strcmp(result, pattern)==0)
log_verbose("PASS: getSymbols retrieved the right value\n");
else{
log_data_err("FAIL: getSymbols retrieved the wrong value\n Expected %s Got %s\n", expected,
log_data_err("FAIL: getSymbols retrieved the wrong value\n Expected %s Got %s\n", expected,
aescstrdup(result,-1) );
}
free(result);
@ -1111,11 +1111,11 @@ static void VerifysetSymbols(UDateFormat* datfor, UDateFormatSymbolType type, in
udat_getSymbols(datfor, type, idx, result, resultlength, &status);
}
if(U_FAILURE(status)){
log_err("FAIL: error in retrieving the value using getSymbols after setting it previously\n %s\n",
log_err("FAIL: error in retrieving the value using getSymbols after setting it previously\n %s\n",
myErrorName(status) );
return;
}
if(u_strcmp(result, value)!=0){
log_err("FAIL:Error in setting and then getting symbols\n Expected %s Got %s\n", expected,
aescstrdup(result,-1) );
@ -1134,7 +1134,7 @@ static void VerifygetsetSymbols(UDateFormat* from, UDateFormat* to, UDateFormatS
UChar *value=NULL;
int32_t resultlength, resultlengthout;
UErrorCode status = U_ZERO_ERROR;
resultlength=0;
resultlengthout=udat_getSymbols(from, type, idx , NULL, resultlength, &status);
if(status==U_BUFFER_OVERFLOW_ERROR){
@ -1147,7 +1147,7 @@ static void VerifygetsetSymbols(UDateFormat* from, UDateFormat* to, UDateFormatS
log_err("FAIL: error in getSymbols() %s\n", myErrorName(status) );
return;
}
resultlength=resultlengthout+1;
udat_setSymbols(to, type, idx, result, resultlength, &status);
if(U_FAILURE(status))
@ -1165,11 +1165,11 @@ static void VerifygetsetSymbols(UDateFormat* from, UDateFormat* to, UDateFormatS
udat_getSymbols(to, type, idx, value, resultlength, &status);
}
if(U_FAILURE(status)){
log_err("FAIL: error in retrieving the value using getSymbols i.e roundtrip\n %s\n",
log_err("FAIL: error in retrieving the value using getSymbols i.e roundtrip\n %s\n",
myErrorName(status) );
return;
}
if(u_strcmp(result, value)!=0){
log_data_err("FAIL:Error in setting and then getting symbols\n Expected %s Got %s\n", austrdup(result),
austrdup(value) );
@ -1187,7 +1187,7 @@ static UChar* myNumformat(const UNumberFormat* numfor, double d)
UChar *result2=NULL;
int32_t resultlength, resultlengthneeded;
UErrorCode status = U_ZERO_ERROR;
resultlength=0;
resultlengthneeded=unum_formatDouble(numfor, d, NULL, resultlength, NULL, &status);
if(status==U_BUFFER_OVERFLOW_ERROR)
@ -1203,7 +1203,7 @@ static UChar* myNumformat(const UNumberFormat* numfor, double d)
log_err("FAIL: Error in formatting using unum_format(.....) %s\n", myErrorName(status) );
return 0;
}
return result2;
}
@ -1277,7 +1277,7 @@ static void TestExtremeDates() {
/* There is no need to test larger values from 1e+30 to 1e+300;
the failures occur around 1e+27, and never above 1e+30. */
ec = U_ZERO_ERROR;
fmt = udat_open(UDAT_LONG, UDAT_LONG, "en_US",
0, 0, 0, 0, &ec);
@ -1327,12 +1327,12 @@ static void TestRelativeCrash(void) {
UErrorCode subStatus = U_ZERO_ERROR;
what = "udat_set2DigitYearStart";
log_verbose("Trying %s on a relative date..\n", what);
udat_set2DigitYearStart(icudf, aDate, &subStatus);
udat_set2DigitYearStart(icudf, aDate, &subStatus);
if(subStatus == expectStatus) {
log_verbose("Success: did not crash on %s, but got %s.\n", what, u_errorName(subStatus));
} else {
log_err("FAIL: didn't crash on %s, but got success %s instead of %s. \n", what, u_errorName(subStatus), u_errorName(expectStatus));
}
}
}
{
/* clone works polymorphically. try it anyways */
@ -1346,42 +1346,42 @@ static void TestRelativeCrash(void) {
udat_close(oth); /* ? */
} else {
log_err("FAIL: didn't crash on %s, but got %s instead of %s. \n", what, u_errorName(subStatus), u_errorName(expectStatus));
}
}
}
{
UErrorCode subStatus = U_ZERO_ERROR;
what = "udat_get2DigitYearStart";
log_verbose("Trying %s on a relative date..\n", what);
udat_get2DigitYearStart(icudf, &subStatus);
udat_get2DigitYearStart(icudf, &subStatus);
if(subStatus == expectStatus) {
log_verbose("Success: did not crash on %s, but got %s.\n", what, u_errorName(subStatus));
} else {
log_err("FAIL: didn't crash on %s, but got success %s instead of %s. \n", what, u_errorName(subStatus), u_errorName(expectStatus));
}
}
}
{
/* Now udat_toPattern works for relative date formatters, unless localized is TRUE */
UErrorCode subStatus = U_ZERO_ERROR;
what = "udat_toPattern";
log_verbose("Trying %s on a relative date..\n", what);
udat_toPattern(icudf, TRUE,NULL,0, &subStatus);
udat_toPattern(icudf, TRUE,NULL,0, &subStatus);
if(subStatus == expectStatus) {
log_verbose("Success: did not crash on %s, but got %s.\n", what, u_errorName(subStatus));
} else {
log_err("FAIL: didn't crash on %s, but got success %s instead of %s. \n", what, u_errorName(subStatus), u_errorName(expectStatus));
}
}
}
{
UErrorCode subStatus = U_ZERO_ERROR;
what = "udat_applyPattern";
log_verbose("Trying %s on a relative date..\n", what);
udat_applyPattern(icudf, FALSE,tzName,-1);
udat_applyPattern(icudf, FALSE,tzName,-1);
subStatus = U_ILLEGAL_ARGUMENT_ERROR; /* what it should be, if this took an errorcode. */
if(subStatus == expectStatus) {
log_verbose("Success: did not crash on %s, but got %s.\n", what, u_errorName(subStatus));
} else {
log_err("FAIL: didn't crash on %s, but got success %s instead of %s. \n", what, u_errorName(subStatus), u_errorName(expectStatus));
}
}
}
{
UChar erabuf[32];
@ -1393,7 +1393,7 @@ static void TestRelativeCrash(void) {
log_verbose("Success: %s returned %s.\n", what, u_errorName(subStatus));
} else {
log_err("FAIL: didn't crash on %s, but got %s instead of U_ZERO_ERROR.\n", what, u_errorName(subStatus));
}
}
}
{
UErrorCode subStatus = U_ZERO_ERROR;
@ -1405,21 +1405,21 @@ static void TestRelativeCrash(void) {
log_verbose("Success: did not crash on %s, but got %s.\n", what, u_errorName(subStatus));
} else {
log_err("FAIL: didn't crash on %s, but got success %s instead of %s. \n", what, u_errorName(subStatus), u_errorName(expectStatus));
}
}
}
{
UErrorCode subStatus = U_ZERO_ERROR;
what = "udat_countSymbols";
log_verbose("Trying %s on a relative date..\n", what);
udat_countSymbols(icudf, UDAT_ERAS);
udat_countSymbols(icudf, UDAT_ERAS);
subStatus = U_ILLEGAL_ARGUMENT_ERROR; /* should have an errorcode. */
if(subStatus == expectStatus) {
log_verbose("Success: did not crash on %s, but got %s.\n", what, u_errorName(subStatus));
} else {
log_err("FAIL: didn't crash on %s, but got success %s instead of %s. \n", what, u_errorName(subStatus), u_errorName(expectStatus));
}
}
}
udat_close(icudf);
} else {
log_data_err("FAIL: err calling udat_open() ->%s (Are you missing data?)\n", u_errorName(status));
@ -1599,9 +1599,9 @@ static void TestContext(void) {
}
// overrideNumberFormat[i][0] is to tell which field to set,
// overrideNumberFormat[i][0] is to tell which field to set,
// overrideNumberFormat[i][1] is the expected result
static const char * overrideNumberFormat[][2] = {
static const char * overrideNumberFormat[][2] = {
{"", "\\u521D\\u4E03 \\u521D\\u4E8C"},
{"d", "07 \\u521D\\u4E8C"},
{"do", "07 \\u521D\\u4E8C"},
@ -1652,7 +1652,7 @@ static void TestOverrideNumberFormat(void) {
unum_close(overrideFmt);
}
udat_close(fmt);
for (i=0; i<UPRV_LENGTHOF(overrideNumberFormat); i++){
UChar ubuf[kUbufMax];
UDateFormat* fmt2;
@ -1696,7 +1696,7 @@ static void TestOverrideNumberFormat(void) {
udat_format(fmt2, july022008, ubuf, kUbufMax, NULL, &status);
assertSuccess("udat_format() july022008", &status);
if (u_strncmp(ubuf, expected, kUbufMax) != 0)
if (u_strncmp(ubuf, expected, kUbufMax) != 0)
log_err("fail: udat_format for locale, expected %s, got %s\n",
u_austrncpy(bbuf1,expected,kUbufMax), u_austrncpy(bbuf2,ubuf,kUbufMax) );
@ -1787,7 +1787,7 @@ static void TestFormatForFields(void) {
int32_t ulen, field, beginPos, endPos;
UChar ubuf[kUBufFieldsLen];
const FieldsData * fptr;
status = U_ZERO_ERROR;
ulen = udat_formatForFields(udfmt, date2015Feb25, ubuf, kUBufFieldsLen, fpositer, &status);
if ( U_FAILURE(status) ) {
@ -1810,7 +1810,7 @@ static void TestFormatForFields(void) {
}
}
}
ucal_setMillis(ucal, date2015Feb25, &status);
status = U_ZERO_ERROR;
ulen = udat_formatCalendarForFields(udfmt, ucal, ubuf, kUBufFieldsLen, fpositer, &status);

File diff suppressed because it is too large Load diff

View file

@ -1,12 +1,12 @@
/********************************************************************
* COPYRIGHT:
* Copyright (c) 1997-2015, International Business Machines Corporation and
* COPYRIGHT:
* Copyright (c) 1997-2016, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
#ifndef _DATEFORMATTEST_
#define _DATEFORMATTEST_
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
@ -15,7 +15,7 @@
#include "unicode/smpdtfmt.h"
#include "caltztst.h"
/**
/**
* Performs many different tests for DateFormat and SimpleDateFormat
**/
class DateFormatTest: public CalendarTimeZoneTest {
@ -40,23 +40,23 @@ public:
* Test the parsing of 2-digit years.
*/
virtual void TestTwoDigitYearDSTParse(void);
public: // package
// internal utility routine (genrates escape sequences for characters)
static UnicodeString& escape(UnicodeString& s);
public:
/**
* Verify that returned field position indices are correct.
*/
void TestFieldPosition(void);
void TestGeneral();
public: // package
// internal utility function
static void getFieldText(DateFormat* df, int32_t field, UDate date, UnicodeString& str);
public:
/**
* Verify that strings which contain incomplete specifications are parsed
@ -64,11 +64,11 @@ public:
* returning an appropriate error.
*/
virtual void TestPartialParse994(void);
public: // package
// internal test subroutine, used by TestPartialParse994
virtual void tryPat994(SimpleDateFormat* format, const char* pat, const char* str, UDate expected);
public:
/**
* Verify the behavior of patterns in which digits for different fields run together
@ -80,11 +80,11 @@ public:
* without intervening separators.
*/
virtual void TestRunTogetherPattern917(void);
public: // package
// internal test subroutine, used by TestRunTogetherPattern917
virtual void testIt917(SimpleDateFormat* fmt, UnicodeString& str, UDate expected);
public:
/**
* Verify the handling of Czech June and July, which have the unique attribute that
@ -99,11 +99,11 @@ public:
* Test the day of year pattern.
*/
virtual void TestDayOfYearPattern195(void);
public: // package
// interl test subroutine, used by TestDayOfYearPattern195
virtual void tryPattern(SimpleDateFormat& sdf, UDate d, const char* pattern, UDate expected);
public:
/**
* Test the handling of single quotes in patterns.
@ -113,7 +113,7 @@ public:
* Verify the correct behavior when handling invalid input strings.
*/
virtual void TestBadInput135(void);
public:
/**
* Verify the correct behavior when parsing an array of inputs against an
@ -125,11 +125,11 @@ public:
* Test the parsing of two-digit years.
*/
virtual void TestTwoDigitYear(void);
public: // package
// internal test subroutine, used by TestTwoDigitYear
virtual void parse2DigitYear(DateFormat& fmt, const char* str, UDate expected);
public:
/**
* Test the formatting of time zones.
@ -209,11 +209,11 @@ public:
void TestStandAloneMonths(void);
void TestQuarters(void);
void TestZTimeZoneParsing(void);
void TestRelativeClone(void);
void TestHostClone(void);
void TestHebrewClone(void);
@ -252,6 +252,12 @@ public:
void TestPatternFromSkeleton();
void TestAmPmMidnightNoon();
void TestFlexibleDayPeriod();
void TestDayPeriodWithLocales();
void TestMinuteSecondFieldsInOddPlaces();
void TestDayPeriodParsing();
private:
UBool showParse(DateFormat &format, const UnicodeString &formattedString);
@ -262,7 +268,7 @@ public:
void TestNumberAsStringParsing(void);
private:
void TestRelative(int daysdelta,
void TestRelative(int daysdelta,
const Locale& loc,
const char *expectChars);
@ -275,9 +281,10 @@ public:
void expectFormat(const char **data, int32_t data_length,
const Locale &locale);
};
#endif /* #if !UCONFIG_NO_FORMATTING */
#endif // _DATEFORMATTEST_
//eof

View file

@ -1,7 +1,7 @@
/********************************************************************
* COPYRIGHT:
* Copyright (c) 1997-2014, International Business Machines Corporation and
* COPYRIGHT:
* Copyright (c) 1997-2016, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
@ -22,7 +22,7 @@ void IntlTestSimpleDateFormatAPI::runIndexedTest( int32_t index, UBool exec, con
{
if (exec) logln("TestSuite SimpleDateFormatAPI");
switch (index) {
case 0: name = "SimpleDateFormat API test";
case 0: name = "SimpleDateFormat API test";
if (exec) {
logln("SimpleDateFormat API test---"); logln("");
UErrorCode status = U_ZERO_ERROR;
@ -271,8 +271,8 @@ void IntlTestSimpleDateFormatAPI::testAPI(/*char *par*/)
}
// ====== Test ticket 11295 getNumberFormatForField returns wild pointer
if (object.getNumberFormatForField('B') != NULL) {
errln("B is not a valid field, "
if (object.getNumberFormatForField('N') != NULL) {
errln("N is not a valid field, "
"getNumberFormatForField should return NULL");
}
}