ICU-9616 Add DangiCalendar & tests, port from J to C

X-SVN-Rev: 33267
This commit is contained in:
Peter Edberg 2013-02-18 23:36:57 +00:00
parent 157ed28fc9
commit 47c5a5aa61
12 changed files with 384 additions and 11 deletions

2
.gitattributes vendored
View File

@ -123,6 +123,8 @@ icu4c/source/data/zone/ms_SG.txt -text
icu4c/source/data/zone/pool.res -text
icu4c/source/extra/uconv/uconv.vcxproj -text
icu4c/source/extra/uconv/uconv.vcxproj.filters -text
icu4c/source/i18n/dangical.cpp -text
icu4c/source/i18n/dangical.h -text
icu4c/source/i18n/i18n.vcxproj -text
icu4c/source/i18n/i18n.vcxproj.filters -text
icu4c/source/i18n/region.cpp -text

View File

@ -69,7 +69,7 @@ choicfmt.o datefmt.o smpdtfmt.o reldtfmt.o dtfmtsym.o udat.o dtptngen.o udatpg.o
nfrs.o nfrule.o nfsubs.o rbnf.o numsys.o ucsdet.o \
ucal.o calendar.o gregocal.o timezone.o simpletz.o olsontz.o \
astro.o taiwncal.o buddhcal.o persncal.o islamcal.o japancal.o gregoimp.o hebrwcal.o \
indiancal.o chnsecal.o cecal.o coptccal.o ethpccal.o \
indiancal.o chnsecal.o cecal.o coptccal.o dangical.o ethpccal.o \
coleitr.o coll.o tblcoll.o sortkey.o bocsu.o ucoleitr.o \
ucol.o ucol_res.o ucol_bld.o ucol_sit.o ucol_tok.o ucol_wgt.o ucol_cnt.o ucol_elm.o \
strmatch.o usearch.o search.o stsearch.o \

View File

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 1997-2012, International Business Machines Corporation and *
* Copyright (C) 1997-2013, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
@ -45,6 +45,7 @@
#include "indiancal.h"
#include "chnsecal.h"
#include "coptccal.h"
#include "dangical.h"
#include "ethpccal.h"
#include "unicode/calendar.h"
#include "cpputils.h"
@ -164,6 +165,7 @@ static const char * const gCalTypes[] = {
"ethiopic",
"ethiopic-amete-alem",
"iso8601",
"dangi",
NULL
};
@ -183,7 +185,8 @@ typedef enum ECalType {
CALTYPE_COPTIC,
CALTYPE_ETHIOPIC,
CALTYPE_ETHIOPIC_AMETE_ALEM,
CALTYPE_ISO8601
CALTYPE_ISO8601,
CALTYPE_DANGI
} ECalType;
U_NAMESPACE_BEGIN
@ -341,6 +344,9 @@ static Calendar *createStandardCalendar(ECalType calType, const Locale &loc, UEr
cal->setFirstDayOfWeek(UCAL_MONDAY);
cal->setMinimalDaysInFirstWeek(4);
break;
case CALTYPE_DANGI:
cal = new DangiCalendar(loc, status);
break;
default:
status = U_UNSUPPORTED_ERROR;
}

View File

@ -127,7 +127,7 @@ ChineseCalendar::ChineseCalendar(const Locale& aLocale, UErrorCode& success)
}
ChineseCalendar::ChineseCalendar(const Locale& aLocale, int32_t epochYear,
TimeZone* zoneAstroCalc, UErrorCode &success)
const TimeZone* zoneAstroCalc, UErrorCode &success)
: Calendar(TimeZone::createDefault(), aLocale, success),
isLeapYear(FALSE),
fEpochYear(epochYear),

View File

@ -94,7 +94,7 @@ U_NAMESPACE_BEGIN
* @author Alan Liu
* @internal
*/
class ChineseCalendar : public Calendar {
class U_I18N_API ChineseCalendar : public Calendar {
public:
//-------------------------------------------------------------------------
// Constructors...
@ -126,7 +126,7 @@ class ChineseCalendar : public Calendar {
* if successful, will not be changed to an error value.
* @internal
*/
ChineseCalendar(const Locale& aLocale, int32_t epochYear, TimeZone* zoneAstroCalc, UErrorCode &success);
ChineseCalendar(const Locale& aLocale, int32_t epochYear, const TimeZone* zoneAstroCalc, UErrorCode &success);
public:
/**
@ -308,6 +308,3 @@ U_NAMESPACE_END
#endif
#endif

View File

@ -0,0 +1,144 @@
/*
******************************************************************************
* Copyright (C) 2013, International Business Machines Corporation
* and others. All Rights Reserved.
******************************************************************************
*
* File DANGICAL.CPP
*****************************************************************************
*/
#include "chnsecal.h"
#include "dangical.h"
#if !UCONFIG_NO_FORMATTING
#include "umutex.h"
#include "gregoimp.h" // Math
#include "unicode/rbtz.h"
#include "unicode/tzrule.h"
#include "ucln_in.h"
// --- The cache --
static UMutex dangiLock = U_MUTEX_INITIALIZER;
static icu::TimeZone *gDangiCalendarZoneAstroCalc = NULL;
static UBool gDangiCalendarZoneAstroCalcInitialized = FALSE;
/**
* The start year of the Korean traditional calendar (Dan-gi) is the inaugural
* year of Dan-gun (BC 2333).
*/
static const int32_t DANGI_EPOCH_YEAR = -2332; // Gregorian year
U_CDECL_BEGIN
static UBool calendar_dangi_cleanup(void) {
if (gDangiCalendarZoneAstroCalc) {
delete gDangiCalendarZoneAstroCalc;
gDangiCalendarZoneAstroCalc = NULL;
}
gDangiCalendarZoneAstroCalcInitialized = FALSE;
return TRUE;
}
U_CDECL_END
U_NAMESPACE_BEGIN
// Implementation of the DangiCalendar class
//-------------------------------------------------------------------------
// Constructors...
//-------------------------------------------------------------------------
DangiCalendar::DangiCalendar(const Locale& aLocale, UErrorCode& success)
: ChineseCalendar(aLocale, DANGI_EPOCH_YEAR, getDangiCalZoneAstroCalc(), success)
{
}
DangiCalendar::DangiCalendar (const DangiCalendar& other)
: ChineseCalendar(other)
{
}
DangiCalendar::~DangiCalendar()
{
}
Calendar*
DangiCalendar::clone() const
{
return new DangiCalendar(*this);
}
const char *DangiCalendar::getType() const {
return "dangi";
}
/**
* The time zone used for performing astronomical computations for
* Dangi calendar. In Korea various timezones have been used historically
* (cf. http://www.math.snu.ac.kr/~kye/others/lunar.html):
*
* - 1908/04/01: GMT+8
* 1908/04/01 - 1911/12/31: GMT+8.5
* 1912/01/01 - 1954/03/20: GMT+9
* 1954/03/21 - 1961/08/09: GMT+8.5
* 1961/08/10 - : GMT+9
*
* Note that, in 1908-1911, the government did not apply the timezone change
* but used GMT+8. In addition, 1954-1961's timezone change does not affect
* the lunar date calculation. Therefore, the following simpler rule works:
*
* -1911: GMT+8
* 1912-: GMT+9
*
* Unfortunately, our astronomer's approximation doesn't agree with the
* references (http://www.math.snu.ac.kr/~kye/others/lunar.html and
* http://astro.kasi.re.kr/Life/ConvertSolarLunarForm.aspx?MenuID=115)
* in 1897/7/30. So the following ad hoc fix is used here:
*
* -1896: GMT+8
* 1897: GMT+7
* 1898-1911: GMT+8
* 1912- : GMT+9
*/
const TimeZone* DangiCalendar::getDangiCalZoneAstroCalc(void) const {
UBool initialized;
UMTX_CHECK(&dangiLock, gDangiCalendarZoneAstroCalcInitialized, initialized);
if (!initialized) {
umtx_lock(&dangiLock);
{
if (!gDangiCalendarZoneAstroCalcInitialized) {
const UDate millis1897[] = { (UDate)((1897 - 1970) * 365 * kOneDay) }; // some days of error is not a problem here
const UDate millis1898[] = { (UDate)((1898 - 1970) * 365 * kOneDay) }; // some days of error is not a problem here
const UDate millis1912[] = { (UDate)((1912 - 1970) * 365 * kOneDay) }; // this doesn't create an issue for 1911/12/20
InitialTimeZoneRule* initialTimeZone = new InitialTimeZoneRule(UnicodeString("GMT+8"), 8*kOneHour, 0);
TimeZoneRule* rule1897 = new TimeArrayTimeZoneRule(UnicodeString("Korean 1897"), 7*kOneHour, 0, millis1897, 1, DateTimeRule::STANDARD_TIME);
TimeZoneRule* rule1898to1911 = new TimeArrayTimeZoneRule(UnicodeString("Korean 1898-1911"), 8*kOneHour, 0, millis1898, 1, DateTimeRule::STANDARD_TIME);
TimeZoneRule* ruleFrom1912 = new TimeArrayTimeZoneRule(UnicodeString("Korean 1912-"), 9*kOneHour, 0, millis1912, 1, DateTimeRule::STANDARD_TIME);
UErrorCode status = U_ZERO_ERROR;
RuleBasedTimeZone* dangiCalZoneAstroCalc = new RuleBasedTimeZone(UnicodeString("KOREA_ZONE"), initialTimeZone); // adopts initialTimeZone
dangiCalZoneAstroCalc->addTransitionRule(rule1897, status); // adopts rule1897
dangiCalZoneAstroCalc->addTransitionRule(rule1898to1911, status);
dangiCalZoneAstroCalc->addTransitionRule(ruleFrom1912, status);
dangiCalZoneAstroCalc->complete(status);
if (U_SUCCESS(status)) {
gDangiCalendarZoneAstroCalc = dangiCalZoneAstroCalc;
} else {
delete dangiCalZoneAstroCalc;
gDangiCalendarZoneAstroCalc = NULL;
}
gDangiCalendarZoneAstroCalcInitialized = TRUE;
ucln_i18n_registerCleanup(UCLN_I18N_CHINESE_CALENDAR, calendar_dangi_cleanup);
}
}
umtx_unlock(&dangiLock);
}
return gDangiCalendarZoneAstroCalc;
}
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DangiCalendar)
U_NAMESPACE_END
#endif

View File

@ -0,0 +1,119 @@
/*
*****************************************************************************
* Copyright (C) 2013, International Business Machines Corporation
* and others. All Rights Reserved.
*****************************************************************************
*
* File DANGICAL.H
*****************************************************************************
*/
#ifndef DANGICAL_H
#define DANGICAL_H
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/calendar.h"
#include "unicode/timezone.h"
#include "chnsecal.h"
U_NAMESPACE_BEGIN
/**
* <p><code>DangiCalendar</code> is a concrete subclass of {@link Calendar}
* that implements a traditional Korean lunisolar calendar.</p>
*
* <p>DangiCalendar usually should be instantiated using
* {@link com.ibm.icu.util.Calendar#getInstance(ULocale)} passing in a <code>ULocale</code>
* with the tag <code>"@calendar=dangi"</code>.</p>
*
* @internal
*/
class DangiCalendar : public ChineseCalendar {
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 DangiCalendar object construction.
* Returns U_ZERO_ERROR if constructed successfully.
* @internal
*/
DangiCalendar(const Locale& aLocale, UErrorCode &success);
/**
* Copy Constructor
* @internal
*/
DangiCalendar(const DangiCalendar& other);
/**
* Destructor.
* @internal
*/
virtual ~DangiCalendar();
/**
* Clone.
* @internal
*/
virtual Calendar* clone() const;
//----------------------------------------------------------------------
// Internal methods & astronomical calculations
//----------------------------------------------------------------------
private:
const TimeZone* getDangiCalZoneAstroCalc(void) const;
// 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;
/**
* 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, "dangi".
*
* @return calendar type
* @internal
*/
const char * getType() const;
private:
DangiCalendar(); // default constructor not implemented
};
U_NAMESPACE_END
#endif
#endif

View File

@ -280,6 +280,7 @@
<ClCompile Include="currfmt.cpp" />
<ClCompile Include="currpinf.cpp" />
<ClCompile Include="currunit.cpp" />
<ClCompile Include="dangical.cpp" />
<ClCompile Include="datefmt.cpp" />
<ClCompile Include="dcfmtsym.cpp" />
<ClCompile Include="decContext.c" />
@ -704,6 +705,7 @@
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
</CustomBuild>
<ClInclude Include="dangical.h" />
<CustomBuild Include="unicode\datefmt.h">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
</Command>

View File

@ -108,6 +108,9 @@
<ClCompile Include="currunit.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="dangical.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="datefmt.cpp">
<Filter>formatting</Filter>
</ClCompile>
@ -543,6 +546,9 @@
<ClInclude Include="currfmt.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="dangical.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="decContext.h">
<Filter>formatting</Filter>
</ClInclude>

View File

@ -1,6 +1,6 @@
/***********************************************************************
* COPYRIGHT:
* Copyright (c) 1997-2011, International Business Machines Corporation
* Copyright (c) 1997-2013, International Business Machines Corporation
* and others. All Rights Reserved.
***********************************************************************/
@ -159,6 +159,7 @@ CalendarLimitTest::TestLimits(void) {
{"islamic", FALSE, DEFAULT_START, 800000}, // Approx. 2250 years from now, after which some rounding errors occur in Islamic calendar
{"hebrew", TRUE, DEFAULT_START, DEFAULT_END},
{"chinese", TRUE, DEFAULT_START, DEFAULT_END},
{"dangi", TRUE, DEFAULT_START, DEFAULT_END},
{"indian", FALSE, DEFAULT_START, DEFAULT_END},
{"coptic", FALSE, DEFAULT_START, DEFAULT_END},
{"ethiopic", FALSE, DEFAULT_START, DEFAULT_END},

View File

@ -3908,6 +3908,14 @@ void DateFormatTest::TestMonthPatterns()
CharsToUnicodeString("2 s\\u00ECyu\\u00E8bis ren-chen"),
CharsToUnicodeString("2 w\\u01D4yu\\u00E8 ren-chen") } },
{ "fr@calendar=chinese", DateFormat::kShort, { UnicodeString("2/4/29"), UnicodeString("2/4bis/29"), UnicodeString("2/5/29") } },
{ "en@calendar=dangi", DateFormat::kLong, { UnicodeString("Month3bis 2, 29"), UnicodeString("Month4 2, 29"), UnicodeString("Month5 1, 29") } },
{ "en@calendar=dangi", DateFormat::kShort, { UnicodeString("3bis/2/29"), UnicodeString("4/2/29"), UnicodeString("5/1/29") } },
{ "ko@calendar=dangi", DateFormat::kLong, { CharsToUnicodeString("\\uC784\\uC9C4\\uB144 3bis\\uC6D4 2\\uC77C"),
CharsToUnicodeString("\\uC784\\uC9C4\\uB144 4\\uC6D4 2\\uC77C"),
CharsToUnicodeString("\\uC784\\uC9C4\\uB144 5\\uC6D4 1\\uC77C") } },
{ "ko@calendar=dangi", DateFormat::kShort, { CharsToUnicodeString("29. 3bis. 2."),
CharsToUnicodeString("29. 4. 2."),
CharsToUnicodeString("29. 5. 1.") } },
// terminator
{ NULL, 0, { UnicodeString(""), UnicodeString(""), UnicodeString("") } }
};

View File

@ -1,4 +1,4 @@
// Copyright (c) 2008-2012 International Business Machines
// Copyright (c) 2008-2013 International Business Machines
// Corporation and others. All Rights Reserved.
calendar:table(nofallback) {
Info {
@ -115,6 +115,58 @@ calendar:table(nofallback) {
"EXTENDED_YEAR=4627,MONTH=5,DATE=1,IS_LEAP_MONTH=0", // ch
"YEAR=1990,MONTH=6,DATE=22", // greg
},
// dangi calendar
// (0-based months)
{
"en_US@calendar=dangi",
"EXTENDED_YEAR=4297,MONTH=6,DATE=29,IS_LEAP_MONTH=0", // dangi
"YEAR=1964,MONTH=8,DATE=5", // greg
},
{
"en_US@calendar=dangi",
"EXTENDED_YEAR=4297,MONTH=7,DATE=1,IS_LEAP_MONTH=0", // dangi
"YEAR=1964,MONTH=8,DATE=6", // greg
},
{
"en_US@calendar=dangi",
"EXTENDED_YEAR=4294,MONTH=10,DATE=18,IS_LEAP_MONTH=0", // dangi
"YEAR=1961,MONTH=11,DATE=25", // greg
},
{
"en_US@calendar=dangi",
"EXTENDED_YEAR=4323,MONTH=4,DATE=30,IS_LEAP_MONTH=0", // dangi
"YEAR=1990,MONTH=5,DATE=22", // greg
},
{
"en_US@calendar=dangi",
"EXTENDED_YEAR=4323,MONTH=4,DATE=1,IS_LEAP_MONTH=1", // dangi
"YEAR=1990,MONTH=5,DATE=23", // greg
},
{
"en_US@calendar=dangi",
"EXTENDED_YEAR=4323,MONTH=4,DATE=29,IS_LEAP_MONTH=1", // dangi
"YEAR=1990,MONTH=6,DATE=21", // greg
},
{
"en_US@calendar=dangi",
"EXTENDED_YEAR=4323,MONTH=5,DATE=1,IS_LEAP_MONTH=0", // dangi
"YEAR=1990,MONTH=6,DATE=22", // greg
},
{
"en_US@calendar=dangi",
"EXTENDED_YEAR=4213,MONTH=9,DATE=1,IS_LEAP_MONTH=0", // dangi
"YEAR=1880,MONTH=10,DATE=3", // greg
},
{
"en_US@calendar=dangi",
"EXTENDED_YEAR=4215,MONTH=10,DATE=1,IS_LEAP_MONTH=0", // dangi
"YEAR=1882,MONTH=11,DATE=10", // greg
},
{
"en_US@calendar=dangi",
"EXTENDED_YEAR=4230,MONTH=6,DATE=1,IS_LEAP_MONTH=0", // dangi
"YEAR=1897,MONTH=6,DATE=29", // greg
},
}
}
TestCalendarOperations {
@ -343,6 +395,42 @@ calendar:table(nofallback) {
"MONTH=-10", // month - 10
"EXTENDED_YEAR=4638,MONTH=5,DATE=29,IS_LEAP_MONTH=0", // ch
},
//dangi add tests
{ // normal
"en_US@calendar=dangi",
"EXTENDED_YEAR=4338,MONTH=2,DATE=15,IS_LEAP_MONTH=0", // dangi
"add",
"MONTH=3", // month + 3
"EXTENDED_YEAR=4338,MONTH=5,DATE=15,IS_LEAP_MONTH=0", // dangi
},
{ // across year
"en_US@calendar=dangi",
"EXTENDED_YEAR=4335,MONTH=11,DATE=15,IS_LEAP_MONTH=0", // dangi
"add",
"MONTH=1", // month + 1
"EXTENDED_YEAR=4336,MONTH=0,DATE=15,IS_LEAP_MONTH=0", // dangi
},
{ // 4 = leap
"en_US@calendar=dangi",
"EXTENDED_YEAR=4334,MONTH=2,DATE=15,IS_LEAP_MONTH=0", // dangi
"add",
"MONTH=3", // month + 3
"EXTENDED_YEAR=4334,MONTH=4,DATE=15,IS_LEAP_MONTH=0", // dangi
},
{ // 4 = leap
"en_US@calendar=dangi",
"EXTENDED_YEAR=4334,MONTH=2,DATE=15,IS_LEAP_MONTH=0", // dangi
"add",
"MONTH=2", // month + 2
"EXTENDED_YEAR=4334,MONTH=3,DATE=15,IS_LEAP_MONTH=1", // dangi
},
{ // dom should pin
"en_US@calendar=dangi",
"EXTENDED_YEAR=4334,MONTH=2,DATE=30,IS_LEAP_MONTH=0", // dangi
"add",
"MONTH=2", // month + 2
"EXTENDED_YEAR=4334,MONTH=3,DATE=29,IS_LEAP_MONTH=1", // dangi
},
{
"en_US@calendar=hebrew",
"MILLIS=-180799750799999",