ICU-4571 Merging Coptic/Ethiopic calendar work from yoshito's work branch to the trunk.

X-SVN-Rev: 23657
This commit is contained in:
Yoshito Umaoka 2008-03-22 02:58:07 +00:00
parent fbeb9bd7c6
commit ac7d853b91
11 changed files with 1360 additions and 4 deletions

View file

@ -1,6 +1,6 @@
#******************************************************************************
#
# Copyright (C) 1998-2007, International Business Machines
# Copyright (C) 1998-2008, International Business Machines
# Corporation and others. All Rights Reserved.
#
#******************************************************************************
@ -67,7 +67,8 @@ ucurr.o digitlst.o fmtable_cnv.o \
choicfmt.o datefmt.o smpdtfmt.o reldtfmt.o dtfmtsym.o udat.o dtptngen.o \
nfrs.o nfrule.o nfsubs.o rbnf.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 \
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 \
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

@ -38,6 +38,8 @@
#include "persncal.h"
#include "indiancal.h"
#include "chnsecal.h"
#include "coptccal.h"
#include "ethpccal.h"
#include "unicode/calendar.h"
#include "cpputils.h"
#include "servloc.h"
@ -144,6 +146,8 @@ static const char * const gCalendarKeywords[] = {
"hebrew",
"chinese",
"indian",
"coptic",
"ethiopic",
NULL
};
@ -202,6 +206,10 @@ static Calendar *createStandardCalendar(char *calType, const Locale &canLoc, UEr
return new ChineseCalendar(canLoc, status);
} else if(!uprv_strcmp(calType, "indian")) {
return new IndianCalendar(canLoc, status);
} else if(!uprv_strcmp(calType, "coptic")) {
return new CopticCalendar(canLoc, status);
} else if(!uprv_strcmp(calType, "ethiopic")) {
return new EthiopicCalendar(canLoc, status);
} else {
status = U_UNSUPPORTED_ERROR;
return NULL;

141
icu4c/source/i18n/cecal.cpp Normal file
View file

@ -0,0 +1,141 @@
/*
*******************************************************************************
* Copyright (C) 2003 - 2008, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "cecal.h"
#include "gregoimp.h" //Math
U_NAMESPACE_BEGIN
static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = {
// Minimum Greatest Least Maximum
// Minimum Maximum
{ 0, 0, 1, 1}, // ERA
{ 1, 1, 5000000, 5000000}, // YEAR
{ 0, 0, 13, 13}, // MONTH
{ 1, 1, 52, 53}, // WEEK_OF_YEAR
{ 0, 0, 1, 6}, // WEEK_OF_MONTH
{ 1, 1, 5, 30}, // DAY_OF_MONTH
{ 1, 1, 365, 366}, // DAY_OF_YEAR
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DAY_OF_WEEK
{ -1, -1, 4, 6}, // DAY_OF_WEEK_IN_MONTH
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // AM_PM
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR_OF_DAY
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MINUTE
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // SECOND
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECOND
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // ZONE_OFFSET
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DST_OFFSET
{ -5000000, -5000000, 5000000, 5000000}, // YEAR_WOY
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DOW_LOCAL
{ -5000000, -5000000, 5000000, 5000000}, // EXTENDED_YEAR
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
};
//-------------------------------------------------------------------------
// Constructors...
//-------------------------------------------------------------------------
CECalendar::CECalendar(const Locale& aLocale, UErrorCode& success)
: Calendar(TimeZone::createDefault(), aLocale, success)
{
setTimeInMillis(getNow(), success);
}
CECalendar::CECalendar (const CECalendar& other)
: Calendar(other)
{
}
CECalendar::~CECalendar()
{
}
CECalendar&
CECalendar::operator=(const CECalendar& right)
{
Calendar::operator=(right);
return *this;
}
//-------------------------------------------------------------------------
// Calendar framework
//-------------------------------------------------------------------------
int32_t
CECalendar::handleComputeMonthStart(int32_t eyear,int32_t emonth, UBool useMonth) const
{
return ceToJD(eyear, emonth, 0, getJDEpochOffset());
}
int32_t
CECalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const
{
return LIMITS[field][limitType];
}
UBool
CECalendar::inDaylightTime(UErrorCode& status) const
{
if (U_FAILURE(status) || !getTimeZone().useDaylightTime()) {
return FALSE;
}
// Force an update of the state of the Calendar.
((CECalendar*)this)->complete(status); // cast away const
return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE);
}
UBool
CECalendar::haveDefaultCentury() const
{
return TRUE;
}
//-------------------------------------------------------------------------
// Calendar system Conversion methods...
//-------------------------------------------------------------------------
int32_t
CECalendar::ceToJD(int32_t year, int32_t month, int32_t date, int32_t jdEpochOffset)
{
return (int32_t) (
(jdEpochOffset+365) // difference from Julian epoch to 1,1,1
+ 365 * (year - 1) // number of days from years
+ Math::floorDivide(year, 4) // extra day of leap year
+ 30 * (month + 1) // number of days from months
+ date // number of days for present month
- 31 // slack?
);
}
void
CECalendar::jdToCE(int32_t julianDay, int32_t jdEpochOffset, int32_t& year, int32_t& month, int32_t& day)
{
int32_t c4; // number of 4 year cycle (1461 days)
int32_t r4; // remainder of 4 year cycle, always positive
c4 = Math::floorDivide(julianDay - jdEpochOffset, 1461, r4);
year = 4 * c4 + (r4/365 - r4/1460); // 4 * <number of 4year cycle> + <years within the last cycle>
int32_t doy = (r4 == 1460) ? 365 : (r4 % 365); // days in present year
month = doy / 30; // 30 -> Coptic/Ethiopic month length up to 12th month
day = (doy % 30) + 1; // 1-based days in a month
}
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */
//eof

134
icu4c/source/i18n/cecal.h Normal file
View file

@ -0,0 +1,134 @@
/*
*******************************************************************************
* Copyright (C) 2003 - 2008, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
#ifndef CECAL_H
#define CECAL_H
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/calendar.h"
U_NAMESPACE_BEGIN
/**
* Base class for EthiopicCalendar and CopticCalendar.
* @internal
*/
class U_I18N_API CECalendar : public Calendar {
protected:
//-------------------------------------------------------------------------
// Constructors...
//-------------------------------------------------------------------------
/**
* Constructs a CECalendar based on the current time in the default time zone
* with the given locale with the Julian epoch offiset
*
* @param aLocale The given locale.
* @param success Indicates the status of CECalendar object construction.
* Returns U_ZERO_ERROR if constructed successfully.
* @internal
*/
CECalendar(const Locale& aLocale, UErrorCode& success);
/**
* Copy Constructor
* @internal
*/
CECalendar (const CECalendar& other);
/**
* Destructor.
* @internal
*/
virtual ~CECalendar();
/**
* Default assignment operator
* @param right Calendar object to be copied
* @internal
*/
CECalendar& operator=(const CECalendar& right);
protected:
//-------------------------------------------------------------------------
// Calendar framework
//-------------------------------------------------------------------------
/**
* Return JD of start of given month/extended year
* @internal
*/
virtual int32_t handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth) const;
/**
* Calculate the limit for a specified type of limit and field
* @internal
*/
virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const;
/**
* (Overrides Calendar) Return true if the current date for this Calendar is in
* Daylight Savings Time. Recognizes DST_OFFSET, if it is set.
*
* @param status Fill-in parameter which receives the status of this operation.
* @return True if the current date for this Calendar is in Daylight Savings Time,
* false, otherwise.
* @internal
*/
virtual UBool inDaylightTime(UErrorCode&) const;
/**
* Returns TRUE because Coptic/Ethiopic Calendar does have a default century
* @internal
*/
virtual UBool haveDefaultCentury() const;
protected:
/**
* The Coptic and Ethiopic calendars differ only in their epochs.
* This method must be implemented by CECalendar subclasses to
* return the date offset from Julian
* @internal
*/
virtual int32_t getJDEpochOffset() const = 0;
/**
* Convert an Coptic/Ethiopic year, month, and day to a Julian day.
*
* @param year the extended year
* @param month the month
* @param day the day
* @param jdEpochOffset the epoch offset from Julian epoch
* @return Julian day
* @internal
*/
static int32_t ceToJD(int32_t year, int32_t month, int32_t date,
int32_t jdEpochOffset);
/**
* Convert a Julian day to an Coptic/Ethiopic year, month and day
*
* @param julianDay the Julian day
* @param jdEpochOffset the epoch offset from Julian epoch
* @param year receives the extended year
* @param month receives the month
* @param date receives the day
* @internal
*/
static void jdToCE(int32_t julianDay, int32_t jdEpochOffset,
int32_t& year, int32_t& month, int32_t& day);
};
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */
#endif
//eof

View file

@ -0,0 +1,178 @@
/*
*******************************************************************************
* Copyright (C) 2003 - 2008, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "umutex.h"
#include "coptccal.h"
#include "cecal.h"
#include <float.h>
U_NAMESPACE_BEGIN
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CopticCalendar)
static const int32_t COPTIC_JD_EPOCH_OFFSET = 1824665;
//-------------------------------------------------------------------------
// Constructors...
//-------------------------------------------------------------------------
CopticCalendar::CopticCalendar(const Locale& aLocale, UErrorCode& success)
: CECalendar(aLocale, success)
{
}
CopticCalendar::CopticCalendar (const CopticCalendar& other)
: CECalendar(other)
{
}
CopticCalendar::~CopticCalendar()
{
}
Calendar*
CopticCalendar::clone() const
{
return new CopticCalendar(*this);
}
const char*
CopticCalendar::getType() const
{
return "coptic";
}
//-------------------------------------------------------------------------
// Calendar framework
//-------------------------------------------------------------------------
int32_t
CopticCalendar::handleGetExtendedYear()
{
int32_t eyear;
if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
eyear = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
} else {
// The year defaults to the epoch start, the era to CE
int32_t era = internalGet(UCAL_ERA, CE);
if (era == BCE) {
eyear = 1 - internalGet(UCAL_YEAR, 1); // Convert to extended year
} else {
eyear = internalGet(UCAL_YEAR, 1); // Default to year 1
}
}
return eyear;
}
void
CopticCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status)
{
int32_t eyear, month, day, era, year;
jdToCE(julianDay, getJDEpochOffset(), eyear, month, day);
if (eyear <= 0) {
era = BCE;
year = 1 - eyear;
} else {
era = CE;
year = eyear;
}
internalSet(UCAL_EXTENDED_YEAR, eyear);
internalSet(UCAL_ERA, era);
internalSet(UCAL_YEAR, year);
internalSet(UCAL_MONTH, month);
internalSet(UCAL_DATE, day);
internalSet(UCAL_DAY_OF_YEAR, (30 * month) + day);
}
const UDate CopticCalendar::fgSystemDefaultCentury = DBL_MIN;
const int32_t CopticCalendar::fgSystemDefaultCenturyYear = -1;
UDate CopticCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
int32_t CopticCalendar::fgSystemDefaultCenturyStartYear = -1;
UDate
CopticCalendar::defaultCenturyStart() const
{
initializeSystemDefaultCentury();
// use defaultCenturyStart unless it's the flag value;
// then use systemDefaultCenturyStart
return fgSystemDefaultCenturyStart;
}
int32_t
CopticCalendar::defaultCenturyStartYear() const
{
initializeSystemDefaultCentury();
// use defaultCenturyStart unless it's the flag value;
// then use systemDefaultCenturyStart
return fgSystemDefaultCenturyStartYear;
}
void
CopticCalendar::initializeSystemDefaultCentury()
{
// lazy-evaluate systemDefaultCenturyStart
UBool needsUpdate;
UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
if (!needsUpdate) {
return;
}
UErrorCode status = U_ZERO_ERROR;
CopticCalendar calendar(Locale("@calendar=coptic"), status);
if (U_SUCCESS(status)) {
calendar.setTime(Calendar::getNow(), status);
calendar.add(UCAL_YEAR, -80, status);
UDate newStart = calendar.getTime(status);
int32_t newYear = calendar.get(UCAL_YEAR, status);
{
umtx_lock(NULL);
fgSystemDefaultCenturyStart = newStart;
fgSystemDefaultCenturyStartYear = newYear;
umtx_unlock(NULL);
}
}
// We have no recourse upon failure unless we want to propagate the failure
// out.
}
int32_t
CopticCalendar::getJDEpochOffset() const
{
return COPTIC_JD_EPOCH_OFFSET;
}
#if 0
// We do not want to introduce this API in ICU4C.
// It was accidentally introduced in ICU4J as a public API.
//-------------------------------------------------------------------------
// Calendar system Conversion methods...
//-------------------------------------------------------------------------
int32_t
CopticCalendar::copticToJD(int32_t year, int32_t month, int32_t day)
{
return CECalendar::ceToJD(year, month, day, COPTIC_JD_EPOCH_OFFSET);
}
#endif
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */
//eof

View file

@ -0,0 +1,272 @@
/*
*******************************************************************************
* Copyright (C) 2003 - 2008, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
#ifndef COPTCCAL_H
#define COPTCCAL_H
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/calendar.h"
#include "cecal.h"
U_NAMESPACE_BEGIN
/**
* Implement the Coptic calendar system.
* @internal
*/
class CopticCalendar : public CECalendar {
public:
/**
* Useful constants for CopticCalendar.
* @internal
*/
enum EMonths {
/**
* Constant for &#x03c9;&#x03bf;&#x03b3;&#x03c4;/&#x062a;&#xfeee;&#xfe97;,
* the 1st month of the Coptic year.
*/
TOUT,
/**
* Constant for &#x03a0;&#x03b1;&#x03bf;&#x03c0;&#x03b9;/&#xfeea;&#xfe91;&#xfe8e;&#xfe91;,
* the 2nd month of the Coptic year.
*/
BABA,
/**
* Constant for &#x0391;&#x03b8;&#x03bf;&#x03c1;/&#x0631;&#xfeee;&#xfe97;&#xfe8e;&#xfeeb;,
* the 3rd month of the Coptic year.
*/
HATOR,
/**
* Constant for &#x03a7;&#x03bf;&#x03b9;&#x03b1;&#x03ba;/&#xfeda;&#xfeec;&#xfef4;&#xfedb;,
* the 4th month of the Coptic year.
*/
KIAHK,
/**
* Constant for &#x03a4;&#x03c9;&#x03b2;&#x03b9;/&#x0637;&#xfeee;&#xfe92;&#xfeeb;,
* the 5th month of the Coptic year.
*/
TOBA,
/**
* Constant for &#x039c;&#x03b5;&#x03e3;&#x03b9;&#x03c1;/&#xfeae;&#xfef4;&#xfeb8;&#xfee3;&#x0623;,
* the 6th month of the Coptic year.
*/
AMSHIR,
/**
* Constant for &#x03a0;&#x03b1;&#x03c1;&#x03b5;&#x03bc;&#x03e9;&#x03b1;&#x03c4;/&#x062a;&#xfe8e;&#xfeec;&#xfee3;&#xfeae;&#xfe91;,
* the 7th month of the Coptic year.
*/
BARAMHAT,
/**
* Constant for &#x03a6;&#x03b1;&#x03c1;&#x03bc;&#x03bf;&#x03b8;&#x03b9;/&#x0647;&#x062f;&#xfeee;&#xfee3;&#xfeae;&#xfe91;,
* the 8th month of the Coptic year.
*/
BARAMOUDA,
/**
* Constant for &#x03a0;&#x03b1;&#x03e3;&#x03b1;&#x03bd;/&#xfeb2;&#xfee8;&#xfeb8;&#xfe91;,
* the 9th month of the Coptic year.
*/
BASHANS,
/**
* Constant for &#x03a0;&#x03b1;&#x03c9;&#x03bd;&#x03b9;/&#xfeea;&#xfee7;&#x0624;&#xfeee;&#xfe91;,
* the 10th month of the Coptic year.
*/
PAONA,
/**
* Constant for &#x0395;&#x03c0;&#x03b7;&#x03c0;/&#xfe90;&#xfef4;&#xfe91;&#x0623;,
* the 11th month of the Coptic year.
*/
EPEP,
/**
* Constant for &#x039c;&#x03b5;&#x03f2;&#x03c9;&#x03c1;&#x03b7;/&#x0649;&#xfeae;&#xfeb4;&#xfee3;,
* the 12th month of the Coptic year.
*/
MESRA,
/**
* Constant for &#x03a0;&#x03b9;&#x03ba;&#x03bf;&#x03b3;&#x03eb;&#x03b9;
* &#x03bc;&#x03b1;&#x03b2;&#x03bf;&#x03c4;/&#xfeae;&#xfef4;&#xfed0;&#xfebc;&#xfedf;&#x0627;
* &#xfeae;&#xfeec;&#xfeb8;&#xfedf;&#x0627;,
* the 13th month of the Coptic year.
*/
NASIE
};
enum EEras {
BCE, // Before the epoch
CE // After the epoch
};
/**
* Constructs a CopticCalendar 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 CopticCalendar object construction.
* Returns U_ZERO_ERROR if constructed successfully.
* @internal
*/
CopticCalendar(const Locale& aLocale, UErrorCode& success);
/**
* Copy Constructor
* @internal
*/
CopticCalendar (const CopticCalendar& other);
/**
* Destructor.
* @internal
*/
virtual ~CopticCalendar();
/**
* Create and return a polymorphic copy of this calendar.
* @return return a polymorphic copy of this calendar.
* @internal
*/
virtual Calendar* clone(void) const;
/**
* return the calendar type, "coptic"
* @return calendar type
* @internal
*/
const char * getType() const;
protected:
//-------------------------------------------------------------------------
// Calendar framework
//-------------------------------------------------------------------------
/**
* Return the extended year defined by the current fields.
* @internal
*/
virtual int32_t handleGetExtendedYear();
/**
* Compute fields from the JD
* @internal
*/
virtual void handleComputeFields(int32_t julianDay, UErrorCode &status);
/**
* Returns the date of the start of the default century
* @return start of century - in milliseconds since epoch, 1970
* @internal
*/
virtual UDate defaultCenturyStart() const;
/**
* Returns the year in which the default century begins
* @internal
*/
virtual int32_t defaultCenturyStartYear() const;
/**
* Return the date offset from Julian
* @internal
*/
virtual int32_t getJDEpochOffset() const;
private:
/**
* The system maintains a static default century start date. This is initialized
* the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to
* indicate an uninitialized state. Once the system default century date and year
* are set, they do not change.
*/
static UDate fgSystemDefaultCenturyStart;
/**
* See documentation for systemDefaultCenturyStart.
*/
static int32_t fgSystemDefaultCenturyStartYear;
/**
* Default value that indicates the defaultCenturyStartYear is unitialized
*/
static const int32_t fgSystemDefaultCenturyYear;
/**
* start of default century, as a date
*/
static const UDate fgSystemDefaultCentury;
/**
* Initializes the 100-year window that dates with 2-digit years
* are considered to fall within so that its start date is 80 years
* before the current time.
*/
static void initializeSystemDefaultCentury(void);
public:
/**
* 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;
/**
* 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);
#if 0
// We do not want to introduce this API in ICU4C.
// It was accidentally introduced in ICU4J as a public API.
public:
//-------------------------------------------------------------------------
// Calendar system Conversion methods...
//-------------------------------------------------------------------------
/**
* Convert an Coptic year, month, and day to a Julian day.
*
* @param year the extended year
* @param month the month
* @param day the day
* @return Julian day
* @internal
*/
static int32_t copticToJD(int32_t year, int32_t month, int32_t day);
#endif
};
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */
#endif /* COPTCCAL_H */
//eof

View file

@ -0,0 +1,212 @@
/*
*******************************************************************************
* Copyright (C) 2003 - 2008, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "umutex.h"
#include "ethpccal.h"
#include "cecal.h"
#include <float.h>
U_NAMESPACE_BEGIN
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(EthiopicCalendar)
//static const int32_t JD_EPOCH_OFFSET_AMETE_ALEM = -285019;
static const int32_t JD_EPOCH_OFFSET_AMETE_MIHRET = 1723856;
static const int32_t AMETE_MIHRET_DELTA = 5500; // 5501 - 1 (Amete Alem 5501 = Amete Mihret 1)
//-------------------------------------------------------------------------
// Constructors...
//-------------------------------------------------------------------------
EthiopicCalendar::EthiopicCalendar(const Locale& aLocale, UErrorCode& success)
: CECalendar(aLocale, success),
isAmeteAlem(FALSE)
{
}
EthiopicCalendar::EthiopicCalendar(const EthiopicCalendar& other)
: CECalendar(other),
isAmeteAlem(other.isAmeteAlem)
{
}
EthiopicCalendar::~EthiopicCalendar()
{
}
Calendar*
EthiopicCalendar::clone() const
{
return new EthiopicCalendar(*this);
}
const char *
EthiopicCalendar::getType() const
{
if (isAmeteAlemEra()) {
return "ethiopic_aa";
}
return "ethiopic";
}
void
EthiopicCalendar::setAmeteAlemEra(UBool onOff)
{
isAmeteAlem = onOff;
}
UBool
EthiopicCalendar::isAmeteAlemEra() const
{
return isAmeteAlem;
}
//-------------------------------------------------------------------------
// Calendar framework
//-------------------------------------------------------------------------
int32_t
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 eyear;
}
void
EthiopicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status)
{
int32_t eyear, month, day, era, year;
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_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);
}
const UDate EthiopicCalendar::fgSystemDefaultCentury = DBL_MIN;
const int32_t EthiopicCalendar::fgSystemDefaultCenturyYear = -1;
UDate EthiopicCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
int32_t EthiopicCalendar::fgSystemDefaultCenturyStartYear = -1;
UDate
EthiopicCalendar::defaultCenturyStart() const
{
initializeSystemDefaultCentury();
return fgSystemDefaultCenturyStart;
}
int32_t
EthiopicCalendar::defaultCenturyStartYear() const
{
initializeSystemDefaultCentury();
if (isAmeteAlemEra()) {
return fgSystemDefaultCenturyStartYear + AMETE_MIHRET_DELTA;
}
return fgSystemDefaultCenturyStartYear;
}
void
EthiopicCalendar::initializeSystemDefaultCentury()
{
// lazy-evaluate systemDefaultCenturyStart
UBool needsUpdate;
UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
if (!needsUpdate) {
return;
}
UErrorCode status = U_ZERO_ERROR;
EthiopicCalendar calendar(Locale("@calendar=ethiopic"), status);
if (U_SUCCESS(status)) {
calendar.setTime(Calendar::getNow(), status);
calendar.add(UCAL_YEAR, -80, status);
UDate newStart = calendar.getTime(status);
int32_t newYear = calendar.get(UCAL_YEAR, status);
{
umtx_lock(NULL);
fgSystemDefaultCenturyStart = newStart;
fgSystemDefaultCenturyStartYear = newYear;
umtx_unlock(NULL);
}
}
// We have no recourse upon failure unless we want to propagate the failure
// out.
}
int32_t
EthiopicCalendar::getJDEpochOffset() const
{
return JD_EPOCH_OFFSET_AMETE_MIHRET;
}
#if 0
// We do not want to introduce this API in ICU4C.
// It was accidentally introduced in ICU4J as a public API.
//-------------------------------------------------------------------------
// Calendar system Conversion methods...
//-------------------------------------------------------------------------
int32_t
EthiopicCalendar::ethiopicToJD(int32_t year, int32_t month, int32_t date)
{
return ceToJD(year, month, date, JD_EPOCH_OFFSET_AMETE_MIHRET);
}
#endif
U_NAMESPACE_END
#endif

View file

@ -0,0 +1,289 @@
/*
*******************************************************************************
* Copyright (C) 2003 - 2008, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
#ifndef ETHPCCAL_H
#define ETHPCCAL_H
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/calendar.h"
#include "cecal.h"
U_NAMESPACE_BEGIN
/**
* Implement the Ethiopic calendar system.
* @internal
*/
class EthiopicCalendar : public CECalendar {
public:
/**
* Useful constants for EthiopicCalendar.
* @internal
*/
enum EMonths {
/**
* Constant for &#x1218;&#x1235;&#x12a8;&#x1228;&#x121d;, the 1st month of the Ethiopic year.
*/
MESKEREM,
/**
* Constant for &#x1325;&#x1245;&#x121d;&#x1275;, the 2nd month of the Ethiopic year.
*/
TEKEMT,
/**
* Constant for &#x1285;&#x12f3;&#x122d;, the 3rd month of the Ethiopic year.
*/
HEDAR,
/**
* Constant for &#x1273;&#x1285;&#x1223;&#x1225;, the 4th month of the Ethiopic year.
*/
TAHSAS,
/**
* Constant for &#x1325;&#x122d;, the 5th month of the Ethiopic year.
*/
TER,
/**
* Constant for &#x12e8;&#x12ab;&#x1272;&#x1275;, the 6th month of the Ethiopic year.
*/
YEKATIT,
/**
* Constant for &#x1218;&#x130b;&#x1262;&#x1275;, the 7th month of the Ethiopic year.
*/
MEGABIT,
/**
* Constant for &#x121a;&#x12eb;&#x12dd;&#x12eb;, the 8th month of the Ethiopic year.
*/
MIAZIA,
/**
* Constant for &#x130d;&#x1295;&#x1266;&#x1275;, the 9th month of the Ethiopic year.
*/
GENBOT,
/**
* Constant for &#x1230;&#x1294;, the 10th month of the Ethiopic year.
*/
SENE,
/**
* Constant for &#x1210;&#x121d;&#x120c;, the 11th month of the Ethiopic year.
*/
HAMLE,
/**
* Constant for &#x1290;&#x1210;&#x1234;, the 12th month of the Ethiopic year.
*/
NEHASSA,
/**
* Constant for &#x1333;&#x1309;&#x121c;&#x1295;, the 13th month of the Ethiopic year.
*/
PAGUMEN
};
enum EEras {
AMETE_ALEM, // Before the epoch
AMETE_MIHRET // After the epoch
};
/**
* Constructs a EthiopicCalendar 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
*/
EthiopicCalendar(const Locale& aLocale, UErrorCode& success);
/**
* Copy Constructor
* @internal
*/
EthiopicCalendar(const EthiopicCalendar& other);
/**
* Destructor.
* @internal
*/
virtual ~EthiopicCalendar();
/**
* Create and return a polymorphic copy of this calendar.
* @return return a polymorphic copy of this calendar.
* @internal
*/
virtual Calendar* clone() const;
/**
* return the calendar type, "ethiopic"
* @return calendar type
* @internal
*/
virtual const char * getType() const;
/**
* 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;
protected:
//-------------------------------------------------------------------------
// Calendar framework
//-------------------------------------------------------------------------
/**
* Return the extended year defined by the current fields.
* @internal
*/
virtual int32_t handleGetExtendedYear();
/**
* Compute fields from the JD
* @internal
*/
virtual void handleComputeFields(int32_t julianDay, UErrorCode &status);
/**
* Calculate the limit for a specified type of limit and field
* @internal
*/
virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const;
/**
* Returns the date of the start of the default century
* @return start of century - in milliseconds since epoch, 1970
* @internal
*/
virtual UDate defaultCenturyStart() const;
/**
* Returns the year in which the default century begins
* @internal
*/
virtual int32_t defaultCenturyStartYear() const;
/**
* Return the date offset from Julian
* @internal
*/
virtual int32_t getJDEpochOffset() const;
private:
/**
* The system maintains a static default century start date. This is initialized
* the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to
* indicate an uninitialized state. Once the system default century date and year
* are set, they do not change.
*/
static UDate fgSystemDefaultCenturyStart;
/**
* See documentation for systemDefaultCenturyStart.
*/
static int32_t fgSystemDefaultCenturyStartYear;
/**
* Default value that indicates the defaultCenturyStartYear is unitialized
*/
static const int32_t fgSystemDefaultCenturyYear;
/**
* start of default century, as a date
*/
static const UDate fgSystemDefaultCentury;
/**
* Initializes the 100-year window that dates with 2-digit years
* are considered to fall within so that its start date is 80 years
* before the current time.
*/
static void initializeSystemDefaultCentury(void);
/**
* When isAmeteAlem is true, then this calendar use only AMETE_ALEM
* for the era. Otherwise (default), this calendar uses both AMETE_ALEM
* and AMETE_MIHRET.
*
* EXTENDED_YEAR isAmeteAlem(false) isAmeteAlem(true)
* 0 Amete Alem 5500 Amete Alem 5500
* 1 Amete Mihret 1 Amete Alem 5501
*/
UBool isAmeteAlem;
public:
/**
* 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;
/**
* 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);
#if 0
// We do not want to introduce this API in ICU4C.
// It was accidentally introduced in ICU4J as a public API.
public:
//-------------------------------------------------------------------------
// Calendar system Conversion methods...
//-------------------------------------------------------------------------
/**
* Convert an Ethiopic year, month, and day to a Julian day.
*
* @param year the extended year
* @param month the month
* @param day the day
* @return Julian day
* @internal
*/
int32_t ethiopicToJD(int32_t year, int32_t month, int32_t day);
#endif
};
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */
#endif /* ETHPCCAL_H */
//eof

View file

@ -582,6 +582,14 @@
/>
</FileConfiguration>
</File>
<File
RelativePath=".\cecal.cpp"
>
</File>
<File
RelativePath=".\cecal.h"
>
</File>
<File
RelativePath=".\chnsecal.cpp"
>
@ -616,6 +624,14 @@
/>
</FileConfiguration>
</File>
<File
RelativePath=".\coptccal.cpp"
>
</File>
<File
RelativePath=".\coptccal.h"
>
</File>
<File
RelativePath=".\curramt.cpp"
>
@ -844,6 +860,14 @@
/>
</FileConfiguration>
</File>
<File
RelativePath=".\ethpccal.cpp"
>
</File>
<File
RelativePath=".\ethpccal.h"
>
</File>
<File
RelativePath=".\unicode\fieldpos.h"
>

View file

@ -1,6 +1,6 @@
/********************************************************************
* COPYRIGHT:
* Copyright (c) 2003-2007, International Business Machines Corporation
* Copyright (c) 2003-2008, International Business Machines Corporation
* and others. All Rights Reserved.
********************************************************************
* Calendar Case Test is a type of CalendarTest which compares the
@ -15,6 +15,8 @@
#include "hebrwcal.h" // for Eras
#include "indiancal.h"
#include "coptccal.h"
#include "ethpccal.h"
#include "unicode/datefmt.h"
#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
@ -27,6 +29,8 @@ void CalendarCaseTest::runIndexedTest( int32_t index, UBool exec, const char* &n
CASE(0,IslamicCivil);
CASE(1,Hebrew);
CASE(2,Indian);
CASE(3,Coptic);
CASE(4,Ethiopic);
default: name = ""; break;
}
}
@ -382,4 +386,95 @@ void CalendarCaseTest::Indian() {
delete c;
}
void CalendarCaseTest::Coptic() {
static const TestCase tests[] = {
// JD Era Year Month Day WkDay Hour Min Sec
{2401442.5, 1, 1579, 2, 20, WED, 0, 0, 0}, // Gregorian: 20/10/1862
{2402422.5, 1, 1581, 10, 29, WED, 0, 0, 0}, // Gregorian: 05/07/1865
{2402630.5, 1, 1582, 5, 22, MON, 0, 0, 0}, // Gregorian: 29/01/1866
{2402708.5, 1, 1582, 8, 10, TUE, 0, 0, 0}, // Gregorian: 17/04/1866
{2402971.5, 1, 1583, 4, 28, SAT, 0, 0, 0}, // Gregorian: 05/01/1867
{2403344.5, 1, 1584, 5, 5, MON, 0, 0, 0}, // Gregorian: 13/01/1868
{1721059.5, 0, 285, 5, 7, SAT, 0, 0, 0}, // Gregorian: 01/01/0000
{1721425.5, 0, 284, 5, 8, MON, 0, 0, 0}, // Gregorian: 01/01/0001
{1824663.5, 0, 2, 13, 6, WED, 0, 0, 0}, // Gregorian: 29/08/0283
{1824664.5, 0, 1, 1, 1, THU, 0, 0, 0}, // Gregorian: 30/08/0283
{1825029.5, 1, 1, 1, 1, FRI, 0, 0, 0}, // Gregorian: 29/08/0284
{1825394.5, 1, 2, 1, 1, SAT, 0, 0, 0}, // Gregorian: 29/08/0285
{1825759.5, 1, 3, 1, 1, SUN, 0, 0, 0}, // Gregorian: 29/08/0286
{1826125.5, 1, 4, 1, 1, TUE, 0, 0, 0}, // Gregorian: 30/08/0287
{1825028.5, 0, 1, 13, 5, THU, 0, 0, 0}, // Gregorian: 28/08/0284
{1825393.5, 1, 1, 13, 5, FRI, 0, 0, 0}, // Gregorian: 28/08/0285
{1825758.5, 1, 2, 13, 5, SAT, 0, 0, 0}, // Gregorian: 28/08/0286
{1826123.5, 1, 3, 13, 5, SUN, 0, 0, 0}, // Gregorian: 28/08/0287
{1826124.5, 1, 3, 13, 6, MON, 0, 0, 0}, // Gregorian: 29/08/0287
// above is first coptic leap year
{1826489.5, 1, 4, 13, 5, TUE, 0, 0, 0}, // Gregorian: 28/08/0288
{2299158.5, 1, 1299, 2, 6, WED, 0, 0, 0}, // Gregorian: 13/10/1582
{2299159.5, 1, 1299, 2, 7, THU, 0, 0, 0}, // Gregorian: 14/10/1582
{2299160.5, 1, 1299, 2, 8, FRI, 0, 0, 0}, // Gregorian: 15/10/1582
{2299161.5, 1, 1299, 2, 9, SAT, 0, 0, 0}, // Gregorian: 16/10/1582
{2415020.5, 1, 1616, 4, 23, MON, 0, 0, 0}, // Gregorian: 01/01/1900
{2453371.5, 1, 1721, 4, 23, SAT, 0, 0, 0}, // Gregorian: 01/01/2005
{2555528.5, 1, 2000, 13, 5, FRI, 0, 0, 0}, // Gregorian: 12/09/2284
{ -1, -1, -1, -1, -1, -1, -1, -1, -1}
};
UErrorCode status = U_ZERO_ERROR;
Calendar *c = Calendar::createInstance("cop_EG@calendar=coptic", status);
c->setLenient(TRUE);
doTestCases(tests, c);
delete c;
}
void CalendarCaseTest::Ethiopic() {
static const TestCase tests[] = {
// JD Era Year Month Day WkDay Hour Min Sec
{2401442.5, 1, 1855, 2, 20, WED, 0, 0, 0}, // Gregorian: 29/10/1862
{2402422.5, 1, 1857, 10, 29, WED, 0, 0, 0}, // Gregorian: 05/07/1865
{2402630.5, 1, 1858, 5, 22, MON, 0, 0, 0}, // Gregorian: 29/01/1866
{2402708.5, 1, 1858, 8, 10, TUE, 0, 0, 0}, // Gregorian: 17/04/1866
{2402971.5, 1, 1859, 4, 28, SAT, 0, 0, 0}, // Gregorian: 05/01/1867
{2403344.5, 1, 1860, 5, 5, MON, 0, 0, 0}, // Gregorian: 13/01/1868
{1721059.5, 0, 5492, 5, 7, SAT, 0, 0, 0}, // Gregorian: 01/01/0000
{1721425.5, 0, 5493, 5, 8, MON, 0, 0, 0}, // Gregorian: 01/01/0001
{1723854.5, 0, 5499, 13, 6, MON, 0, 0, 0}, // Gregorian: 27/08/0007
{1723855.5, 0, 5500, 1, 1, TUE, 0, 0, 0}, // Gregorian: 28/08/0007
{1724220.5, 1, 1, 1, 1, WED, 0, 0, 0}, // Gregorian: 27/08/0008
{1724585.5, 1, 2, 1, 1, THU, 0, 0, 0}, // Gregorian: 27/08/0009
{1724950.5, 1, 3, 1, 1, FRI, 0, 0, 0}, // Gregorian: 27/08/0010
//{1724536.5, 1, 4, 1, 1, SUN, 0, 0, 0}, // Gregorian: 28/08/0011
{1725316.5, 1, 4, 1, 1, SUN, 0, 0, 0}, // Gregorian: 28/08/0011 - dlf
{1724219.5, 0, 5500, 13, 5, TUE, 0, 0, 0}, // Gregorian: 26/08/0008
{1724584.5, 1, 1, 13, 5, WED, 0, 0, 0}, // Gregorian: 26/08/0009
{1724949.5, 1, 2, 13, 5, THU, 0, 0, 0}, // Gregorian: 26/08/0010
{1725314.5, 1, 3, 13, 5, FRI, 0, 0, 0}, // Gregorian: 26/08/0011
{1725315.5, 1, 3, 13, 6, SAT, 0, 0, 0}, // Gregorian: 27/08/0011 - first ethiopic leap year
//{1725560.5, 1, 4, 13, 5, SUN, 0, 0, 0}, // Gregorian: 26/08/0012 - dlf
{1725680.5, 1, 4, 13, 5, SUN, 0, 0, 0}, // Gregorian: 26/08/0012
{2299158.5, 1, 1575, 2, 6, WED, 0, 0, 0}, // Gregorian: 13/10/1582
{2299159.5, 1, 1575, 2, 7, THU, 0, 0, 0}, // Gregorian: 14/10/1582 Julian 04/10/1582
{2299160.5, 1, 1575, 2, 8, FRI, 0, 0, 0}, // Gregorian: 15/10/1582
{2299161.5, 1, 1575, 2, 9, SAT, 0, 0, 0}, // Gregorian: 16/10/1582
{2415020.5, 1, 1892, 4, 23, MON, 0, 0, 0}, // Gregorian: 01/01/1900
{2453371.5, 1, 1997, 4, 23, SAT, 0, 0, 0}, // Gregorian: 01/01/2005
{2454719.5, 1, 2000, 13, 5, WED, 0, 0, 0}, // Gregorian: 10/09/2008
{ -1, -1, -1, -1, -1, -1, -1, -1, -1}
};
UErrorCode status = U_ZERO_ERROR;
Calendar *c = Calendar::createInstance("am_ET@calendar=ethiopic", status);
c->setLenient(TRUE);
doTestCases(tests, c);
delete c;
}
#endif

View file

@ -1,6 +1,6 @@
/********************************************************************
* COPYRIGHT:
* Copyright (c) 2003-2007, International Business Machines Corporation
* Copyright (c) 2003-2008, International Business Machines Corporation
* and others. All Rights Reserved.
********************************************************************
* Calendar Case Test is a type of CalendarTest which compares the
@ -57,6 +57,8 @@ class CalendarCaseTest: public CalendarTest {
void IslamicCivil();
void Hebrew();
void Indian();
void Coptic();
void Ethiopic();
};
#endif