ICU-22164 Replace switch+getType with subclass

See #2215

fix
This commit is contained in:
Frank Tang 2022-11-10 01:22:16 +00:00 committed by Frank Yung-Fong Tang
parent b0ab1171ad
commit 9c1fb785b3
15 changed files with 1458 additions and 373 deletions

View file

@ -45,6 +45,7 @@
#include "hebrwcal.h"
#include "persncal.h"
#include "indiancal.h"
#include "iso8601cal.h"
#include "chnsecal.h"
#include "coptccal.h"
#include "dangical.h"
@ -354,18 +355,19 @@ static Calendar *createStandardCalendar(ECalType calType, const Locale &loc, UEr
cal.adoptInsteadAndCheckErrorCode(new PersianCalendar(loc, status), status);
break;
case CALTYPE_ISLAMIC_TBLA:
cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status, IslamicCalendar::TBLA), status);
cal.adoptInsteadAndCheckErrorCode(new IslamicTBLACalendar(loc, status), status);
break;
case CALTYPE_ISLAMIC_CIVIL:
cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status, IslamicCalendar::CIVIL), status);
cal.adoptInsteadAndCheckErrorCode(new IslamicCivilCalendar(loc, status), status);
break;
case CALTYPE_ISLAMIC_RGSA:
// default any region specific not handled individually to islamic
cal.adoptInsteadAndCheckErrorCode(new IslamicRGSACalendar(loc, status), status);
break;
case CALTYPE_ISLAMIC:
cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status, IslamicCalendar::ASTRONOMICAL), status);
cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status), status);
break;
case CALTYPE_ISLAMIC_UMALQURA:
cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status, IslamicCalendar::UMALQURA), status);
cal.adoptInsteadAndCheckErrorCode(new IslamicUmalquraCalendar(loc, status), status);
break;
case CALTYPE_HEBREW:
cal.adoptInsteadAndCheckErrorCode(new HebrewCalendar(loc, status), status);
@ -380,17 +382,13 @@ static Calendar *createStandardCalendar(ECalType calType, const Locale &loc, UEr
cal.adoptInsteadAndCheckErrorCode(new CopticCalendar(loc, status), status);
break;
case CALTYPE_ETHIOPIC:
cal.adoptInsteadAndCheckErrorCode(new EthiopicCalendar(loc, status, EthiopicCalendar::AMETE_MIHRET_ERA), status);
cal.adoptInsteadAndCheckErrorCode(new EthiopicCalendar(loc, status), status);
break;
case CALTYPE_ETHIOPIC_AMETE_ALEM:
cal.adoptInsteadAndCheckErrorCode(new EthiopicCalendar(loc, status, EthiopicCalendar::AMETE_ALEM_ERA), status);
cal.adoptInsteadAndCheckErrorCode(new EthiopicAmeteAlemCalendar(loc, status), status);
break;
case CALTYPE_ISO8601:
cal.adoptInsteadAndCheckErrorCode(new GregorianCalendar(loc, status), status);
if (cal.isValid()) {
cal->setFirstDayOfWeek(UCAL_MONDAY);
cal->setMinimalDaysInFirstWeek(4);
}
cal.adoptInsteadAndCheckErrorCode(new ISO8601Calendar(loc, status), status);
break;
case CALTYPE_DANGI:
cal.adoptInsteadAndCheckErrorCode(new DangiCalendar(loc, status), status);

View file

@ -19,6 +19,7 @@
U_NAMESPACE_BEGIN
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(EthiopicCalendar)
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(EthiopicAmeteAlemCalendar)
//static const int32_t JD_EPOCH_OFFSET_AMETE_ALEM = -285019;
static const int32_t JD_EPOCH_OFFSET_AMETE_MIHRET = 1723856;
@ -29,16 +30,8 @@ static const int32_t AMETE_MIHRET_DELTA = 5500; // 5501 - 1 (Amete Alem 5501 = A
//-------------------------------------------------------------------------
EthiopicCalendar::EthiopicCalendar(const Locale& aLocale,
UErrorCode& success,
EEraType type /*= AMETE_MIHRET_ERA*/)
: CECalendar(aLocale, success),
eraType(type)
{
}
EthiopicCalendar::EthiopicCalendar(const EthiopicCalendar& other)
: CECalendar(other),
eraType(other.eraType)
UErrorCode& success)
: CECalendar(aLocale, success)
{
}
@ -55,24 +48,9 @@ EthiopicCalendar::clone() const
const char *
EthiopicCalendar::getType() const
{
if (isAmeteAlemEra()) {
return "ethiopic-amete-alem";
}
return "ethiopic";
}
void
EthiopicCalendar::setAmeteAlemEra(UBool onOff)
{
eraType = onOff ? AMETE_ALEM_ERA : AMETE_MIHRET_ERA;
}
UBool
EthiopicCalendar::isAmeteAlemEra() const
{
return (eraType == AMETE_ALEM_ERA);
}
//-------------------------------------------------------------------------
// Calendar framework
//-------------------------------------------------------------------------
@ -82,63 +60,31 @@ EthiopicCalendar::handleGetExtendedYear()
{
// Ethiopic calendar uses EXTENDED_YEAR aligned to
// Amelete Hihret year always.
int32_t eyear;
if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
eyear = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
} else if (isAmeteAlemEra()) {
eyear = internalGet(UCAL_YEAR, 1 + AMETE_MIHRET_DELTA)
- AMETE_MIHRET_DELTA; // Default to year 1 of Amelete Mihret
} else {
// The year defaults to the epoch start, the era to AMETE_MIHRET
int32_t era = internalGet(UCAL_ERA, AMETE_MIHRET);
if (era == AMETE_MIHRET) {
eyear = internalGet(UCAL_YEAR, 1); // Default to year 1
} else {
eyear = internalGet(UCAL_YEAR, 1) - AMETE_MIHRET_DELTA;
}
return internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
}
return eyear;
// The year defaults to the epoch start, the era to AMETE_MIHRET
if (internalGet(UCAL_ERA, AMETE_MIHRET) == AMETE_MIHRET) {
return internalGet(UCAL_YEAR, 1); // Default to year 1
}
return internalGet(UCAL_YEAR, 1) - AMETE_MIHRET_DELTA;
}
void
EthiopicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &/*status*/)
{
int32_t eyear, month, day, era, year;
int32_t eyear, month, day;
jdToCE(julianDay, getJDEpochOffset(), eyear, month, day);
if (isAmeteAlemEra()) {
era = AMETE_ALEM;
year = eyear + AMETE_MIHRET_DELTA;
} else {
if (eyear > 0) {
era = AMETE_MIHRET;
year = eyear;
} else {
era = AMETE_ALEM;
year = eyear + AMETE_MIHRET_DELTA;
}
}
internalSet(UCAL_EXTENDED_YEAR, eyear);
internalSet(UCAL_ERA, era);
internalSet(UCAL_YEAR, year);
internalSet(UCAL_ERA, (eyear > 0) ? AMETE_MIHRET : AMETE_ALEM);
internalSet(UCAL_YEAR, (eyear > 0) ? eyear : (eyear + AMETE_MIHRET_DELTA));
internalSet(UCAL_MONTH, month);
internalSet(UCAL_DATE, day);
internalSet(UCAL_DAY_OF_YEAR, (30 * month) + day);
}
int32_t
EthiopicCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const
{
if (isAmeteAlemEra() && field == UCAL_ERA) {
return 0; // Only one era in this mode, era is always 0
}
return CECalendar::handleGetLimit(field, limitType);
}
constexpr uint32_t kEthiopicRelatedYearDiff = 8;
constexpr uint32_t kEthiopicAmeteAlemRelatedYearDiff = -5492;
int32_t EthiopicCalendar::getRelatedYear(UErrorCode &status) const
{
@ -146,14 +92,13 @@ int32_t EthiopicCalendar::getRelatedYear(UErrorCode &status) const
if (U_FAILURE(status)) {
return 0;
}
return year + (isAmeteAlemEra() ? kEthiopicAmeteAlemRelatedYearDiff : kEthiopicRelatedYearDiff);
return year + kEthiopicRelatedYearDiff;
}
void EthiopicCalendar::setRelatedYear(int32_t year)
{
// set extended year
set(UCAL_EXTENDED_YEAR, year -
(isAmeteAlemEra() ? kEthiopicAmeteAlemRelatedYearDiff : kEthiopicRelatedYearDiff));
set(UCAL_EXTENDED_YEAR, year - kEthiopicRelatedYearDiff);
}
/**
@ -193,9 +138,6 @@ EthiopicCalendar::defaultCenturyStartYear() const
{
// lazy-evaluate systemDefaultCenturyStartYear
umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
if (isAmeteAlemEra()) {
return gSystemDefaultCenturyStartYear + AMETE_MIHRET_DELTA;
}
return gSystemDefaultCenturyStartYear;
}
@ -222,6 +164,94 @@ EthiopicCalendar::ethiopicToJD(int32_t year, int32_t month, int32_t date)
}
#endif
//-------------------------------------------------------------------------
// Constructors...
//-------------------------------------------------------------------------
EthiopicAmeteAlemCalendar::EthiopicAmeteAlemCalendar(const Locale& aLocale,
UErrorCode& success)
: EthiopicCalendar(aLocale, success)
{
}
EthiopicAmeteAlemCalendar::~EthiopicAmeteAlemCalendar()
{
}
EthiopicAmeteAlemCalendar*
EthiopicAmeteAlemCalendar::clone() const
{
return new EthiopicAmeteAlemCalendar(*this);
}
//-------------------------------------------------------------------------
// Calendar framework
//-------------------------------------------------------------------------
const char *
EthiopicAmeteAlemCalendar::getType() const
{
return "ethiopic-amete-alem";
}
int32_t
EthiopicAmeteAlemCalendar::handleGetExtendedYear()
{
// Ethiopic calendar uses EXTENDED_YEAR aligned to
// Amelete Hihret year always.
if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
return internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
}
return internalGet(UCAL_YEAR, 1 + AMETE_MIHRET_DELTA)
- AMETE_MIHRET_DELTA; // Default to year 1 of Amelete Mihret
}
void
EthiopicAmeteAlemCalendar::handleComputeFields(int32_t julianDay, UErrorCode &/*status*/)
{
int32_t eyear, month, day;
jdToCE(julianDay, getJDEpochOffset(), eyear, month, day);
internalSet(UCAL_EXTENDED_YEAR, eyear);
internalSet(UCAL_ERA, AMETE_ALEM);
internalSet(UCAL_YEAR, eyear + AMETE_MIHRET_DELTA);
internalSet(UCAL_MONTH, month);
internalSet(UCAL_DATE, day);
internalSet(UCAL_DAY_OF_YEAR, (30 * month) + day);
}
int32_t
EthiopicAmeteAlemCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const
{
if (field == UCAL_ERA) {
return 0; // Only one era in this mode, era is always 0
}
return EthiopicCalendar::handleGetLimit(field, limitType);
}
constexpr uint32_t kEthiopicAmeteAlemRelatedYearDiff = -5492;
int32_t EthiopicAmeteAlemCalendar::getRelatedYear(UErrorCode &status) const
{
int32_t year = get(UCAL_EXTENDED_YEAR, status);
if (U_FAILURE(status)) {
return 0;
}
return year + kEthiopicAmeteAlemRelatedYearDiff;
}
void EthiopicAmeteAlemCalendar::setRelatedYear(int32_t year)
{
// set extended year
set(UCAL_EXTENDED_YEAR, year - kEthiopicAmeteAlemRelatedYearDiff);
}
int32_t
EthiopicAmeteAlemCalendar::defaultCenturyStartYear() const
{
return EthiopicCalendar::defaultCenturyStartYear() + AMETE_MIHRET_DELTA;
}
U_NAMESPACE_END
#endif

View file

@ -26,15 +26,6 @@ U_NAMESPACE_BEGIN
class EthiopicCalendar : public CECalendar {
public:
/**
* Calendar type - use Amete Alem era for all the time or not
* @internal
*/
enum EEraType {
AMETE_MIHRET_ERA,
AMETE_ALEM_ERA
};
/**
* Useful constants for EthiopicCalendar.
* @internal
@ -122,13 +113,13 @@ public:
* only use Amete Alem for all the time.
* @internal
*/
EthiopicCalendar(const Locale& aLocale, UErrorCode& success, EEraType type = AMETE_MIHRET_ERA);
EthiopicCalendar(const Locale& aLocale, UErrorCode& success);
/**
* Copy Constructor
* @internal
*/
EthiopicCalendar(const EthiopicCalendar& other);
EthiopicCalendar(const EthiopicCalendar& other) = default;
/**
* Destructor.
@ -144,26 +135,12 @@ public:
virtual EthiopicCalendar* clone() const override;
/**
* return the calendar type, "ethiopic"
* Return the calendar type, "ethiopic"
* @return calendar type
* @internal
*/
virtual const char * getType() const override;
/**
* Set Alem or Mihret era.
* @param onOff Set Amete Alem era if true, otherwise set Amete Mihret era.
* @internal
*/
void setAmeteAlemEra (UBool onOff);
/**
* Return true if this calendar is set to the Amete Alem era.
* @return true if set to the Amete Alem era.
* @internal
*/
UBool isAmeteAlemEra() const;
/**
* @return The related Gregorian year; will be obtained by modifying the value
* obtained by get from UCAL_EXTENDED_YEAR field
@ -185,6 +162,11 @@ protected:
/**
* Return the extended year defined by the current fields.
* This calendar uses both AMETE_ALEM and AMETE_MIHRET.
*
* EXTENDED_YEAR ERA YEAR
* 0 AMETE_ALEM 5500
* 1 AMETE_MIHRET 1
* @internal
*/
virtual int32_t handleGetExtendedYear() override;
@ -195,12 +177,6 @@ protected:
*/
virtual void handleComputeFields(int32_t julianDay, UErrorCode &status) override;
/**
* Calculate the limit for a specified type of limit and field
* @internal
*/
virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const override;
/**
* Returns the date of the start of the default century
* @return start of century - in milliseconds since epoch, 1970
@ -220,18 +196,6 @@ protected:
*/
virtual int32_t getJDEpochOffset() const override;
private:
/**
* When eraType is AMETE_ALEM_ERA, then this calendar use only AMETE_ALEM
* for the era. Otherwise (default), this calendar uses both AMETE_ALEM
* and AMETE_MIHRET.
*
* EXTENDED_YEAR AMETE_ALEM_ERA AMETE_MIHRET_ERA
* 0 Amete Alem 5500 Amete Alem 5500
* 1 Amete Mihret 1 Amete Alem 5501
*/
EEraType eraType;
public:
/**
* Override Calendar Returns a unique class ID POLYMORPHICALLY. Pure virtual
@ -280,6 +244,123 @@ public:
#endif
};
/**
* Implement the Ethiopic Amete Alem calendar system.
* @internal
*/
class EthiopicAmeteAlemCalendar : public EthiopicCalendar {
public:
/**
* Constructs a EthiopicAmeteAlemCalendar based on the current time in the default time zone
* with the given locale.
*
* @param aLocale The given locale.
* @param success Indicates the status of EthiopicCalendar object construction.
* Returns U_ZERO_ERROR if constructed successfully.
* @internal
*/
EthiopicAmeteAlemCalendar(const Locale& aLocale, UErrorCode& success);
/**
* Copy Constructor
* @internal
*/
EthiopicAmeteAlemCalendar(const EthiopicAmeteAlemCalendar& other) = default;
/**
* Destructor.
* @internal
*/
virtual ~EthiopicAmeteAlemCalendar();
/**
* Create and return a polymorphic copy of this calendar.
* @return return a polymorphic copy of this calendar.
* @internal
*/
virtual EthiopicAmeteAlemCalendar* clone() const override;
/**
* Return the calendar type, "ethiopic-amete-alem"
* @return calendar type
* @internal
*/
virtual const char * getType() const override;
/**
* Override Calendar Returns a unique class ID POLYMORPHICALLY. Pure virtual
* override. This method is to implement a simple version of RTTI, since not all C++
* compilers support genuine RTTI. Polymorphic operator==() and clone() methods call
* this method.
*
* @return The class ID for this object. All objects of a given class have the
* same class ID. Objects of other classes have different class IDs.
* @internal
*/
virtual UClassID getDynamicClassID(void) const override;
/**
* Return the class ID for this class. This is useful only for comparing to a return
* value from getDynamicClassID(). For example:
*
* Base* polymorphic_pointer = createPolymorphicObject();
* if (polymorphic_pointer->getDynamicClassID() ==
* Derived::getStaticClassID()) ...
*
* @return The class ID for all objects of this class.
* @internal
*/
U_I18N_API static UClassID U_EXPORT2 getStaticClassID(void);
/**
* @return The related Gregorian year; will be obtained by modifying the value
* obtained by get from UCAL_EXTENDED_YEAR field
* @internal
*/
virtual int32_t getRelatedYear(UErrorCode &status) const override;
/**
* @param year The related Gregorian year to set; will be modified as necessary then
* set in UCAL_EXTENDED_YEAR field
* @internal
*/
virtual void setRelatedYear(int32_t year) override;
protected:
//-------------------------------------------------------------------------
// Calendar framework
//-------------------------------------------------------------------------
/**
* Return the extended year defined by the current fields.
* This calendar use only AMETE_ALEM for the era.
*
* EXTENDED_YEAR ERA YEAR
* 0 AMETE_ALEM 5500
* 1 AMETE_ALEM 5501
* @internal
*/
virtual int32_t handleGetExtendedYear() override;
/**
* Compute fields from the JD
* @internal
*/
virtual void handleComputeFields(int32_t julianDay, UErrorCode &status) override;
/**
* Calculate the limit for a specified type of limit and field
* @internal
*/
virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const override;
/**
* Returns the year in which the default century begins
* @internal
*/
virtual int32_t defaultCenturyStartYear() const override;
};
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */
#endif /* ETHPCCAL_H */

View file

@ -166,6 +166,7 @@
<ClCompile Include="hebrwcal.cpp" />
<ClCompile Include="indiancal.cpp" />
<ClCompile Include="islamcal.cpp" />
<ClCompile Include="iso8601cal.cpp" />
<ClCompile Include="japancal.cpp" />
<ClCompile Include="listformatter.cpp" />
<ClCompile Include="ulistformatter.cpp" />
@ -384,6 +385,7 @@
<ClInclude Include="hebrwcal.h" />
<ClInclude Include="indiancal.h" />
<ClInclude Include="islamcal.h" />
<ClInclude Include="iso8601cal.h" />
<ClInclude Include="japancal.h" />
<ClInclude Include="measunit_impl.h" />
<ClInclude Include="msgfmt_impl.h" />

View file

@ -186,6 +186,9 @@
<ClCompile Include="indiancal.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="iso8601cal.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="islamcal.cpp">
<Filter>formatting</Filter>
</ClCompile>
@ -851,6 +854,9 @@
<ClInclude Include="indiancal.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="iso8601cal.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="islamcal.h">
<Filter>formatting</Filter>
</ClInclude>

View file

@ -399,6 +399,7 @@
<ClCompile Include="hebrwcal.cpp" />
<ClCompile Include="indiancal.cpp" />
<ClCompile Include="islamcal.cpp" />
<ClCompile Include="iso8601cal.cpp" />
<ClCompile Include="japancal.cpp" />
<ClCompile Include="listformatter.cpp" />
<ClCompile Include="ulistformatter.cpp" />
@ -615,6 +616,7 @@
<ClInclude Include="hebrwcal.h" />
<ClInclude Include="indiancal.h" />
<ClInclude Include="islamcal.h" />
<ClInclude Include="iso8601cal.h" />
<ClInclude Include="japancal.h" />
<ClInclude Include="measunit_impl.h" />
<ClInclude Include="msgfmt_impl.h" />

View file

@ -206,67 +206,22 @@ int32_t getUmalqura_MonthLength(int32_t y, int32_t m) {
//-------------------------------------------------------------------------
const char *IslamicCalendar::getType() const {
const char *sType = NULL;
switch (cType) {
case CIVIL:
sType = "islamic-civil";
break;
case ASTRONOMICAL:
sType = "islamic";
break;
case TBLA:
sType = "islamic-tbla";
break;
case UMALQURA:
sType = "islamic-umalqura";
break;
default:
UPRV_UNREACHABLE_EXIT; // out of range
}
return sType;
return "islamic";
}
IslamicCalendar* IslamicCalendar::clone() const {
return new IslamicCalendar(*this);
}
IslamicCalendar::IslamicCalendar(const Locale& aLocale, UErrorCode& success, ECalculationType type)
: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success),
cType(type)
IslamicCalendar::IslamicCalendar(const Locale& aLocale, UErrorCode& success)
: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success)
{
setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
}
IslamicCalendar::IslamicCalendar(const IslamicCalendar& other) : Calendar(other), cType(other.cType) {
}
IslamicCalendar::~IslamicCalendar()
{
}
void IslamicCalendar::setCalculationType(ECalculationType type, UErrorCode &status)
{
if (cType != type) {
// The fields of the calendar will become invalid, because the calendar
// rules are different
UDate m = getTimeInMillis(status);
cType = type;
clear();
setTimeInMillis(m, status);
}
}
/**
* Returns <code>true</code> if this object is using the fixed-cycle civil
* calendar, or <code>false</code> if using the religious, astronomical
* calendar.
* @draft ICU 2.4
*/
UBool IslamicCalendar::isCivil() {
return (cType == CIVIL);
}
//-------------------------------------------------------------------------
// Minimum / Maximum access functions
//-------------------------------------------------------------------------
@ -365,19 +320,7 @@ UBool IslamicCalendar::civilLeapYear(int32_t year)
* from the Hijri epoch, origin 0.
*/
int32_t IslamicCalendar::yearStart(int32_t year) const{
if (cType == CIVIL || cType == TBLA ||
(cType == UMALQURA && (year < UMALQURA_YEAR_START || year > UMALQURA_YEAR_END)))
{
return (year-1)*354 + ClockMath::floorDivide((3+11*(int64_t)year),(int64_t)30);
} else if(cType==ASTRONOMICAL){
return trueMonthStart(12*(year-1));
} else {
year -= UMALQURA_YEAR_START;
// rounded least-squares fit of the dates previously calculated from UMALQURA_MONTHLENGTH iteration
int32_t yrStartLinearEstimate = (int32_t)((354.36720 * (double)year) + 460322.05 + 0.5);
// need a slight correction to some
return yrStartLinearEstimate + umAlQuraYrStartEstimateFix[year];
}
return trueMonthStart(12*(year-1));
}
/**
@ -388,19 +331,7 @@ int32_t IslamicCalendar::yearStart(int32_t year) const{
* @param month The hijri month, 0-based (assumed to be in range 0..11)
*/
int32_t IslamicCalendar::monthStart(int32_t year, int32_t month) const {
if (cType == CIVIL || cType == TBLA) {
// This does not handle months out of the range 0..11
return (int32_t)uprv_ceil(29.5*month)
+ (year-1)*354 + (int32_t)ClockMath::floorDivide((3+11*(int64_t)year),(int64_t)30);
} else if(cType==ASTRONOMICAL){
return trueMonthStart(12*(year-1) + month);
} else {
int32_t ms = yearStart(year);
for(int i=0; i< month; i++){
ms+= handleGetMonthLength(year, i);
}
return ms;
}
return trueMonthStart(12*(year-1) + month);
}
/**
@ -506,22 +437,8 @@ double IslamicCalendar::moonAge(UDate time, UErrorCode &status)
* @draft ICU 2.4
*/
int32_t IslamicCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const {
int32_t length = 0;
if (cType == CIVIL || cType == TBLA ||
(cType == UMALQURA && (extendedYear<UMALQURA_YEAR_START || extendedYear>UMALQURA_YEAR_END)) ) {
length = 29 + (month+1) % 2;
if (month == DHU_AL_HIJJAH && civilLeapYear(extendedYear)) {
length++;
}
} else if(cType == ASTRONOMICAL){
month = 12*(extendedYear-1) + month;
length = trueMonthStart(month+1) - trueMonthStart(month) ;
} else {
length = getUmalqura_MonthLength(extendedYear - UMALQURA_YEAR_START, month);
}
return length;
month = 12*(extendedYear-1) + month;
return trueMonthStart(month+1) - trueMonthStart(month) ;
}
/**
@ -529,19 +446,8 @@ int32_t IslamicCalendar::handleGetMonthLength(int32_t extendedYear, int32_t mont
* @draft ICU 2.4
*/
int32_t IslamicCalendar::handleGetYearLength(int32_t extendedYear) const {
if (cType == CIVIL || cType == TBLA ||
(cType == UMALQURA && (extendedYear<UMALQURA_YEAR_START || extendedYear>UMALQURA_YEAR_END)) ) {
return 354 + (civilLeapYear(extendedYear) ? 1 : 0);
} else if(cType == ASTRONOMICAL){
int32_t month = 12*(extendedYear-1);
return (trueMonthStart(month + 12) - trueMonthStart(month));
} else {
int len = 0;
for(int i=0; i<12; i++) {
len += handleGetMonthLength(extendedYear, i);
}
return len;
}
int32_t month = 12*(extendedYear-1);
return (trueMonthStart(month + 12) - trueMonthStart(month));
}
//-------------------------------------------------------------------------
@ -567,8 +473,8 @@ int32_t IslamicCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, U
eyear += (month / 12) - 1;
month = (month % 12) + 11;
}
return monthStart(eyear, month) + ((cType == TBLA)? ASTRONOMICAL_EPOC: CIVIL_EPOC) - 1;
}
return monthStart(eyear, month) + getEpoc() - 1;
}
//-------------------------------------------------------------------------
// Functions for converting from milliseconds to field values
@ -604,93 +510,49 @@ int32_t IslamicCalendar::handleGetExtendedYear() {
* @draft ICU 2.4
*/
void IslamicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
int32_t year, month, dayOfMonth, dayOfYear;
int32_t startDate;
int32_t days = julianDay - CIVIL_EPOC;
if (U_FAILURE(status)) return;
int32_t days = julianDay - getEpoc();
if (cType == CIVIL || cType == TBLA) {
if(cType == TBLA) {
days = julianDay - ASTRONOMICAL_EPOC;
}
// Use the civil calendar approximation, which is just arithmetic
year = (int32_t)ClockMath::floorDivide(30 * (int64_t)days + 10646, (int64_t)10631);
month = (int32_t)uprv_ceil((days - 29 - yearStart(year)) / 29.5 );
month = month<11?month:11;
startDate = monthStart(year, month);
} else if(cType == ASTRONOMICAL){
// Guess at the number of elapsed full months since the epoch
int32_t months = (int32_t)uprv_floor((double)days / CalendarAstronomer::SYNODIC_MONTH);
// Guess at the number of elapsed full months since the epoch
int32_t month = (int32_t)uprv_floor((double)days / CalendarAstronomer::SYNODIC_MONTH);
startDate = (int32_t)uprv_floor(months * CalendarAstronomer::SYNODIC_MONTH);
int32_t startDate = (int32_t)uprv_floor(month * CalendarAstronomer::SYNODIC_MONTH);
double age = moonAge(internalGetTime(), status);
if (U_FAILURE(status)) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
if ( days - startDate >= 25 && age > 0) {
// If we're near the end of the month, assume next month and search backwards
months++;
}
// Find out the last time that the new moon was actually visible at this longitude
// This returns midnight the night that the moon was visible at sunset.
while ((startDate = trueMonthStart(months)) > days) {
// If it was after the date in question, back up a month and try again
months--;
}
year = months >= 0 ? ((months / 12) + 1) : ((months + 1 ) / 12);
month = ((months % 12) + 12 ) % 12;
} else if(cType == UMALQURA) {
int32_t umalquraStartdays = yearStart(UMALQURA_YEAR_START) ;
if( days < umalquraStartdays){
//Use Civil calculation
year = (int32_t)ClockMath::floorDivide(
(30 * (int64_t)days + 10646) , (int64_t)10631.0 );
month = (int32_t)uprv_ceil((days - 29 - yearStart(year)) / 29.5 );
month = month<11?month:11;
startDate = monthStart(year, month);
}else{
int y =UMALQURA_YEAR_START-1, m =0;
long d = 1;
while(d > 0){
y++;
d = days - yearStart(y) +1;
if(d == handleGetYearLength(y)){
m=11;
break;
}else if(d < handleGetYearLength(y) ){
int monthLen = handleGetMonthLength(y, m);
m=0;
while(d > monthLen){
d -= monthLen;
m++;
monthLen = handleGetMonthLength(y, m);
}
break;
}
}
year = y;
month = m;
}
} else { // invalid 'civil'
UPRV_UNREACHABLE_EXIT; // should not get here, out of range
double age = moonAge(internalGetTime(), status);
if (U_FAILURE(status)) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
if ( days - startDate >= 25 && age > 0) {
// If we're near the end of the month, assume next month and search backwards
month++;
}
dayOfMonth = (days - monthStart(year, month)) + 1;
// Find out the last time that the new moon was actually visible at this longitude
// This returns midnight the night that the moon was visible at sunset.
while ((startDate = trueMonthStart(month)) > days) {
// If it was after the date in question, back up a month and try again
month--;
}
int32_t year = month >= 0 ? ((month / 12) + 1) : ((month + 1 ) / 12);
month = ((month % 12) + 12 ) % 12;
int32_t dayOfMonth = (days - monthStart(year, month)) + 1;
// Now figure out the day of the year.
dayOfYear = (days - monthStart(year, 0)) + 1;
int32_t dayOfYear = (days - monthStart(year, 0)) + 1;
internalSet(UCAL_ERA, 0);
internalSet(UCAL_YEAR, year);
internalSet(UCAL_EXTENDED_YEAR, year);
internalSet(UCAL_MONTH, month);
internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
}
internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
}
int32_t IslamicCalendar::getEpoc() const {
return CIVIL_EPOC;
}
static int32_t gregoYearFromIslamicStart(int32_t year) {
// ad hoc conversion, improve under #10752
@ -789,9 +651,315 @@ IslamicCalendar::initializeSystemDefaultCentury()
// out.
}
/*****************************************************************************
* IslamicCivilCalendar
*****************************************************************************/
IslamicCivilCalendar::IslamicCivilCalendar(const Locale& aLocale, UErrorCode& success)
: IslamicCalendar(aLocale, success)
{
}
IslamicCivilCalendar::~IslamicCivilCalendar()
{
}
const char *IslamicCivilCalendar::getType() const {
return "islamic-civil";
}
IslamicCivilCalendar* IslamicCivilCalendar::clone() const {
return new IslamicCivilCalendar(*this);
}
/**
* Return the day # on which the given year starts. Days are counted
* from the Hijri epoch, origin 0.
*/
int32_t IslamicCivilCalendar::yearStart(int32_t year) const{
return static_cast<int32_t>(
(year-1)*354 + ClockMath::floorDivide((3+11*static_cast<int64_t>(year)),
static_cast<int64_t>(30)));
}
/**
* Return the day # on which the given month starts. Days are counted
* from the Hijri epoch, origin 0.
*
* @param year The hijri year
* @param month The hijri month, 0-based (assumed to be in range 0..11)
*/
int32_t IslamicCivilCalendar::monthStart(int32_t year, int32_t month) const {
// This does not handle months out of the range 0..11
return static_cast<int32_t>(
uprv_ceil(29.5*month) + (year-1)*354 +
static_cast<int32_t>(ClockMath::floorDivide(
3+11*static_cast<int64_t>(year),
static_cast<int64_t>(30))));
}
/**
* Return the length (in days) of the given month.
*
* @param year The hijri year
* @param year The hijri month, 0-based
* @draft ICU 2.4
*/
int32_t IslamicCivilCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const {
int32_t length = 29 + (month+1) % 2;
if (month == DHU_AL_HIJJAH && civilLeapYear(extendedYear)) {
length++;
}
return length;
}
/**
* Return the number of days in the given Islamic year
* @draft ICU 2.4
*/
int32_t IslamicCivilCalendar::handleGetYearLength(int32_t extendedYear) const {
return 354 + (civilLeapYear(extendedYear) ? 1 : 0);
}
/**
* Override Calendar to compute several fields specific to the Islamic
* calendar system. These are:
*
* <ul><li>ERA
* <li>YEAR
* <li>MONTH
* <li>DAY_OF_MONTH
* <li>DAY_OF_YEAR
* <li>EXTENDED_YEAR</ul>
*
* The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
* method is called. The getGregorianXxx() methods return Gregorian
* calendar equivalents for the given Julian day.
* @draft ICU 2.4
*/
void IslamicCivilCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
if (U_FAILURE(status)) return;
int32_t days = julianDay - getEpoc();
// Use the civil calendar approximation, which is just arithmetic
int32_t year = static_cast<int32_t>(
ClockMath::floorDivide(30 * static_cast<int64_t>(days) + 10646,
static_cast<int64_t>(10631)));
int32_t month = static_cast<int32_t>(
uprv_ceil((days - 29 - yearStart(year)) / 29.5 ));
month = month<11?month:11;
int32_t dayOfMonth = (days - monthStart(year, month)) + 1;
// Now figure out the day of the year.
int32_t dayOfYear = (days - monthStart(year, 0)) + 1;
internalSet(UCAL_ERA, 0);
internalSet(UCAL_YEAR, year);
internalSet(UCAL_EXTENDED_YEAR, year);
internalSet(UCAL_MONTH, month);
internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
}
/*****************************************************************************
* IslamicTBLACalendar
*****************************************************************************/
IslamicTBLACalendar::IslamicTBLACalendar(const Locale& aLocale, UErrorCode& success)
: IslamicCivilCalendar(aLocale, success)
{
}
IslamicTBLACalendar::~IslamicTBLACalendar()
{
}
const char *IslamicTBLACalendar::getType() const {
return "islamic-tbla";
}
IslamicTBLACalendar* IslamicTBLACalendar::clone() const {
return new IslamicTBLACalendar(*this);
}
int32_t IslamicTBLACalendar::getEpoc() const {
return ASTRONOMICAL_EPOC;
}
/*****************************************************************************
* IslamicUmalquraCalendar
*****************************************************************************/
IslamicUmalquraCalendar::IslamicUmalquraCalendar(const Locale& aLocale, UErrorCode& success)
: IslamicCalendar(aLocale, success)
{
}
IslamicUmalquraCalendar::~IslamicUmalquraCalendar()
{
}
const char *IslamicUmalquraCalendar::getType() const {
return "islamic-umalqura";
}
IslamicUmalquraCalendar* IslamicUmalquraCalendar::clone() const {
return new IslamicUmalquraCalendar(*this);
}
/**
* Return the day # on which the given year starts. Days are counted
* from the Hijri epoch, origin 0.
*/
int32_t IslamicUmalquraCalendar::yearStart(int32_t year) const {
if (year < UMALQURA_YEAR_START || year > UMALQURA_YEAR_END) {
return static_cast<int32_t>(
(year-1)*354 + ClockMath::floorDivide((3+11*static_cast<int64_t>(year)),
static_cast<int64_t>(30)));
}
year -= UMALQURA_YEAR_START;
// rounded least-squares fit of the dates previously calculated from UMALQURA_MONTHLENGTH iteration
int32_t yrStartLinearEstimate = static_cast<int32_t>(
(354.36720 * (double)year) + 460322.05 + 0.5);
// need a slight correction to some
return yrStartLinearEstimate + umAlQuraYrStartEstimateFix[year];
}
/**
* Return the day # on which the given month starts. Days are counted
* from the Hijri epoch, origin 0.
*
* @param year The hijri year
* @param month The hijri month, 0-based (assumed to be in range 0..11)
*/
int32_t IslamicUmalquraCalendar::monthStart(int32_t year, int32_t month) const {
int32_t ms = yearStart(year);
for(int i=0; i< month; i++){
ms+= handleGetMonthLength(year, i);
}
return ms;
}
/**
* Return the length (in days) of the given month.
*
* @param year The hijri year
* @param year The hijri month, 0-based
*/
int32_t IslamicUmalquraCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const {
int32_t length = 0;
if (extendedYear<UMALQURA_YEAR_START || extendedYear>UMALQURA_YEAR_END) {
length = 29 + (month+1) % 2;
if (month == DHU_AL_HIJJAH && civilLeapYear(extendedYear)) {
length++;
}
return length;
}
return getUmalqura_MonthLength(extendedYear - UMALQURA_YEAR_START, month);
}
/**
* Return the number of days in the given Islamic year
* @draft ICU 2.4
*/
int32_t IslamicUmalquraCalendar::handleGetYearLength(int32_t extendedYear) const {
if (extendedYear<UMALQURA_YEAR_START || extendedYear>UMALQURA_YEAR_END) {
return 354 + (civilLeapYear(extendedYear) ? 1 : 0);
}
int len = 0;
for(int i=0; i<12; i++) {
len += handleGetMonthLength(extendedYear, i);
}
return len;
}
/**
* Override Calendar to compute several fields specific to the Islamic
* calendar system. These are:
*
* <ul><li>ERA
* <li>YEAR
* <li>MONTH
* <li>DAY_OF_MONTH
* <li>DAY_OF_YEAR
* <li>EXTENDED_YEAR</ul>
*
* The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
* method is called. The getGregorianXxx() methods return Gregorian
* calendar equivalents for the given Julian day.
* @draft ICU 2.4
*/
void IslamicUmalquraCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
if (U_FAILURE(status)) return;
int32_t year, month, dayOfMonth, dayOfYear;
int32_t days = julianDay - getEpoc();
int32_t umalquraStartdays = yearStart(UMALQURA_YEAR_START) ;
if (days < umalquraStartdays) {
//Use Civil calculation
year = (int32_t)ClockMath::floorDivide(
(30 * (int64_t)days + 10646) , (int64_t)10631.0 );
month = (int32_t)uprv_ceil((days - 29 - yearStart(year)) / 29.5 );
month = month < 11 ? month : 11;
} else {
int y =UMALQURA_YEAR_START-1, m =0;
long d = 1;
while (d > 0) {
y++;
d = days - yearStart(y) +1;
if (d == handleGetYearLength(y)) {
m=11;
break;
}
if (d < handleGetYearLength(y)){
int monthLen = handleGetMonthLength(y, m);
m=0;
while(d > monthLen){
d -= monthLen;
m++;
monthLen = handleGetMonthLength(y, m);
}
break;
}
}
year = y;
month = m;
}
dayOfMonth = (days - monthStart(year, month)) + 1;
// Now figure out the day of the year.
dayOfYear = (days - monthStart(year, 0)) + 1;
internalSet(UCAL_ERA, 0);
internalSet(UCAL_YEAR, year);
internalSet(UCAL_EXTENDED_YEAR, year);
internalSet(UCAL_MONTH, month);
internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
}
/*****************************************************************************
* IslamicRGSACalendar
*****************************************************************************/
IslamicRGSACalendar::IslamicRGSACalendar(const Locale& aLocale, UErrorCode& success)
: IslamicCalendar(aLocale, success)
{
}
IslamicRGSACalendar::~IslamicRGSACalendar()
{
}
const char *IslamicRGSACalendar::getType() const {
return "islamic-rgsa";
}
IslamicRGSACalendar* IslamicRGSACalendar::clone() const {
return new IslamicRGSACalendar(*this);
}
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicCalendar)
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicCivilCalendar)
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicUmalquraCalendar)
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicTBLACalendar)
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicRGSACalendar)
U_NAMESPACE_END

View file

@ -53,7 +53,8 @@ U_NAMESPACE_BEGIN
* every 30 years. This calendar is easily calculated and thus predictable in
* advance, so it is used as the civil calendar in a number of Arab countries.
* This is the default behavior of a newly-created <code>IslamicCalendar</code>
* object.
* object. This calendar variant is implemented in the IslamicCivilCalendar
* class.
* <p>
* The Islamic <em>religious</em> calendar, however, is based on the <em>observation</em>
* of the crescent moon. It is thus affected by the position at which the
@ -71,10 +72,6 @@ U_NAMESPACE_BEGIN
* calculations. At present, the approximations used in this class are fairly
* simplistic; they will be improved in later versions of the code.
* <p>
* The {@link #setCivil setCivil} method determines
* which approach is used to determine the start of a month. By default, the
* fixed-cycle civil calendar is used. However, if <code>setCivil(false)</code>
* is called, an approximation of the true lunar calendar will be used.
*
* @see GregorianCalendar
*
@ -88,18 +85,6 @@ class U_I18N_API IslamicCalendar : public Calendar {
//-------------------------------------------------------------------------
// Constants...
//-------------------------------------------------------------------------
/**
* Calendar type - civil or religious or um alqura
* @internal
*/
enum ECalculationType {
ASTRONOMICAL,
CIVIL,
UMALQURA,
TBLA
};
/**
* Constants for the months
* @internal
@ -192,16 +177,15 @@ class U_I18N_API IslamicCalendar : public Calendar {
* @param aLocale The given locale.
* @param success Indicates the status of IslamicCalendar object construction.
* Returns U_ZERO_ERROR if constructed successfully.
* @param type The Islamic calendar calculation type. The default value is CIVIL.
* @internal
*/
IslamicCalendar(const Locale& aLocale, UErrorCode &success, ECalculationType type = CIVIL);
IslamicCalendar(const Locale& aLocale, UErrorCode &success);
/**
* Copy Constructor
* @internal
*/
IslamicCalendar(const IslamicCalendar& other);
IslamicCalendar(const IslamicCalendar& other) = default;
/**
* Destructor.
@ -209,40 +193,20 @@ class U_I18N_API IslamicCalendar : public Calendar {
*/
virtual ~IslamicCalendar();
/**
* Sets Islamic calendar calculation type used by this instance.
*
* @param type The calendar calculation type, <code>CIVIL</code> to use the civil
* calendar, <code>ASTRONOMICAL</code> to use the astronomical calendar.
* @internal
*/
void setCalculationType(ECalculationType type, UErrorCode &status);
/**
* Returns <code>true</code> if this object is using the fixed-cycle civil
* calendar, or <code>false</code> if using the religious, astronomical
* calendar.
* @internal
*/
UBool isCivil();
// TODO: copy c'tor, etc
// clone
virtual IslamicCalendar* clone() const override;
private:
protected:
/**
* Determine whether a year is a leap year in the Islamic civil calendar
*/
static UBool civilLeapYear(int32_t year);
/**
* Return the day # on which the given year starts. Days are counted
* from the Hijri epoch, origin 0.
*/
int32_t yearStart(int32_t year) const;
virtual int32_t yearStart(int32_t year) const;
/**
* Return the day # on which the given month starts. Days are counted
@ -251,7 +215,7 @@ class U_I18N_API IslamicCalendar : public Calendar {
* @param year The hijri year
* @param year The hijri month, 0-based
*/
int32_t monthStart(int32_t year, int32_t month) const;
virtual int32_t monthStart(int32_t year, int32_t month) const;
/**
* Find the day number on which a particular month of the true/lunar
@ -263,6 +227,7 @@ class U_I18N_API IslamicCalendar : public Calendar {
*/
int32_t trueMonthStart(int32_t month) const;
private:
/**
* Return the "age" of the moon at the given time; this is the difference
* in ecliptic latitude between the moon and the sun. This method simply
@ -274,17 +239,6 @@ class U_I18N_API IslamicCalendar : public Calendar {
*/
static double moonAge(UDate time, UErrorCode &status);
//-------------------------------------------------------------------------
// Internal data....
//
/**
* <code>CIVIL</code> if this object uses the fixed-cycle Islamic civil calendar,
* and <code>ASTRONOMICAL</code> if it approximates the true religious calendar using
* astronomical calculations for the time of the new moon.
*/
ECalculationType cType;
//----------------------------------------------------------------------
// Calendar framework
//----------------------------------------------------------------------
@ -346,6 +300,12 @@ class U_I18N_API IslamicCalendar : public Calendar {
*/
virtual void handleComputeFields(int32_t julianDay, UErrorCode &status) override;
/**
* Return the epoc.
* @internal
*/
virtual int32_t getEpoc() const;
// UObject stuff
public:
/**
@ -369,7 +329,7 @@ class U_I18N_API IslamicCalendar : public Calendar {
/*U_I18N_API*/ static UClassID U_EXPORT2 getStaticClassID(void);
/**
* return the calendar type, "buddhist".
* return the calendar type, "islamic".
*
* @return calendar type
* @internal
@ -423,10 +383,372 @@ class U_I18N_API IslamicCalendar : public Calendar {
static void U_CALLCONV initializeSystemDefaultCentury(void);
};
/*
* IslamicCivilCalendar is one of the two main variants of the Islamic calendar.
* The <em>civil</em> calendar, which uses a fixed cycle of alternating 29-
* and 30-day months, with a leap day added to the last month of 11 out of
* every 30 years. This calendar is easily calculated and thus predictable in
* advance, so it is used as the civil calendar in a number of Arab countries.
* This calendar is referring as "Islamic calendar, tabular (intercalary years
* [2,5,7,10,13,16,18,21,24,26,29]- civil epoch" in CLDR.
*/
class U_I18N_API IslamicCivilCalendar : public IslamicCalendar {
public:
/**
* Constructs an IslamicCivilCalendar based on the current time in the default time zone
* with the given locale.
*
* @param aLocale The given locale.
* @param success Indicates the status of IslamicCivilCalendar object construction.
* Returns U_ZERO_ERROR if constructed successfully.
* @internal
*/
IslamicCivilCalendar(const Locale& aLocale, UErrorCode &success);
/**
* Copy Constructor
* @internal
*/
IslamicCivilCalendar(const IslamicCivilCalendar& other) = default;
/**
* Destructor.
* @internal
*/
virtual ~IslamicCivilCalendar();
// clone
virtual IslamicCivilCalendar* clone() const override;
/**
* @return The class ID for this object. All objects of a given class have the
* same class ID. Objects of other classes have different class IDs.
* @internal
*/
virtual UClassID getDynamicClassID(void) const override;
/**
* Return the class ID for this class. This is useful only for comparing to a return
* value from getDynamicClassID(). For example:
*
* Base* polymorphic_pointer = createPolymorphicObject();
* if (polymorphic_pointer->getDynamicClassID() ==
* Derived::getStaticClassID()) ...
*
* @return The class ID for all objects of this class.
* @internal
*/
static UClassID U_EXPORT2 getStaticClassID(void);
/**
* return the calendar type, "islamic-civil".
*
* @return calendar type
* @internal
*/
virtual const char * getType() const override;
protected:
/**
* Return the day # on which the given year starts. Days are counted
* from the Hijri epoch, origin 0.
* @internal
*/
virtual int32_t yearStart(int32_t year) const override;
/**
* Return the day # on which the given month starts. Days are counted
* from the Hijri epoch, origin 0.
*
* @param year The hijri year
* @param year The hijri month, 0-based
* @internal
*/
virtual int32_t monthStart(int32_t year, int32_t month) const override;
/**
* Return the length (in days) of the given month.
*
* @param year The hijri year
* @param year The hijri month, 0-based
* @internal
*/
virtual int32_t handleGetMonthLength(int32_t extendedYear, int32_t month) const override;
/**
* Return the number of days in the given Islamic year
* @internal
*/
virtual int32_t handleGetYearLength(int32_t extendedYear) const override;
/**
* Override Calendar to compute several fields specific to the Islamic
* calendar system. These are:
*
* <ul><li>ERA
* <li>YEAR
* <li>MONTH
* <li>DAY_OF_MONTH
* <li>DAY_OF_YEAR
* <li>EXTENDED_YEAR</ul>
*
* The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
* method is called. The getGregorianXxx() methods return Gregorian
* calendar equivalents for the given Julian day.
* @internal
*/
virtual void handleComputeFields(int32_t julianDay, UErrorCode &status) override;
};
/*
* IslamicTBLACalendar calendar.
* This is a subclass of IslamicCivilCalendar. The only differences in the
* calendar math is it uses different epoch.
* This calendar is referring as "Islamic calendar, tabular (intercalary years
* [2,5,7,10,13,16,18,21,24,26,29] - astronomical epoch" in CLDR.
*/
class U_I18N_API IslamicTBLACalendar : public IslamicCivilCalendar {
public:
/**
* Constructs an IslamicTBLACalendar based on the current time in the default time zone
* with the given locale.
*
* @param aLocale The given locale.
* @param success Indicates the status of IslamicTBLACalendar object construction.
* Returns U_ZERO_ERROR if constructed successfully.
* @internal
*/
IslamicTBLACalendar(const Locale& aLocale, UErrorCode &success);
/**
* Copy Constructor
* @internal
*/
IslamicTBLACalendar(const IslamicTBLACalendar& other) = default;
/**
* Destructor.
* @internal
*/
virtual ~IslamicTBLACalendar();
/**
* @return The class ID for this object. All objects of a given class have the
* same class ID. Objects of other classes have different class IDs.
* @internal
*/
virtual UClassID getDynamicClassID(void) const override;
/**
* Return the class ID for this class. This is useful only for comparing to a return
* value from getDynamicClassID(). For example:
*
* Base* polymorphic_pointer = createPolymorphicObject();
* if (polymorphic_pointer->getDynamicClassID() ==
* Derived::getStaticClassID()) ...
*
* @return The class ID for all objects of this class.
* @internal
*/
static UClassID U_EXPORT2 getStaticClassID(void);
/**
* return the calendar type, "islamic-tbla".
*
* @return calendar type
* @internal
*/
virtual const char * getType() const override;
// clone
virtual IslamicTBLACalendar* clone() const override;
protected:
/**
* Return the epoc.
* @internal
*/
virtual int32_t getEpoc() const override;
};
/*
* IslamicUmalquraCalendar
* This calendar is referred as "Islamic calendar, Umm al-Qura" in CLDR.
*/
class U_I18N_API IslamicUmalquraCalendar : public IslamicCalendar {
public:
/**
* Constructs an IslamicUmalquraCalendar based on the current time in the default time zone
* with the given locale.
*
* @param aLocale The given locale.
* @param success Indicates the status of IslamicUmalquraCalendar object construction.
* Returns U_ZERO_ERROR if constructed successfully.
* @internal
*/
IslamicUmalquraCalendar(const Locale& aLocale, UErrorCode &success);
/**
* Copy Constructor
* @internal
*/
IslamicUmalquraCalendar(const IslamicUmalquraCalendar& other) = default;
/**
* Destructor.
* @internal
*/
virtual ~IslamicUmalquraCalendar();
/**
* @return The class ID for this object. All objects of a given class have the
* same class ID. Objects of other classes have different class IDs.
* @internal
*/
virtual UClassID getDynamicClassID(void) const override;
/**
* Return the class ID for this class. This is useful only for comparing to a return
* value from getDynamicClassID(). For example:
*
* Base* polymorphic_pointer = createPolymorphicObject();
* if (polymorphic_pointer->getDynamicClassID() ==
* Derived::getStaticClassID()) ...
*
* @return The class ID for all objects of this class.
* @internal
*/
static UClassID U_EXPORT2 getStaticClassID(void);
/**
* return the calendar type, "islamic-umalqura".
*
* @return calendar type
* @internal
*/
virtual const char * getType() const override;
// clone
virtual IslamicUmalquraCalendar* clone() const override;
protected:
/**
* Return the day # on which the given year starts. Days are counted
* from the Hijri epoch, origin 0.
* @internal
*/
virtual int32_t yearStart(int32_t year) const override;
/**
* Return the day # on which the given month starts. Days are counted
* from the Hijri epoch, origin 0.
*
* @param year The hijri year
* @param year The hijri month, 0-based
* @internal
*/
virtual int32_t monthStart(int32_t year, int32_t month) const override;
/**
* Return the length (in days) of the given month.
*
* @param year The hijri year
* @param year The hijri month, 0-based
* @internal
*/
virtual int32_t handleGetMonthLength(int32_t extendedYear, int32_t month) const override;
/**
* Return the number of days in the given Islamic year
* @internal
*/
virtual int32_t handleGetYearLength(int32_t extendedYear) const override;
/**
* Override Calendar to compute several fields specific to the Islamic
* calendar system. These are:
*
* <ul><li>ERA
* <li>YEAR
* <li>MONTH
* <li>DAY_OF_MONTH
* <li>DAY_OF_YEAR
* <li>EXTENDED_YEAR</ul>
*
* The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
* method is called. The getGregorianXxx() methods return Gregorian
* calendar equivalents for the given Julian day.
* @internal
*/
virtual void handleComputeFields(int32_t julianDay, UErrorCode &status) override;
};
/*
* IslamicRGSACalendar
* Islamic calendar, Saudi Arabia sighting. Since the calendar depends on the
* sighting, it is impossible to implement by algorithm ahead of time. It is
* currently identical to IslamicCalendar except the getType will return
* "islamic-rgsa".
*/
class U_I18N_API IslamicRGSACalendar : public IslamicCalendar {
public:
/**
* Constructs an IslamicRGSACalendar based on the current time in the default time zone
* with the given locale.
*
* @param aLocale The given locale.
* @param success Indicates the status of IslamicRGSACalendar object construction.
* Returns U_ZERO_ERROR if constructed successfully.
* @internal
*/
IslamicRGSACalendar(const Locale& aLocale, UErrorCode &success);
/**
* Copy Constructor
* @internal
*/
IslamicRGSACalendar(const IslamicRGSACalendar& other) = default;
/**
* Destructor.
* @internal
*/
virtual ~IslamicRGSACalendar();
/**
* @return The class ID for this object. All objects of a given class have the
* same class ID. Objects of other classes have different class IDs.
* @internal
*/
virtual UClassID getDynamicClassID(void) const override;
/**
* Return the class ID for this class. This is useful only for comparing to a return
* value from getDynamicClassID(). For example:
*
* Base* polymorphic_pointer = createPolymorphicObject();
* if (polymorphic_pointer->getDynamicClassID() ==
* Derived::getStaticClassID()) ...
*
* @return The class ID for all objects of this class.
* @internal
*/
static UClassID U_EXPORT2 getStaticClassID(void);
/**
* return the calendar type, "islamic-rgsa".
*
* @return calendar type
* @internal
*/
virtual const char * getType() const override;
// clone
virtual IslamicRGSACalendar* clone() const override;
};
U_NAMESPACE_END
#endif
#endif

View file

@ -0,0 +1,37 @@
// © 2022 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "iso8601cal.h"
#include "unicode/gregocal.h"
U_NAMESPACE_BEGIN
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ISO8601Calendar)
ISO8601Calendar::ISO8601Calendar(const Locale& aLocale, UErrorCode& success)
: GregorianCalendar(aLocale, success)
{
setFirstDayOfWeek(UCAL_MONDAY);
setMinimalDaysInFirstWeek(4);
}
ISO8601Calendar::~ISO8601Calendar()
{
}
ISO8601Calendar* ISO8601Calendar::clone() const
{
return new ISO8601Calendar(*this);
}
const char *ISO8601Calendar::getType() const
{
return "iso8601";
}
U_NAMESPACE_END
#endif

View file

@ -0,0 +1,102 @@
// © 2022 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
#ifndef ISO8601CAL_H
#define ISO8601CAL_H
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/calendar.h"
#include "unicode/gregocal.h"
#include "unicode/timezone.h"
U_NAMESPACE_BEGIN
/**
* Concrete class which provides the ISO8601 calendar.
* <P>
* <code>ISO8601Calendar</code> is a subclass of <code>GregorianCalendar</code>
* that the first day of a week is Monday and the minimal days in the first
* week of a year or month is four days.
* <p>
* The ISO8601 calendar is identical to the Gregorian calendar in all respects
* except for the first day of week and the minimal days in the first week
* of a year.
* @internal
*/
class ISO8601Calendar : public GregorianCalendar {
public:
//-------------------------------------------------------------------------
// Constructors...
//-------------------------------------------------------------------------
/**
* Constructs a DangiCalendar based on the current time in the default time zone
* with the given locale.
*
* @param aLocale The given locale.
* @param success Indicates the status of ISO8601Calendar object construction.
* Returns U_ZERO_ERROR if constructed successfully.
* @internal
*/
ISO8601Calendar(const Locale& aLocale, UErrorCode &success);
/**
* Copy Constructor
* @internal
*/
ISO8601Calendar(const ISO8601Calendar& other) = default;
/**
* Destructor.
* @internal
*/
virtual ~ISO8601Calendar();
/**
* Clone.
* @internal
*/
virtual ISO8601Calendar* clone() const override;
// UObject stuff
public:
/**
* @return The class ID for this object. All objects of a given class have the
* same class ID. Objects of other classes have different class IDs.
* @internal
*/
virtual UClassID getDynamicClassID(void) const override;
/**
* Return the class ID for this class. This is useful only for comparing to a return
* value from getDynamicClassID(). For example:
*
* Base* polymorphic_pointer = createPolymorphicObject();
* if (polymorphic_pointer->getDynamicClassID() ==
* Derived::getStaticClassID()) ...
*
* @return The class ID for all objects of this class.
* @internal
*/
U_I18N_API static UClassID U_EXPORT2 getStaticClassID(void);
/**
* return the calendar type, "iso8601".
*
* @return calendar type
* @internal
*/
virtual const char * getType() const override;
private:
ISO8601Calendar(); // default constructor not implemented
};
U_NAMESPACE_END
#endif
#endif

View file

@ -86,6 +86,7 @@ hebrwcal.cpp
indiancal.cpp
inputext.cpp
islamcal.cpp
iso8601cal.cpp
japancal.cpp
listformatter.cpp
measfmt.cpp

View file

@ -1078,7 +1078,7 @@ group: formatting
measfmt.o quantityformatter.o
# dateformat
astro.o buddhcal.o calendar.o cecal.o chnsecal.o coptccal.o dangical.o ethpccal.o
gregocal.o gregoimp.o hebrwcal.o indiancal.o islamcal.o japancal.o persncal.o taiwncal.o
gregocal.o gregoimp.o hebrwcal.o indiancal.o islamcal.o iso8601cal.o japancal.o persncal.o taiwncal.o
erarules.o # mostly for Japanese eras
ucal.o
basictz.o olsontz.o rbtz.o simpletz.o timezone.o tzrule.o tztrans.o

View file

@ -353,6 +353,34 @@ void CalendarTest::runIndexedTest( int32_t index, UBool exec, const char* &name,
TestTimeZoneInLocale();
}
break;
#define CASE(num, NAME) \
case num: \
name = #NAME; \
if(exec) { \
logln(#NAME "---"); logln(""); \
NAME(); \
} \
break;
CASE(38, TestBasicConversionISO8601);
CASE(39, TestBasicConversionJapanese);
CASE(40, TestBasicConversionBuddhist);
CASE(41, TestBasicConversionTaiwan);
CASE(42, TestBasicConversionPersian);
CASE(43, TestBasicConversionIslamic);
CASE(44, TestBasicConversionIslamicTBLA);
CASE(45, TestBasicConversionIslamicCivil);
CASE(46, TestBasicConversionIslamicRGSA);
CASE(47, TestBasicConversionIslamicUmalqura);
CASE(48, TestBasicConversionHebrew);
CASE(49, TestBasicConversionChinese);
CASE(50, TestBasicConversionDangi);
CASE(51, TestBasicConversionIndian);
CASE(52, TestBasicConversionCoptic);
CASE(53, TestBasicConversionEthiopic);
CASE(54, TestBasicConversionEthiopicAmeteAlem);
#undef CASE
default: name = ""; break;
}
}
@ -2390,8 +2418,8 @@ void CalendarTest::TestISO8601() {
errln("Error: Failed to create a calendar for locale: %s", TEST_LOCALES[i]);
continue;
}
if (uprv_strcmp(cal->getType(), "gregorian") != 0) {
errln("Error: Gregorian calendar is not used for locale: %s", TEST_LOCALES[i]);
if (uprv_strcmp(cal->getType(), "iso8601") != 0) {
errln("Error: iso8601 calendar is not used for locale: %s", TEST_LOCALES[i]);
continue;
}
for (int j = 0; TEST_DATA[j][0] != 0; j++) {
@ -2833,8 +2861,8 @@ void CalendarTest::TestTimeZoneInLocale(void) {
{ "my-u-ca-islamic-umalqura-tz-kzala", "Asia/Almaty", "islamic-umalqura" },
{ "lo-u-ca-islamic-tbla-tz-bmbda", "Atlantic/Bermuda", "islamic-tbla" },
{ "km-u-ca-islamic-civil-tz-aqplm", "Antarctica/Palmer", "islamic-civil" },
{ "kk-u-ca-islamic-rgsa-tz-usanc", "America/Anchorage", "islamic" },
{ "ar-u-ca-iso8601-tz-bjptn", "Africa/Porto-Novo", "gregorian" },
{ "kk-u-ca-islamic-rgsa-tz-usanc", "America/Anchorage", "islamic-rgsa" },
{ "ar-u-ca-iso8601-tz-bjptn", "Africa/Porto-Novo", "iso8601" },
{ "he-u-ca-japanese-tz-tzdar", "Africa/Dar_es_Salaam", "japanese" },
{ "bs-u-ca-persian-tz-etadd", "Africa/Addis_Ababa", "persian" },
{ "it-u-ca-roc-tz-aruaq", "America/Argentina/San_Juan", "roc" },
@ -2859,6 +2887,286 @@ void CalendarTest::TestTimeZoneInLocale(void) {
}
}
void CalendarTest::AsssertCalendarFieldValue(
Calendar* cal, double time, const char* type,
int32_t era, int32_t year, int32_t month, int32_t week_of_year,
int32_t week_of_month, int32_t date, int32_t day_of_year, int32_t day_of_week,
int32_t day_of_week_in_month, int32_t am_pm, int32_t hour, int32_t hour_of_day,
int32_t minute, int32_t second, int32_t millisecond, int32_t zone_offset,
int32_t dst_offset, int32_t year_woy, int32_t dow_local, int32_t extended_year,
int32_t julian_day, int32_t milliseconds_in_day, int32_t is_leap_month) {
UErrorCode status = U_ZERO_ERROR;
cal->setTime(time, status);
assertEquals("getType", type, cal->getType());
assertEquals("UCAL_ERA", era, cal->get(UCAL_ERA, status));
assertEquals("UCAL_YEAR", year, cal->get(UCAL_YEAR, status));
assertEquals("UCAL_MONTH", month, cal->get(UCAL_MONTH, status));
assertEquals("UCAL_WEEK_OF_YEAR", week_of_year, cal->get(UCAL_WEEK_OF_YEAR, status));
assertEquals("UCAL_WEEK_OF_MONTH", week_of_month, cal->get(UCAL_WEEK_OF_MONTH, status));
assertEquals("UCAL_DATE", date, cal->get(UCAL_DATE, status));
assertEquals("UCAL_DAY_OF_YEAR", day_of_year, cal->get(UCAL_DAY_OF_YEAR, status));
assertEquals("UCAL_DAY_OF_WEEK", day_of_week, cal->get(UCAL_DAY_OF_WEEK, status));
assertEquals("UCAL_DAY_OF_WEEK_IN_MONTH", day_of_week_in_month, cal->get(UCAL_DAY_OF_WEEK_IN_MONTH, status));
assertEquals("UCAL_AM_PM", am_pm, cal->get(UCAL_AM_PM, status));
assertEquals("UCAL_HOUR", hour, cal->get(UCAL_HOUR, status));
assertEquals("UCAL_HOUR_OF_DAY", hour_of_day, cal->get(UCAL_HOUR_OF_DAY, status));
assertEquals("UCAL_MINUTE", minute, cal->get(UCAL_MINUTE, status));
assertEquals("UCAL_SECOND", second, cal->get(UCAL_SECOND, status));
assertEquals("UCAL_MILLISECOND", millisecond, cal->get(UCAL_MILLISECOND, status));
assertEquals("UCAL_ZONE_OFFSET", zone_offset, cal->get(UCAL_ZONE_OFFSET, status));
assertEquals("UCAL_DST_OFFSET", dst_offset, cal->get(UCAL_DST_OFFSET, status));
assertEquals("UCAL_YEAR_WOY", year_woy, cal->get(UCAL_YEAR_WOY, status));
assertEquals("UCAL_DOW_LOCAL", dow_local, cal->get(UCAL_DOW_LOCAL, status));
assertEquals("UCAL_EXTENDED_YEAR", extended_year, cal->get(UCAL_EXTENDED_YEAR, status));
assertEquals("UCAL_JULIAN_DAY", julian_day, cal->get(UCAL_JULIAN_DAY, status));
assertEquals("UCAL_MILLISECONDS_IN_DAY", milliseconds_in_day, cal->get(UCAL_MILLISECONDS_IN_DAY, status));
assertEquals("UCAL_IS_LEAP_MONTH", is_leap_month, cal->get(UCAL_IS_LEAP_MONTH, status));
}
static constexpr double test_time = 1667277891323; // Nov 1, 2022 4:44:51 GMT
void CalendarTest::TestBasicConversionGregorian(void) {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<Calendar> cal(icu::Calendar::createInstance(
*TimeZone::getGMT(), Locale("en@calendar=gregorian"), status));
if (U_FAILURE(status)) {
errln("Fail: Cannot get Gregorian calendar");
return;
}
AsssertCalendarFieldValue(
cal.getAlias(), test_time, "gregorian",
1, 2022, 10, 45, 1, 1, 305, 3, 1, 0, 4, 4, 44, 51,
323, 0, 0, 2022, 3, 2022, 2459885, 17091323, 0);
}
void CalendarTest::TestBasicConversionISO8601(void) {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<Calendar> cal(icu::Calendar::createInstance(
*TimeZone::getGMT(), Locale("en@calendar=iso8601"), status));
if (U_FAILURE(status)) {
errln("Fail: Cannot get ISO8601 calendar");
return;
}
AsssertCalendarFieldValue(
cal.getAlias(), test_time, "iso8601",
1, 2022, 10, 44, 1, 1, 305, 3, 1, 0, 4, 4, 44, 51,
323, 0, 0, 2022, 2, 2022, 2459885, 17091323, 0);
}
void CalendarTest::TestBasicConversionJapanese(void) {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<Calendar> cal(icu::Calendar::createInstance(
*TimeZone::getGMT(), Locale("en@calendar=japanese"), status));
if (U_FAILURE(status)) {
errln("Fail: Cannot get Japanese calendar");
return;
}
AsssertCalendarFieldValue(
cal.getAlias(), test_time, "japanese",
236, 4, 10, 45, 1, 1, 305, 3, 1, 0, 4, 4, 44, 51,
323, 0, 0, 2022, 3, 2022, 2459885, 17091323, 0);
}
void CalendarTest::TestBasicConversionBuddhist(void) {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<Calendar> cal(icu::Calendar::createInstance(
*TimeZone::getGMT(), Locale("en@calendar=buddhist"), status));
if (U_FAILURE(status)) {
errln("Fail: Cannot get Buddhist calendar");
return;
}
AsssertCalendarFieldValue(
cal.getAlias(), test_time, "buddhist",
0, 2565, 10, 45, 1, 1, 305, 3, 1, 0, 4, 4, 44, 51,
323, 0, 0, 2022, 3, 2022, 2459885, 17091323, 0);
}
void CalendarTest::TestBasicConversionTaiwan(void) {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<Calendar> cal(icu::Calendar::createInstance(
*TimeZone::getGMT(), Locale("en@calendar=roc"), status));
if (U_FAILURE(status)) {
errln("Fail: Cannot get Taiwan calendar");
return;
}
AsssertCalendarFieldValue(
cal.getAlias(), test_time, "roc",
1, 111, 10, 45, 1, 1, 305, 3, 1, 0, 4, 4, 44, 51,
323, 0, 0, 2022, 3, 2022, 2459885, 17091323, 0);
}
void CalendarTest::TestBasicConversionPersian(void) {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<Calendar> cal(icu::Calendar::createInstance(
*TimeZone::getGMT(), Locale("en@calendar=persian"), status));
if (U_FAILURE(status)) {
errln("Fail: Cannot get Persian calendar");
return;
}
AsssertCalendarFieldValue(
cal.getAlias(), test_time, "persian",
0, 1401, 7, 33, 2, 10, 226, 3, 2, 0, 4, 4, 44, 51,
323, 0, 0, 1401, 3, 1401, 2459885, 17091323, 0);
}
void CalendarTest::TestBasicConversionIslamic(void) {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<Calendar> cal(icu::Calendar::createInstance(
*TimeZone::getGMT(), Locale("en@calendar=islamic"), status));
if (U_FAILURE(status)) {
errln("Fail: Cannot get Islamic calendar");
return;
}
AsssertCalendarFieldValue(
cal.getAlias(), test_time, "islamic",
0, 1444, 3, 15, 2, 7, 96, 3, 1, 0, 4, 4, 44, 51,
323, 0, 0, 1444, 3, 1444, 2459885, 17091323, 0);
}
void CalendarTest::TestBasicConversionIslamicTBLA(void) {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<Calendar> cal(icu::Calendar::createInstance(
*TimeZone::getGMT(), Locale("en@calendar=islamic-tbla"), status));
if (U_FAILURE(status)) {
errln("Fail: Cannot get IslamicTBLA calendar");
return;
}
AsssertCalendarFieldValue(
cal.getAlias(), test_time, "islamic-tbla",
0, 1444, 3, 15, 2, 7, 96, 3, 1, 0, 4, 4, 44, 51,
323, 0, 0, 1444, 3, 1444, 2459885, 17091323, 0);
}
void CalendarTest::TestBasicConversionIslamicCivil(void) {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<Calendar> cal(icu::Calendar::createInstance(
*TimeZone::getGMT(), Locale("en@calendar=islamic-civil"), status));
if (U_FAILURE(status)) {
errln("Fail: Cannot get IslamicCivil calendar");
return;
}
AsssertCalendarFieldValue(
cal.getAlias(), test_time, "islamic-civil",
0, 1444, 3, 15, 2, 6, 95, 3, 1, 0, 4, 4, 44, 51,
323, 0, 0, 1444, 3, 1444, 2459885, 17091323, 0);
}
void CalendarTest::TestBasicConversionIslamicRGSA(void) {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<Calendar> cal(icu::Calendar::createInstance(
*TimeZone::getGMT(), Locale("en@calendar=islamic-rgsa"), status));
if (U_FAILURE(status)) {
errln("Fail: Cannot get IslamicRGSA calendar");
return;
}
AsssertCalendarFieldValue(
cal.getAlias(), test_time, "islamic-rgsa",
0, 1444, 3, 15, 2, 7, 96, 3, 1, 0, 4, 4, 44, 51,
323, 0, 0, 1444, 3, 1444, 2459885, 17091323, 0);
}
void CalendarTest::TestBasicConversionIslamicUmalqura(void) {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<Calendar> cal(icu::Calendar::createInstance(
*TimeZone::getGMT(), Locale("en@calendar=islamic-umalqura"), status));
if (U_FAILURE(status)) {
errln("Fail: Cannot get IslamicUmalqura calendar");
return;
}
AsssertCalendarFieldValue(
cal.getAlias(), test_time, "islamic-umalqura",
0, 1444, 3, 15, 2, 7, 95, 3, 1, 0, 4, 4, 44, 51,
323, 0, 0, 1444, 3, 1444, 2459885, 17091323, 0);
}
void CalendarTest::TestBasicConversionHebrew(void) {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<Calendar> cal(icu::Calendar::createInstance(
*TimeZone::getGMT(), Locale("en@calendar=hebrew"), status));
if (U_FAILURE(status)) {
errln("Fail: Cannot get Hebrew calendar");
return;
}
AsssertCalendarFieldValue(
cal.getAlias(), test_time, "hebrew",
0, 5783, 1, 6, 2, 7, 37, 3, 1, 0, 4, 4, 44, 51,
323, 0, 0, 5783, 3, 5783, 2459885, 17091323, 0);
}
void CalendarTest::TestBasicConversionChinese(void) {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<Calendar> cal(icu::Calendar::createInstance(
*TimeZone::getGMT(), Locale("en@calendar=chinese"), status));
if (U_FAILURE(status)) {
errln("Fail: Cannot get Chinese calendar");
return;
}
AsssertCalendarFieldValue(
cal.getAlias(), test_time, "chinese",
78, 39, 9, 40, 2, 8, 274, 3, 2, 0, 4, 4, 44, 51,
323, 0, 0, 4659, 3, 4659, 2459885, 17091323, 0);
}
void CalendarTest::TestBasicConversionDangi(void) {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<Calendar> cal(icu::Calendar::createInstance(
*TimeZone::getGMT(), Locale("en@calendar=dangi"), status));
if (U_FAILURE(status)) {
errln("Fail: Cannot get Dangi calendar");
return;
}
AsssertCalendarFieldValue(
cal.getAlias(), test_time, "dangi",
78, 39, 9, 40, 2, 8, 274, 3, 2, 0, 4, 4, 44, 51,
323, 0, 0, 4355, 3, 4355, 2459885, 17091323, 0);
}
void CalendarTest::TestBasicConversionIndian(void) {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<Calendar> cal(icu::Calendar::createInstance(
*TimeZone::getGMT(), Locale("en@calendar=indian"), status));
if (U_FAILURE(status)) {
errln("Fail: Cannot get Indian calendar");
return;
}
AsssertCalendarFieldValue(
cal.getAlias(), test_time, "indian",
0, 1944, 7, 33, 2, 10, 225, 3, 2, 0, 4, 4, 44, 51,
323, 0, 0, 1944, 3, 1944, 2459885, 17091323, 0);
}
void CalendarTest::TestBasicConversionCoptic(void) {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<Calendar> cal(icu::Calendar::createInstance(
*TimeZone::getGMT(), Locale("en@calendar=coptic"), status));
if (U_FAILURE(status)) {
errln("Fail: Cannot get Coptic calendar");
return;
}
AsssertCalendarFieldValue(
cal.getAlias(), test_time, "coptic",
1, 1739, 1, 8, 4, 22, 52, 3, 4, 0, 4, 4, 44, 51,
323, 0, 0, 1739, 3, 1739, 2459885, 17091323, 0);
}
void CalendarTest::TestBasicConversionEthiopic(void) {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<Calendar> cal(icu::Calendar::createInstance(
*TimeZone::getGMT(), Locale("en@calendar=ethiopic"), status));
if (U_FAILURE(status)) {
errln("Fail: Cannot get Ethiopic calendar");
return;
}
AsssertCalendarFieldValue(
cal.getAlias(), test_time, "ethiopic",
1, 2015, 1, 8, 4, 22, 52, 3, 4, 0, 4, 4, 44, 51,
323, 0, 0, 2015, 3, 2015, 2459885, 17091323, 0);
}
void CalendarTest::TestBasicConversionEthiopicAmeteAlem(void) {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<Calendar> cal(icu::Calendar::createInstance(
*TimeZone::getGMT(), Locale("en@calendar=ethiopic-amete-alem"), status));
if (U_FAILURE(status)) {
errln("Fail: Cannot get EthiopicAmeteAlem calendar");
return;
}
AsssertCalendarFieldValue(
cal.getAlias(), test_time, "ethiopic-amete-alem",
0, 7515, 1, 8, 4, 22, 52, 3, 4, 0, 4, 4, 44, 51,
323, 0, 0, 2015, 3, 2015, 2459885, 17091323, 0);
}
void CalendarTest::setAndTestCalendar(Calendar* cal, int32_t initMonth, int32_t initDay, int32_t initYear, UErrorCode& status) {
cal->clear();
cal->setLenient(false);

View file

@ -257,6 +257,34 @@ public: // package
void TestAddAcrossZoneTransition(void);
void TestChineseCalendarMapping(void);
void TestBasicConversionGregorian(void);
void TestBasicConversionISO8601(void);
void TestBasicConversionJapanese(void);
void TestBasicConversionBuddhist(void);
void TestBasicConversionTaiwan(void);
void TestBasicConversionPersian(void);
void TestBasicConversionIslamic(void);
void TestBasicConversionIslamicTBLA(void);
void TestBasicConversionIslamicCivil(void);
void TestBasicConversionIslamicRGSA(void);
void TestBasicConversionIslamicUmalqura(void);
void TestBasicConversionHebrew(void);
void TestBasicConversionChinese(void);
void TestBasicConversionDangi(void);
void TestBasicConversionIndian(void);
void TestBasicConversionCoptic(void);
void TestBasicConversionEthiopic(void);
void TestBasicConversionEthiopicAmeteAlem(void);
void AsssertCalendarFieldValue(
Calendar* cal, double time, const char* type,
int32_t era, int32_t year, int32_t month, int32_t week_of_year,
int32_t week_of_month, int32_t date, int32_t day_of_year, int32_t day_of_week,
int32_t day_of_week_in_month, int32_t am_pm, int32_t hour, int32_t hour_of_day,
int32_t minute, int32_t second, int32_t millisecond, int32_t zone_offset,
int32_t dst_offset, int32_t year_woy, int32_t dow_local, int32_t extended_year,
int32_t julian_day, int32_t milliseconds_in_day, int32_t is_leap_month);
};
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -3477,8 +3477,8 @@ void DateFormatTest::TestTimeZoneInLocale()
{ "my-u-ca-islamic-umalqura-tz-kzala", "Asia/Almaty", "islamic-umalqura" },
{ "lo-u-ca-islamic-tbla-tz-bmbda", "Atlantic/Bermuda", "islamic-tbla" },
{ "km-u-ca-islamic-civil-tz-aqplm", "Antarctica/Palmer", "islamic-civil" },
{ "kk-u-ca-islamic-rgsa-tz-usanc", "America/Anchorage", "islamic" },
{ "ar-u-ca-iso8601-tz-bjptn", "Africa/Porto-Novo", "gregorian" },
{ "kk-u-ca-islamic-rgsa-tz-usanc", "America/Anchorage", "islamic-rgsa" },
{ "ar-u-ca-iso8601-tz-bjptn", "Africa/Porto-Novo", "iso8601" },
{ "he-u-ca-japanese-tz-tzdar", "Africa/Dar_es_Salaam", "japanese" },
{ "bs-u-ca-persian-tz-etadd", "Africa/Addis_Ababa", "persian" },
{ "it-u-ca-roc-tz-aruaq", "America/Argentina/San_Juan", "roc" },