mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-07 06:25:30 +00:00
ICU-22027 Add C++ Calendar API for Temporal
API proposal https://docs.google.com/document/d/1UYriEzzExiLhi2RD3zjTsI5UQHv1dXaFqrct7yXNdCA/edit#heading=h.x9obor85vpx9 Design Doc https://docs.google.com/document/d/15ViyC9s0k3VEDwBmAkKxxz4IadZ6QrAIoETkdkF0cVA/ ICU-22027 Adjust API to remove the mention of M00L for now.
This commit is contained in:
parent
a7f4531bfa
commit
cd1b772cbf
21 changed files with 2212 additions and 338 deletions
|
@ -660,6 +660,7 @@ static const int32_t kCalendarLimits[UCAL_FIELD_COUNT][4] = {
|
|||
{ -0x7F000000, -0x7F000000, 0x7F000000, 0x7F000000 }, // JULIAN_DAY
|
||||
{ 0, 0, 24*kOneHour-1, 24*kOneHour-1 }, // MILLISECONDS_IN_DAY
|
||||
{ 0, 0, 1, 1 }, // IS_LEAP_MONTH
|
||||
{ 0, 0, 11, 11 } // ORDINAL_MONTH
|
||||
};
|
||||
|
||||
// Resource bundle tags read by this class
|
||||
|
@ -1421,7 +1422,8 @@ void Calendar::computeFields(UErrorCode &ec)
|
|||
(1 << UCAL_MONTH) |
|
||||
(1 << UCAL_DAY_OF_MONTH) | // = UCAL_DATE
|
||||
(1 << UCAL_DAY_OF_YEAR) |
|
||||
(1 << UCAL_EXTENDED_YEAR);
|
||||
(1 << UCAL_EXTENDED_YEAR) |
|
||||
(1 << UCAL_ORDINAL_MONTH);
|
||||
|
||||
for (int32_t i=0; i<UCAL_FIELD_COUNT; ++i) {
|
||||
if ((mask & 1) == 0) {
|
||||
|
@ -1690,7 +1692,9 @@ void Calendar::handleComputeFields(int32_t /* julianDay */, UErrorCode& status)
|
|||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
internalSet(UCAL_MONTH, getGregorianMonth());
|
||||
int32_t month = getGregorianMonth();
|
||||
internalSet(UCAL_MONTH, month);
|
||||
internalSet(UCAL_ORDINAL_MONTH, month);
|
||||
internalSet(UCAL_DAY_OF_MONTH, getGregorianDayOfMonth());
|
||||
internalSet(UCAL_DAY_OF_YEAR, getGregorianDayOfYear());
|
||||
int32_t eyear = getGregorianYear();
|
||||
|
@ -1772,6 +1776,7 @@ void Calendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& statu
|
|||
}
|
||||
|
||||
case UCAL_MONTH:
|
||||
case UCAL_ORDINAL_MONTH:
|
||||
// Rolling the month involves both pinning the final value
|
||||
// and adjusting the DAY_OF_MONTH if necessary. We only adjust the
|
||||
// DAY_OF_MONTH if, after updating the MONTH field, it is illegal.
|
||||
|
@ -1829,6 +1834,7 @@ void Calendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& statu
|
|||
}
|
||||
set(field, newYear);
|
||||
pinField(UCAL_MONTH,status);
|
||||
pinField(UCAL_ORDINAL_MONTH,status);
|
||||
pinField(UCAL_DAY_OF_MONTH,status);
|
||||
return;
|
||||
}
|
||||
|
@ -1837,6 +1843,7 @@ void Calendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& statu
|
|||
// Rolling the year can involve pinning the DAY_OF_MONTH.
|
||||
set(field, internalGet(field) + amount);
|
||||
pinField(UCAL_MONTH,status);
|
||||
pinField(UCAL_ORDINAL_MONTH,status);
|
||||
pinField(UCAL_DAY_OF_MONTH,status);
|
||||
return;
|
||||
|
||||
|
@ -1976,6 +1983,7 @@ void Calendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& statu
|
|||
// have to be updated as well.
|
||||
set(UCAL_DAY_OF_YEAR, day_of_year);
|
||||
clear(UCAL_MONTH);
|
||||
clear(UCAL_ORDINAL_MONTH);
|
||||
return;
|
||||
}
|
||||
case UCAL_DAY_OF_YEAR:
|
||||
|
@ -2118,6 +2126,7 @@ void Calendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status
|
|||
U_FALLTHROUGH;
|
||||
case UCAL_EXTENDED_YEAR:
|
||||
case UCAL_MONTH:
|
||||
case UCAL_ORDINAL_MONTH:
|
||||
{
|
||||
UBool oldLenient = isLenient();
|
||||
setLenient(true);
|
||||
|
@ -2700,7 +2709,6 @@ int32_t Calendar::getLimit(UCalendarDateFields field, ELimitType limitType) cons
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
int32_t
|
||||
Calendar::getActualMinimum(UCalendarDateFields field, UErrorCode& status) const
|
||||
{
|
||||
|
@ -2764,6 +2772,47 @@ Calendar::inDaylightTime(UErrorCode& status) const
|
|||
return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : false);
|
||||
}
|
||||
|
||||
bool
|
||||
Calendar::inTemporalLeapYear(UErrorCode& status) const
|
||||
{
|
||||
// Default to Gregorian based leap year rule.
|
||||
return getActualMaximum(UCAL_DAY_OF_YEAR, status) == 366;
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
static const char * const gTemporalMonthCodes[] = {
|
||||
"M01", "M02", "M03", "M04", "M05", "M06",
|
||||
"M07", "M08", "M09", "M10", "M11", "M12", nullptr
|
||||
};
|
||||
|
||||
const char*
|
||||
Calendar::getTemporalMonthCode(UErrorCode& status) const
|
||||
{
|
||||
int32_t month = get(UCAL_MONTH, status);
|
||||
if (U_FAILURE(status)) return nullptr;
|
||||
U_ASSERT(month < 12);
|
||||
U_ASSERT(internalGet(UCAL_IS_LEAP_MONTH) == 0);
|
||||
return gTemporalMonthCodes[month];
|
||||
}
|
||||
|
||||
void
|
||||
Calendar::setTemporalMonthCode(const char* code, UErrorCode& status )
|
||||
{
|
||||
if (U_FAILURE(status)) return;
|
||||
int32_t len = static_cast<int32_t>(uprv_strlen(code));
|
||||
if (len == 3 && code[0] == 'M') {
|
||||
for (int m = 0; gTemporalMonthCodes[m] != nullptr; m++) {
|
||||
if (uprv_strcmp(code, gTemporalMonthCodes[m]) == 0) {
|
||||
set(UCAL_MONTH, m);
|
||||
set(UCAL_IS_LEAP_MONTH, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
/**
|
||||
|
@ -2799,7 +2848,7 @@ void Calendar::validateField(UCalendarDateFields field, UErrorCode &status) {
|
|||
switch (field) {
|
||||
case UCAL_DAY_OF_MONTH:
|
||||
y = handleGetExtendedYear();
|
||||
validateField(field, 1, handleGetMonthLength(y, internalGet(UCAL_MONTH)), status);
|
||||
validateField(field, 1, handleGetMonthLength(y, internalGetMonth()), status);
|
||||
break;
|
||||
case UCAL_DAY_OF_YEAR:
|
||||
y = handleGetExtendedYear();
|
||||
|
@ -2860,7 +2909,7 @@ UCalendarDateFields Calendar::newerField(UCalendarDateFields defaultField, UCale
|
|||
return defaultField;
|
||||
}
|
||||
|
||||
UCalendarDateFields Calendar::resolveFields(const UFieldResolutionTable* precedenceTable) {
|
||||
UCalendarDateFields Calendar::resolveFields(const UFieldResolutionTable* precedenceTable) const {
|
||||
int32_t bestField = UCAL_FIELD_COUNT;
|
||||
int32_t tempBestField;
|
||||
for (int32_t g=0; precedenceTable[g][0][0] != -1 && (bestField == UCAL_FIELD_COUNT); ++g) {
|
||||
|
@ -2929,6 +2978,16 @@ const UFieldResolutionTable Calendar::kDatePrecedence[] =
|
|||
};
|
||||
|
||||
|
||||
const UFieldResolutionTable Calendar::kMonthPrecedence[] =
|
||||
{
|
||||
{
|
||||
{ UCAL_MONTH,kResolveSTOP, kResolveSTOP },
|
||||
{ UCAL_ORDINAL_MONTH,kResolveSTOP, kResolveSTOP },
|
||||
{kResolveSTOP}
|
||||
},
|
||||
{{kResolveSTOP}}
|
||||
};
|
||||
|
||||
const UFieldResolutionTable Calendar::kDOWPrecedence[] =
|
||||
{
|
||||
{
|
||||
|
@ -3211,6 +3270,7 @@ int32_t Calendar::computeJulianDay()
|
|||
if (fStamp[UCAL_JULIAN_DAY] >= (int32_t)kMinimumUserStamp) {
|
||||
int32_t bestStamp = newestStamp(UCAL_ERA, UCAL_DAY_OF_WEEK_IN_MONTH, kUnset);
|
||||
bestStamp = newestStamp(UCAL_YEAR_WOY, UCAL_EXTENDED_YEAR, bestStamp);
|
||||
bestStamp = newestStamp(UCAL_ORDINAL_MONTH, UCAL_ORDINAL_MONTH, bestStamp);
|
||||
if (bestStamp <= fStamp[UCAL_JULIAN_DAY]) {
|
||||
return internalGet(UCAL_JULIAN_DAY);
|
||||
}
|
||||
|
@ -3250,8 +3310,8 @@ int32_t Calendar::handleComputeJulianDay(UCalendarDateFields bestField) {
|
|||
// give calendar subclass a chance to have a default 'first' month
|
||||
int32_t month;
|
||||
|
||||
if(isSet(UCAL_MONTH)) {
|
||||
month = internalGet(UCAL_MONTH);
|
||||
if(isSet(UCAL_MONTH) || isSet(UCAL_ORDINAL_MONTH)) {
|
||||
month = internalGetMonth();
|
||||
} else {
|
||||
month = getDefaultMonthInYear(year);
|
||||
}
|
||||
|
@ -3319,7 +3379,7 @@ int32_t Calendar::handleComputeJulianDay(UCalendarDateFields bestField) {
|
|||
// past the first of the given day-of-week in this month.
|
||||
// Note that we handle -2, -3, etc. correctly, even though
|
||||
// values < -1 are technically disallowed.
|
||||
int32_t m = internalGet(UCAL_MONTH, UCAL_JANUARY);
|
||||
int32_t m = internalGetMonth(UCAL_JANUARY);
|
||||
int32_t monthLength = handleGetMonthLength(year, m);
|
||||
date += ((monthLength - date) / 7 + dim + 1) * 7;
|
||||
}
|
||||
|
@ -3544,23 +3604,25 @@ int32_t Calendar::handleGetExtendedYearFromWeekFields(int32_t yearWoy, int32_t w
|
|||
}
|
||||
|
||||
case UCAL_DATE:
|
||||
if((internalGet(UCAL_MONTH)==0) &&
|
||||
{
|
||||
int32_t m = internalGetMonth();
|
||||
if((m == 0) &&
|
||||
(woy >= getLeastMaximum(UCAL_WEEK_OF_YEAR))) {
|
||||
return yearWoy+1; // month 0, late woy = in the next year
|
||||
} else if(woy==1) {
|
||||
//if(nextJan1InPrevYear) {
|
||||
if(internalGet(UCAL_MONTH)==0) {
|
||||
if(m == 0) {
|
||||
return yearWoy;
|
||||
} else {
|
||||
return yearWoy-1;
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
//(internalGet(UCAL_DATE) <= (7-first)) /* && in minDow */ ) {
|
||||
//within 1st week and in this month..
|
||||
//return yearWoy+1;
|
||||
return yearWoy;
|
||||
}
|
||||
//(internalGet(UCAL_DATE) <= (7-first)) /* && in minDow */ ) {
|
||||
//within 1st week and in this month..
|
||||
//return yearWoy+1;
|
||||
return yearWoy;
|
||||
|
||||
default: // assume the year is appropriate
|
||||
return yearWoy;
|
||||
|
@ -3626,6 +3688,10 @@ Calendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const
|
|||
result = getMaximum(field);
|
||||
break;
|
||||
|
||||
case UCAL_ORDINAL_MONTH:
|
||||
result = inTemporalLeapYear(status) ? getMaximum(UCAL_ORDINAL_MONTH) : getLeastMaximum(UCAL_ORDINAL_MONTH);
|
||||
break;
|
||||
|
||||
default:
|
||||
// For all other fields, do it the hard way....
|
||||
result = getActualHelper(field, getLeastMaximum(field), getMaximum(field),status);
|
||||
|
@ -3955,6 +4021,20 @@ Calendar::internalSet(EDateFields field, int32_t value)
|
|||
internalSet((UCalendarDateFields) field, value);
|
||||
}
|
||||
|
||||
int32_t Calendar::internalGetMonth() const {
|
||||
if (resolveFields(kMonthPrecedence) == UCAL_MONTH) {
|
||||
return internalGet(UCAL_MONTH);
|
||||
}
|
||||
return internalGet(UCAL_ORDINAL_MONTH);
|
||||
}
|
||||
|
||||
int32_t Calendar::internalGetMonth(int32_t defaultValue) const {
|
||||
if (resolveFields(kMonthPrecedence) == UCAL_MONTH) {
|
||||
return internalGet(UCAL_MONTH, defaultValue);
|
||||
}
|
||||
return internalGet(UCAL_ORDINAL_MONTH);
|
||||
}
|
||||
|
||||
BasicTimeZone*
|
||||
Calendar::getBasicTimeZone(void) const {
|
||||
if (dynamic_cast<const OlsonTimeZone *>(fZone) != NULL
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include "cecal.h"
|
||||
#include "gregoimp.h" //Math
|
||||
#include "cstring.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -42,6 +43,7 @@ static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = {
|
|||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
|
||||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY
|
||||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
|
||||
{ 0, 0, 12, 12}, // ORDINAL_MONTH
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -132,6 +134,24 @@ CECalendar::jdToCE(int32_t julianDay, int32_t jdEpochOffset, int32_t& year, int3
|
|||
day = (doy % 30) + 1; // 1-based days in a month
|
||||
}
|
||||
|
||||
static const char* kMonthCode13 = "M13";
|
||||
|
||||
const char* CECalendar::getTemporalMonthCode(UErrorCode& status) const {
|
||||
if (get(UCAL_MONTH, status) == 12) return kMonthCode13;
|
||||
return Calendar::getTemporalMonthCode(status);
|
||||
}
|
||||
|
||||
void
|
||||
CECalendar::setTemporalMonthCode(const char* code, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) return;
|
||||
if (uprv_strcmp(code, kMonthCode13) == 0) {
|
||||
set(UCAL_MONTH, 12);
|
||||
set(UCAL_IS_LEAP_MONTH, 0);
|
||||
return;
|
||||
}
|
||||
Calendar::setTemporalMonthCode(code, status);
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
|
|
@ -24,6 +24,36 @@ U_NAMESPACE_BEGIN
|
|||
*/
|
||||
class U_I18N_API CECalendar : public Calendar {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Gets The Temporal monthCode value corresponding to the month for the date.
|
||||
* The value is a string identifier that starts with the literal grapheme
|
||||
* "M" followed by two graphemes representing the zero-padded month number
|
||||
* of the current month in a normal (non-leap) year. For the short thirteen
|
||||
* month in each year in the CECalendar, the value is "M13".
|
||||
*
|
||||
* @param status ICU Error Code
|
||||
* @return One of 13 possible strings in {"M01".. "M12", "M13"}.
|
||||
* @draft ICU 73
|
||||
*/
|
||||
virtual const char* getTemporalMonthCode(UErrorCode& status) const override;
|
||||
|
||||
/**
|
||||
* Sets The Temporal monthCode which is a string identifier that starts
|
||||
* with the literal grapheme "M" followed by two graphemes representing
|
||||
* the zero-padded month number of the current month in a normal
|
||||
* (non-leap) year. For CECalendar calendar, the values
|
||||
* are "M01" .. "M13" while the "M13" is represent the short thirteen month
|
||||
* in each year.
|
||||
*
|
||||
* @param temporalMonth The value to be set for temporal monthCode.
|
||||
* @param status ICU Error Code
|
||||
*
|
||||
* @draft ICU 73
|
||||
*/
|
||||
virtual void setTemporalMonthCode(const char* code, UErrorCode& status) override;
|
||||
|
||||
protected:
|
||||
//-------------------------------------------------------------------------
|
||||
// Constructors...
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "unicode/simpletz.h"
|
||||
#include "uhash.h"
|
||||
#include "ucln_in.h"
|
||||
#include "cstring.h"
|
||||
|
||||
// Debugging
|
||||
#ifdef U_DEBUG_CHNSECAL
|
||||
|
@ -124,7 +125,7 @@ ChineseCalendar* ChineseCalendar::clone() const {
|
|||
|
||||
ChineseCalendar::ChineseCalendar(const Locale& aLocale, UErrorCode& success)
|
||||
: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success),
|
||||
isLeapYear(false),
|
||||
hasLeapMonthBetweenWinterSolstices(false),
|
||||
fEpochYear(CHINESE_EPOCH_YEAR),
|
||||
fZoneAstroCalc(getChineseCalZoneAstroCalc())
|
||||
{
|
||||
|
@ -134,7 +135,7 @@ ChineseCalendar::ChineseCalendar(const Locale& aLocale, UErrorCode& success)
|
|||
ChineseCalendar::ChineseCalendar(const Locale& aLocale, int32_t epochYear,
|
||||
const TimeZone* zoneAstroCalc, UErrorCode &success)
|
||||
: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success),
|
||||
isLeapYear(false),
|
||||
hasLeapMonthBetweenWinterSolstices(false),
|
||||
fEpochYear(epochYear),
|
||||
fZoneAstroCalc(zoneAstroCalc)
|
||||
{
|
||||
|
@ -142,7 +143,7 @@ ChineseCalendar::ChineseCalendar(const Locale& aLocale, int32_t epochYear,
|
|||
}
|
||||
|
||||
ChineseCalendar::ChineseCalendar(const ChineseCalendar& other) : Calendar(other) {
|
||||
isLeapYear = other.isLeapYear;
|
||||
hasLeapMonthBetweenWinterSolstices = other.hasLeapMonthBetweenWinterSolstices;
|
||||
fEpochYear = other.fEpochYear;
|
||||
fZoneAstroCalc = other.fZoneAstroCalc;
|
||||
}
|
||||
|
@ -196,6 +197,7 @@ static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = {
|
|||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
|
||||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY
|
||||
{ 0, 0, 1, 1}, // IS_LEAP_MONTH
|
||||
{ 0, 0, 11, 12}, // ORDINAL_MONTH
|
||||
};
|
||||
|
||||
|
||||
|
@ -321,7 +323,6 @@ const UFieldResolutionTable* ChineseCalendar::getFieldResolutionTable() const {
|
|||
* @stable ICU 2.8
|
||||
*/
|
||||
int32_t ChineseCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth) const {
|
||||
|
||||
ChineseCalendar *nonConstThis = (ChineseCalendar*)this; // cast away const
|
||||
|
||||
// If the month is out of range, adjust it into range, and
|
||||
|
@ -340,6 +341,7 @@ int32_t ChineseCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, U
|
|||
|
||||
// Save fields for later restoration
|
||||
int32_t saveMonth = internalGet(UCAL_MONTH);
|
||||
int32_t saveOrdinalMonth = internalGet(UCAL_ORDINAL_MONTH);
|
||||
int32_t saveIsLeapMonth = internalGet(UCAL_IS_LEAP_MONTH);
|
||||
|
||||
// Ignore IS_LEAP_MONTH field if useMonth is false
|
||||
|
@ -361,8 +363,8 @@ int32_t ChineseCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, U
|
|||
}
|
||||
|
||||
nonConstThis->internalSet(UCAL_MONTH, saveMonth);
|
||||
nonConstThis->internalSet(UCAL_ORDINAL_MONTH, saveOrdinalMonth);
|
||||
nonConstThis->internalSet(UCAL_IS_LEAP_MONTH, saveIsLeapMonth);
|
||||
|
||||
return julianDay - 1;
|
||||
}
|
||||
|
||||
|
@ -374,6 +376,7 @@ int32_t ChineseCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, U
|
|||
void ChineseCalendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status) {
|
||||
switch (field) {
|
||||
case UCAL_MONTH:
|
||||
case UCAL_ORDINAL_MONTH:
|
||||
if (amount != 0) {
|
||||
int32_t dom = get(UCAL_DAY_OF_MONTH, status);
|
||||
if (U_FAILURE(status)) break;
|
||||
|
@ -404,6 +407,7 @@ void ChineseCalendar::add(EDateFields field, int32_t amount, UErrorCode& status)
|
|||
void ChineseCalendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& status) {
|
||||
switch (field) {
|
||||
case UCAL_MONTH:
|
||||
case UCAL_ORDINAL_MONTH:
|
||||
if (amount != 0) {
|
||||
int32_t dom = get(UCAL_DAY_OF_MONTH, status);
|
||||
if (U_FAILURE(status)) break;
|
||||
|
@ -419,7 +423,7 @@ void ChineseCalendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode
|
|||
// leap year.
|
||||
int32_t m = get(UCAL_MONTH, status); // 0-based month
|
||||
if (U_FAILURE(status)) break;
|
||||
if (isLeapYear) { // (member variable)
|
||||
if (hasLeapMonthBetweenWinterSolstices) { // (member variable)
|
||||
if (get(UCAL_IS_LEAP_MONTH, status) == 1) {
|
||||
++m;
|
||||
} else {
|
||||
|
@ -442,7 +446,7 @@ void ChineseCalendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode
|
|||
|
||||
// Now do the standard roll computation on m, with the
|
||||
// allowed range of 0..n-1, where n is 12 or 13.
|
||||
int32_t n = isLeapYear ? 13 : 12; // Months in this year
|
||||
int32_t n = hasLeapMonthBetweenWinterSolstices ? 13 : 12; // Months in this year
|
||||
int32_t newM = (m + amount) % n;
|
||||
if (newM < 0) {
|
||||
newM += n;
|
||||
|
@ -661,7 +665,7 @@ UBool ChineseCalendar::isLeapMonthBetween(int32_t newMoon1, int32_t newMoon2) co
|
|||
* IS_LEAP_MONTH fields, as required by
|
||||
* <code>handleComputeMonthStart()</code>.
|
||||
*
|
||||
* <p>As a side effect, this method sets {@link #isLeapYear}.
|
||||
* <p>As a side effect, this method sets {@link #hasLeapMonthBetweenWinterSolstices}.
|
||||
* @param days days after January 1, 1970 0:00 astronomical base zone
|
||||
* of the date to compute fields for
|
||||
* @param gyear the Gregorian year of the given date
|
||||
|
@ -672,7 +676,6 @@ UBool ChineseCalendar::isLeapMonthBetween(int32_t newMoon1, int32_t newMoon2) co
|
|||
*/
|
||||
void ChineseCalendar::computeChineseFields(int32_t days, int32_t gyear, int32_t gmonth,
|
||||
UBool setAllFields) {
|
||||
|
||||
// Find the winter solstices before and after the target date.
|
||||
// These define the boundaries of this Chinese year, specifically,
|
||||
// the position of month 11, which always contains the solstice.
|
||||
|
@ -692,24 +695,33 @@ void ChineseCalendar::computeChineseFields(int32_t days, int32_t gyear, int32_t
|
|||
int32_t firstMoon = newMoonNear(solsticeBefore + 1, true);
|
||||
int32_t lastMoon = newMoonNear(solsticeAfter + 1, false);
|
||||
int32_t thisMoon = newMoonNear(days + 1, false); // Start of this month
|
||||
// Note: isLeapYear is a member variable
|
||||
isLeapYear = synodicMonthsBetween(firstMoon, lastMoon) == 12;
|
||||
// Note: hasLeapMonthBetweenWinterSolstices is a member variable
|
||||
hasLeapMonthBetweenWinterSolstices = synodicMonthsBetween(firstMoon, lastMoon) == 12;
|
||||
|
||||
int32_t month = synodicMonthsBetween(firstMoon, thisMoon);
|
||||
if (isLeapYear && isLeapMonthBetween(firstMoon, thisMoon)) {
|
||||
int32_t theNewYear = newYear(gyear);
|
||||
if (days < theNewYear) {
|
||||
theNewYear = newYear(gyear-1);
|
||||
}
|
||||
if (hasLeapMonthBetweenWinterSolstices && isLeapMonthBetween(firstMoon, thisMoon)) {
|
||||
month--;
|
||||
}
|
||||
if (month < 1) {
|
||||
month += 12;
|
||||
}
|
||||
|
||||
UBool isLeapMonth = isLeapYear &&
|
||||
int32_t ordinalMonth = synodicMonthsBetween(theNewYear, thisMoon);
|
||||
if (ordinalMonth < 0) {
|
||||
ordinalMonth += 12;
|
||||
}
|
||||
UBool isLeapMonth = hasLeapMonthBetweenWinterSolstices &&
|
||||
hasNoMajorSolarTerm(thisMoon) &&
|
||||
!isLeapMonthBetween(firstMoon, newMoonNear(thisMoon - SYNODIC_GAP, false));
|
||||
|
||||
internalSet(UCAL_MONTH, month-1); // Convert from 1-based to 0-based
|
||||
internalSet(UCAL_ORDINAL_MONTH, ordinalMonth); // Convert from 1-based to 0-based
|
||||
internalSet(UCAL_IS_LEAP_MONTH, isLeapMonth?1:0);
|
||||
|
||||
|
||||
if (setAllFields) {
|
||||
|
||||
// Extended year and cycle year is based on the epoch year
|
||||
|
@ -897,8 +909,83 @@ ChineseCalendar::internalGetDefaultCenturyStartYear() const
|
|||
return gSystemDefaultCenturyStartYear;
|
||||
}
|
||||
|
||||
bool
|
||||
ChineseCalendar::inTemporalLeapYear(UErrorCode &status) const
|
||||
{
|
||||
int32_t days = getActualMaximum(UCAL_DAY_OF_YEAR, status);
|
||||
if (U_FAILURE(status)) return false;
|
||||
return days > 360;
|
||||
}
|
||||
|
||||
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ChineseCalendar)
|
||||
|
||||
|
||||
static const char * const gTemporalLeapMonthCodes[] = {
|
||||
"M01L", "M02L", "M03L", "M04L", "M05L", "M06L",
|
||||
"M07L", "M08L", "M09L", "M10L", "M11L", "M12L", nullptr
|
||||
};
|
||||
|
||||
const char* ChineseCalendar::getTemporalMonthCode(UErrorCode &status) const {
|
||||
// We need to call get, not internalGet, to force the calculation
|
||||
// from UCAL_ORDINAL_MONTH.
|
||||
int32_t is_leap = get(UCAL_IS_LEAP_MONTH, status);
|
||||
if (U_FAILURE(status)) return nullptr;
|
||||
if (is_leap != 0) {
|
||||
int32_t month = get(UCAL_MONTH, status);
|
||||
if (U_FAILURE(status)) return nullptr;
|
||||
return gTemporalLeapMonthCodes[month];
|
||||
}
|
||||
return Calendar::getTemporalMonthCode(status);
|
||||
}
|
||||
|
||||
void
|
||||
ChineseCalendar::setTemporalMonthCode(const char* code, UErrorCode& status )
|
||||
{
|
||||
if (U_FAILURE(status)) return;
|
||||
int32_t len = static_cast<int32_t>(uprv_strlen(code));
|
||||
if (len != 4 || code[0] != 'M' || code[3] != 'L') {
|
||||
set(UCAL_IS_LEAP_MONTH, 0);
|
||||
return Calendar::setTemporalMonthCode(code, status);
|
||||
}
|
||||
for (int m = 0; gTemporalLeapMonthCodes[m] != nullptr; m++) {
|
||||
if (uprv_strcmp(code, gTemporalLeapMonthCodes[m]) == 0) {
|
||||
set(UCAL_MONTH, m);
|
||||
set(UCAL_IS_LEAP_MONTH, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
}
|
||||
|
||||
int32_t ChineseCalendar::internalGetMonth() const {
|
||||
if (resolveFields(kMonthPrecedence) == UCAL_MONTH) {
|
||||
return internalGet(UCAL_MONTH);
|
||||
}
|
||||
LocalPointer<Calendar> temp(this->clone());
|
||||
temp->set(UCAL_MONTH, 0);
|
||||
temp->set(UCAL_IS_LEAP_MONTH, 0);
|
||||
temp->set(UCAL_DATE, 1);
|
||||
// Calculate the UCAL_MONTH and UCAL_IS_LEAP_MONTH by adding number of
|
||||
// months.
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
temp->roll(UCAL_MONTH, internalGet(UCAL_ORDINAL_MONTH), status);
|
||||
|
||||
|
||||
ChineseCalendar *nonConstThis = (ChineseCalendar*)this; // cast away const
|
||||
nonConstThis->internalSet(UCAL_IS_LEAP_MONTH, temp->get(UCAL_IS_LEAP_MONTH, status));
|
||||
int32_t month = temp->get(UCAL_MONTH, status);
|
||||
U_ASSERT(U_SUCCESS(status));
|
||||
nonConstThis->internalSet(UCAL_MONTH, month);
|
||||
return month;
|
||||
}
|
||||
|
||||
int32_t ChineseCalendar::internalGetMonth(int32_t defaultValue) const {
|
||||
if (resolveFields(kMonthPrecedence) == UCAL_MONTH) {
|
||||
return internalGet(UCAL_MONTH, defaultValue);
|
||||
}
|
||||
return internalGetMonth();
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
|
|
@ -113,6 +113,49 @@ class U_I18N_API ChineseCalendar : public Calendar {
|
|||
*/
|
||||
ChineseCalendar(const Locale& aLocale, UErrorCode &success);
|
||||
|
||||
/**
|
||||
* Returns true if the date is in a leap year.
|
||||
*
|
||||
* @param status ICU Error Code
|
||||
* @return True if the date in the fields is in a Temporal proposal
|
||||
* defined leap year. False otherwise.
|
||||
*/
|
||||
virtual bool inTemporalLeapYear(UErrorCode &status) const override;
|
||||
|
||||
/**
|
||||
* Gets The Temporal monthCode value corresponding to the month for the date.
|
||||
* The value is a string identifier that starts with the literal grapheme
|
||||
* "M" followed by two graphemes representing the zero-padded month number
|
||||
* of the current month in a normal (non-leap) year and suffixed by an
|
||||
* optional literal grapheme "L" if this is a leap month in a lunisolar
|
||||
* calendar. For Chinese calendars (including Dangi), the values are
|
||||
* "M01" .. "M12" for non-leap year, and "M01" .. "M12" with one of
|
||||
* "M01L" .. "M12L" for leap year.
|
||||
*
|
||||
* @param status ICU Error Code
|
||||
* @return One of 24 possible strings in
|
||||
* {"M01" .. "M12", "M01L" .. "M12L"}.
|
||||
* @draft ICU 73
|
||||
*/
|
||||
virtual const char* getTemporalMonthCode(UErrorCode &status) const override;
|
||||
|
||||
/**
|
||||
* Sets The Temporal monthCode which is a string identifier that starts
|
||||
* with the literal grapheme "M" followed by two graphemes representing
|
||||
* the zero-padded month number of the current month in a normal
|
||||
* (non-leap) year and suffixed by an optional literal grapheme "L" if this
|
||||
* is a leap month in a lunisolar calendar. For Chinese calendars, the values
|
||||
* are "M01" .. "M12" for non-leap years, and "M01" .. "M12" plus one in
|
||||
* "M01L" .. "M12L" for leap year.
|
||||
*
|
||||
* @param temporalMonth The value to be set for temporal monthCode. One of
|
||||
* 24 possible strings in {"M01" .. "M12", "M01L" .. "M12L"}.
|
||||
* @param status ICU Error Code
|
||||
*
|
||||
* @draft ICU 73
|
||||
*/
|
||||
virtual void setTemporalMonthCode(const char* code, UErrorCode& status) override;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
|
@ -152,7 +195,12 @@ class U_I18N_API ChineseCalendar : public Calendar {
|
|||
// Internal data....
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
UBool isLeapYear;
|
||||
// There is a leap month between the Winter Solstice before and after the
|
||||
// current date.This is different from leap year because in some year, such as
|
||||
// 1813 and 2033, the leap month is after the Winter Solstice of that year. So
|
||||
// this value could be false for a date prior to the Winter Solstice of that
|
||||
// year but that year still has a leap month and therefor is a leap year.
|
||||
UBool hasLeapMonthBetweenWinterSolstices;
|
||||
int32_t fEpochYear; // Start year of this Chinese calendar instance.
|
||||
const TimeZone* fZoneAstroCalc; // Zone used for the astronomical calculation
|
||||
// of this Chinese calendar instance.
|
||||
|
@ -241,6 +289,10 @@ class U_I18N_API ChineseCalendar : public Calendar {
|
|||
*/
|
||||
virtual const char * getType() const override;
|
||||
|
||||
protected:
|
||||
virtual int32_t internalGetMonth(int32_t defaultValue) const override;
|
||||
|
||||
virtual int32_t internalGetMonth() const override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
|
|
|
@ -92,6 +92,7 @@ CopticCalendar::handleComputeFields(int32_t julianDay, UErrorCode &/*status*/)
|
|||
internalSet(UCAL_ERA, era);
|
||||
internalSet(UCAL_YEAR, year);
|
||||
internalSet(UCAL_MONTH, month);
|
||||
internalSet(UCAL_ORDINAL_MONTH, month);
|
||||
internalSet(UCAL_DATE, day);
|
||||
internalSet(UCAL_DAY_OF_YEAR, (30 * month) + day);
|
||||
}
|
||||
|
|
|
@ -80,6 +80,7 @@ EthiopicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &/*status*/)
|
|||
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_ORDINAL_MONTH, month);
|
||||
internalSet(UCAL_DATE, day);
|
||||
internalSet(UCAL_DAY_OF_YEAR, (30 * month) + day);
|
||||
}
|
||||
|
@ -216,6 +217,7 @@ EthiopicAmeteAlemCalendar::handleComputeFields(int32_t julianDay, UErrorCode &/*
|
|||
internalSet(UCAL_ERA, AMETE_ALEM);
|
||||
internalSet(UCAL_YEAR, eyear + AMETE_MIHRET_DELTA);
|
||||
internalSet(UCAL_MONTH, month);
|
||||
internalSet(UCAL_ORDINAL_MONTH, month);
|
||||
internalSet(UCAL_DATE, day);
|
||||
internalSet(UCAL_DAY_OF_YEAR, (30 * month) + day);
|
||||
}
|
||||
|
|
|
@ -101,6 +101,7 @@ static const int32_t kGregorianCalendarLimits[UCAL_FIELD_COUNT][4] = {
|
|||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
|
||||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY
|
||||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
|
||||
{ 0, 0, 11, 11}, // ORDINAL_MONTH
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -435,6 +436,7 @@ void GregorianCalendar::handleComputeFields(int32_t julianDay, UErrorCode& statu
|
|||
}
|
||||
|
||||
internalSet(UCAL_MONTH, month);
|
||||
internalSet(UCAL_ORDINAL_MONTH, month);
|
||||
internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
|
||||
internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
|
||||
internalSet(UCAL_EXTENDED_YEAR, eyear);
|
||||
|
@ -633,7 +635,7 @@ GregorianCalendar::yearLength() const
|
|||
void
|
||||
GregorianCalendar::pinDayOfMonth()
|
||||
{
|
||||
int32_t monthLen = monthLength(internalGet(UCAL_MONTH));
|
||||
int32_t monthLen = monthLength(internalGetMonth());
|
||||
int32_t dom = internalGet(UCAL_DATE);
|
||||
if(dom > monthLen)
|
||||
set(UCAL_DATE, monthLen);
|
||||
|
@ -659,7 +661,7 @@ GregorianCalendar::validateFields() const
|
|||
if (isSet(UCAL_DATE)) {
|
||||
int32_t date = internalGet(UCAL_DATE);
|
||||
if (date < getMinimum(UCAL_DATE) ||
|
||||
date > monthLength(internalGet(UCAL_MONTH))) {
|
||||
date > monthLength(internalGetMonth())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -839,7 +841,7 @@ GregorianCalendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& s
|
|||
case UCAL_DAY_OF_MONTH:
|
||||
case UCAL_WEEK_OF_MONTH:
|
||||
{
|
||||
int32_t max = monthLength(internalGet(UCAL_MONTH));
|
||||
int32_t max = monthLength(internalGetMonth());
|
||||
UDate t = internalGetTime();
|
||||
// We subtract 1 from the DAY_OF_MONTH to make it zero-based, and an
|
||||
// additional 10 if we are after the cutover. Thus the monthStart
|
||||
|
@ -872,7 +874,7 @@ GregorianCalendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& s
|
|||
// may be one year before or after the calendar year.
|
||||
int32_t isoYear = get(UCAL_YEAR_WOY, status);
|
||||
int32_t isoDoy = internalGet(UCAL_DAY_OF_YEAR);
|
||||
if (internalGet(UCAL_MONTH) == UCAL_JANUARY) {
|
||||
if (internalGetMonth() == UCAL_JANUARY) {
|
||||
if (woy >= 52) {
|
||||
isoDoy += handleGetYearLength(isoYear);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
#include "cmemory.h"
|
||||
#include "cstring.h"
|
||||
#include "umutex.h"
|
||||
#include <float.h>
|
||||
#include "gregoimp.h" // ClockMath
|
||||
|
@ -63,6 +64,7 @@ static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = {
|
|||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
|
||||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY
|
||||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
|
||||
{ 0, 0, 11, 12}, // ORDINAL_MONTH
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -217,7 +219,8 @@ void HebrewCalendar::add(UCalendarDateFields field, int32_t amount, UErrorCode&
|
|||
return;
|
||||
}
|
||||
switch (field) {
|
||||
case UCAL_MONTH:
|
||||
case UCAL_MONTH:
|
||||
case UCAL_ORDINAL_MONTH:
|
||||
{
|
||||
// We can't just do a set(MONTH, get(MONTH) + amount). The
|
||||
// reason is ADAR_1. Suppose amount is +2 and we land in
|
||||
|
@ -315,6 +318,7 @@ void HebrewCalendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode&
|
|||
}
|
||||
switch (field) {
|
||||
case UCAL_MONTH:
|
||||
case UCAL_ORDINAL_MONTH:
|
||||
{
|
||||
int32_t month = get(UCAL_MONTH, status);
|
||||
int32_t year = get(UCAL_YEAR, status);
|
||||
|
@ -534,7 +538,8 @@ int32_t HebrewCalendar::handleGetYearLength(int32_t eyear) const {
|
|||
}
|
||||
|
||||
void HebrewCalendar::validateField(UCalendarDateFields field, UErrorCode &status) {
|
||||
if (field == UCAL_MONTH && !isLeapYear(handleGetExtendedYear()) && internalGet(UCAL_MONTH) == ADAR_1) {
|
||||
if ((field == UCAL_MONTH || field == UCAL_ORDINAL_MONTH)
|
||||
&& !isLeapYear(handleGetExtendedYear()) && internalGetMonth() == ADAR_1) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return;
|
||||
}
|
||||
|
@ -607,6 +612,11 @@ void HebrewCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status)
|
|||
internalSet(UCAL_ERA, 0);
|
||||
internalSet(UCAL_YEAR, year);
|
||||
internalSet(UCAL_EXTENDED_YEAR, year);
|
||||
int32_t ordinal_month = month;
|
||||
if (!isLeap && ordinal_month > ADAR_1) {
|
||||
ordinal_month--;
|
||||
}
|
||||
internalSet(UCAL_ORDINAL_MONTH, ordinal_month);
|
||||
internalSet(UCAL_MONTH, month);
|
||||
internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
|
||||
internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
|
||||
|
@ -728,6 +738,49 @@ int32_t HebrewCalendar::defaultCenturyStartYear() const {
|
|||
return gSystemDefaultCenturyStartYear;
|
||||
}
|
||||
|
||||
bool HebrewCalendar::inTemporalLeapYear(UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) return false;
|
||||
int32_t eyear = get(UCAL_EXTENDED_YEAR, status);
|
||||
if (U_FAILURE(status)) return false;
|
||||
return isLeapYear(eyear);
|
||||
}
|
||||
|
||||
static const char * const gTemporalMonthCodesForHebrew[] = {
|
||||
"M01", "M02", "M03", "M04", "M05", "M05L", "M06",
|
||||
"M07", "M08", "M09", "M10", "M11", "M12", nullptr
|
||||
};
|
||||
|
||||
const char* HebrewCalendar::getTemporalMonthCode(UErrorCode& status) const {
|
||||
int32_t month = get(UCAL_MONTH, status);
|
||||
if (U_FAILURE(status)) return nullptr;
|
||||
return gTemporalMonthCodesForHebrew[month];
|
||||
}
|
||||
|
||||
void HebrewCalendar::setTemporalMonthCode(const char* code, UErrorCode& status )
|
||||
{
|
||||
if (U_FAILURE(status)) return;
|
||||
int32_t len = static_cast<int32_t>(uprv_strlen(code));
|
||||
if (len == 3 || len == 4) {
|
||||
for (int m = 0; gTemporalMonthCodesForHebrew[m] != nullptr; m++) {
|
||||
if (uprv_strcmp(code, gTemporalMonthCodesForHebrew[m]) == 0) {
|
||||
set(UCAL_MONTH, m);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
}
|
||||
|
||||
int32_t HebrewCalendar::internalGetMonth() const {
|
||||
if (resolveFields(kMonthPrecedence) == UCAL_ORDINAL_MONTH) {
|
||||
int32_t ordinalMonth = internalGet(UCAL_ORDINAL_MONTH);
|
||||
HebrewCalendar *nonConstThis = (HebrewCalendar*)this; // cast away const
|
||||
|
||||
int32_t year = nonConstThis->handleGetExtendedYear();
|
||||
return ordinalMonth + ((isLeapYear(year) && (ordinalMonth > ADAR_1)) ? 1: 0);
|
||||
}
|
||||
return Calendar::internalGetMonth();
|
||||
}
|
||||
|
||||
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(HebrewCalendar)
|
||||
|
||||
|
|
|
@ -399,6 +399,51 @@ public:
|
|||
*/
|
||||
virtual int32_t defaultCenturyStartYear() const override;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Returns true if the date is in a leap year.
|
||||
*
|
||||
* @param status ICU Error Code
|
||||
* @return True if the date in the fields is in a Temporal proposal
|
||||
* defined leap year. False otherwise.
|
||||
*/
|
||||
virtual bool inTemporalLeapYear(UErrorCode& status) const override;
|
||||
|
||||
/**
|
||||
* Gets The Temporal monthCode value corresponding to the month for the date.
|
||||
* The value is a string identifier that starts with the literal grapheme
|
||||
* "M" followed by two graphemes representing the zero-padded month number
|
||||
* of the current month in a normal (non-leap) year and suffixed by an
|
||||
* optional literal grapheme "L" if this is a leap month in a lunisolar
|
||||
* calendar. For the Hebrew calendar, the values are "M01" .. "M12" for
|
||||
* non-leap year, and "M01" .. "M05", "M05L", "M06" .. "M12" for leap year.
|
||||
*
|
||||
* @param status ICU Error Code
|
||||
* @return One of 13 possible strings in {"M01".. "M05", "M05L",
|
||||
* "M06" .. "M12"}.
|
||||
* @draft ICU 73
|
||||
*/
|
||||
virtual const char* getTemporalMonthCode(UErrorCode& status) const override;
|
||||
|
||||
/**
|
||||
* Sets The Temporal monthCode which is a string identifier that starts
|
||||
* with the literal grapheme "M" followed by two graphemes representing
|
||||
* the zero-padded month number of the current month in a normal
|
||||
* (non-leap) year and suffixed by an optional literal grapheme "L" if this
|
||||
* is a leap month in a lunisolar calendar. For Hebrew calendar, the values
|
||||
* are "M01" .. "M12" for non-leap years, and "M01" .. "M05", "M05L", "M06"
|
||||
* .. "M12" for leap year.
|
||||
*
|
||||
* @param temporalMonth The value to be set for temporal monthCode.
|
||||
* @param status ICU Error Code
|
||||
*
|
||||
* @draft ICU 73
|
||||
*/
|
||||
virtual void setTemporalMonthCode(const char* code, UErrorCode& status ) override;
|
||||
|
||||
protected:
|
||||
virtual int32_t internalGetMonth() const override;
|
||||
|
||||
private: // Calendar-specific implementation
|
||||
/**
|
||||
* Finds the day # of the first day in the given Hebrew year.
|
||||
|
|
|
@ -80,6 +80,7 @@ static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = {
|
|||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
|
||||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY
|
||||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
|
||||
{ 0, 0, 11, 11}, // ORDINAL_MONTH
|
||||
};
|
||||
|
||||
static const int32_t INDIAN_ERA_START = 78;
|
||||
|
@ -293,6 +294,7 @@ void IndianCalendar::handleComputeFields(int32_t julianDay, UErrorCode& /* stat
|
|||
internalSet(UCAL_EXTENDED_YEAR, IndianYear);
|
||||
internalSet(UCAL_YEAR, IndianYear);
|
||||
internalSet(UCAL_MONTH, IndianMonth);
|
||||
internalSet(UCAL_ORDINAL_MONTH, IndianMonth);
|
||||
internalSet(UCAL_DAY_OF_MONTH, IndianDayOfMonth);
|
||||
internalSet(UCAL_DAY_OF_YEAR, yday + 1); // yday is 0-based
|
||||
}
|
||||
|
|
|
@ -259,6 +259,7 @@ static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = {
|
|||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
|
||||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY
|
||||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
|
||||
{ 0, 0, 11, 11}, // ORDINAL_MONTH
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -546,6 +547,7 @@ void IslamicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status)
|
|||
internalSet(UCAL_YEAR, year);
|
||||
internalSet(UCAL_EXTENDED_YEAR, year);
|
||||
internalSet(UCAL_MONTH, month);
|
||||
internalSet(UCAL_ORDINAL_MONTH, month);
|
||||
internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
|
||||
internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
|
||||
}
|
||||
|
@ -631,6 +633,14 @@ int32_t IslamicCalendar::defaultCenturyStartYear() const
|
|||
return gSystemDefaultCenturyStartYear;
|
||||
}
|
||||
|
||||
bool
|
||||
IslamicCalendar::inTemporalLeapYear(UErrorCode &status) const
|
||||
{
|
||||
int32_t days = getActualMaximum(UCAL_DAY_OF_YEAR, status);
|
||||
if (U_FAILURE(status)) return false;
|
||||
return days == 355;
|
||||
}
|
||||
|
||||
|
||||
U_CFUNC void U_CALLCONV
|
||||
IslamicCalendar::initializeSystemDefaultCentury()
|
||||
|
@ -757,6 +767,7 @@ void IslamicCivilCalendar::handleComputeFields(int32_t julianDay, UErrorCode &st
|
|||
internalSet(UCAL_YEAR, year);
|
||||
internalSet(UCAL_EXTENDED_YEAR, year);
|
||||
internalSet(UCAL_MONTH, month);
|
||||
internalSet(UCAL_ORDINAL_MONTH, month);
|
||||
internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
|
||||
internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
|
||||
}
|
||||
|
@ -932,6 +943,7 @@ void IslamicUmalquraCalendar::handleComputeFields(int32_t julianDay, UErrorCode
|
|||
internalSet(UCAL_YEAR, year);
|
||||
internalSet(UCAL_EXTENDED_YEAR, year);
|
||||
internalSet(UCAL_MONTH, month);
|
||||
internalSet(UCAL_ORDINAL_MONTH, month);
|
||||
internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
|
||||
internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
|
||||
}
|
||||
|
|
|
@ -350,6 +350,15 @@ class U_I18N_API IslamicCalendar : public Calendar {
|
|||
*/
|
||||
virtual void setRelatedYear(int32_t year) override;
|
||||
|
||||
/**
|
||||
* Returns true if the date is in a leap year.
|
||||
*
|
||||
* @param status ICU Error Code
|
||||
* @return True if the date in the fields is in a Temporal proposal
|
||||
* defined leap year. False otherwise.
|
||||
*/
|
||||
virtual bool inTemporalLeapYear(UErrorCode &status) const override;
|
||||
|
||||
private:
|
||||
IslamicCalendar() = delete; // default constructor not implemented
|
||||
|
||||
|
|
|
@ -219,7 +219,7 @@ void JapaneseCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status
|
|||
//Calendar::timeToFields(theTime, quick, status);
|
||||
GregorianCalendar::handleComputeFields(julianDay, status);
|
||||
int32_t year = internalGet(UCAL_EXTENDED_YEAR); // Gregorian year
|
||||
int32_t eraIdx = gJapaneseEraRules->getEraIndex(year, internalGet(UCAL_MONTH) + 1, internalGet(UCAL_DAY_OF_MONTH), status);
|
||||
int32_t eraIdx = gJapaneseEraRules->getEraIndex(year, internalGetMonth() + 1, internalGet(UCAL_DAY_OF_MONTH), status);
|
||||
|
||||
internalSet(UCAL_ERA, eraIdx);
|
||||
internalSet(UCAL_YEAR, year - gJapaneseEraRules->getStartYear(eraIdx, status) + 1);
|
||||
|
|
|
@ -58,6 +58,7 @@ static const int32_t kPersianCalendarLimits[UCAL_FIELD_COUNT][4] = {
|
|||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
|
||||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY
|
||||
{/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
|
||||
{ 0, 0, 11, 11}, // ORDINAL_MONTH
|
||||
};
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
@ -229,6 +230,7 @@ void PersianCalendar::handleComputeFields(int32_t julianDay, UErrorCode &/*statu
|
|||
internalSet(UCAL_YEAR, year);
|
||||
internalSet(UCAL_EXTENDED_YEAR, year);
|
||||
internalSet(UCAL_MONTH, month);
|
||||
internalSet(UCAL_ORDINAL_MONTH, month);
|
||||
internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
|
||||
internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
|
||||
}
|
||||
|
|
|
@ -1349,6 +1349,66 @@ public:
|
|||
*/
|
||||
virtual UBool isWeekend(void) const;
|
||||
|
||||
#ifndef U_HIDE_DRAFT_API
|
||||
/**
|
||||
* Returns true if the date is in a leap year. Recalculate the current time
|
||||
* field values if the time value has been changed by a call to * setTime().
|
||||
* This method is semantically const, but may alter the object in memory.
|
||||
* A "leap year" is a year that contains more days than other years (for
|
||||
* solar or lunar calendars) or more months than other years (for lunisolar
|
||||
* calendars like Hebrew or Chinese), as defined in the ECMAScript Temporal
|
||||
* proposal.
|
||||
*
|
||||
* @param status ICU Error Code
|
||||
* @return True if the date in the fields is in a Temporal proposal
|
||||
* defined leap year. False otherwise.
|
||||
* @draft ICU 73
|
||||
*/
|
||||
virtual bool inTemporalLeapYear(UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Gets The Temporal monthCode value corresponding to the month for the date.
|
||||
* The value is a string identifier that starts with the literal grapheme
|
||||
* "M" followed by two graphemes representing the zero-padded month number
|
||||
* of the current month in a normal (non-leap) year and suffixed by an
|
||||
* optional literal grapheme "L" if this is a leap month in a lunisolar
|
||||
* calendar. The 25 possible values are "M01" .. "M13" and "M01L" .. "M12L".
|
||||
* For the Hebrew calendar, the values are "M01" .. "M12" for non-leap year, and
|
||||
* "M01" .. "M05", "M05L", "M06" .. "M12" for leap year.
|
||||
* For the Chinese calendar, the values are "M01" .. "M12" for non-leap year and
|
||||
* in leap year with another monthCode in "M01L" .. "M12L".
|
||||
* For Coptic and Ethiopian calendar, the Temporal monthCode values for any
|
||||
* years are "M01" to "M13".
|
||||
*
|
||||
* @param status ICU Error Code
|
||||
* @return One of 25 possible strings in {"M01".."M13", "M01L".."M12L"}.
|
||||
* @draft ICU 73
|
||||
*/
|
||||
virtual const char* getTemporalMonthCode(UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Sets The Temporal monthCode which is a string identifier that starts
|
||||
* with the literal grapheme "M" followed by two graphemes representing
|
||||
* the zero-padded month number of the current month in a normal
|
||||
* (non-leap) year and suffixed by an optional literal grapheme "L" if this
|
||||
* is a leap month in a lunisolar calendar. The 25 possible values are
|
||||
* "M01" .. "M13" and "M01L" .. "M12L". For Hebrew calendar, the values are
|
||||
* "M01" .. "M12" for non-leap years, and "M01" .. "M05", "M05L", "M06"
|
||||
* .. "M12" for leap year.
|
||||
* For the Chinese calendar, the values are "M01" .. "M12" for non-leap year and
|
||||
* in leap year with another monthCode in "M01L" .. "M12L".
|
||||
* For Coptic and Ethiopian calendar, the Temporal monthCode values for any
|
||||
* years are "M01" to "M13".
|
||||
*
|
||||
* @param temporalMonth The value to be set for temporal monthCode.
|
||||
* @param status ICU Error Code
|
||||
*
|
||||
* @draft ICU 73
|
||||
*/
|
||||
virtual void setTemporalMonthCode(const char* temporalMonth, UErrorCode& status);
|
||||
|
||||
#endif /* U_HIDE_DRAFT_API */
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
|
@ -1489,6 +1549,31 @@ protected:
|
|||
* @internal
|
||||
*/
|
||||
inline int32_t internalGet(UCalendarDateFields field) const {return fFields[field];}
|
||||
|
||||
/**
|
||||
* Use this function instead of internalGet(UCAL_MONTH). The implementation
|
||||
* check the timestamp of UCAL_MONTH and UCAL_ORDINAL_MONTH and use the
|
||||
* one set later. The subclass should override it to conver the value of UCAL_ORDINAL_MONTH
|
||||
* to UCAL_MONTH correctly if UCAL_ORDINAL_MONTH has higher priority.
|
||||
*
|
||||
* @return The value for the UCAL_MONTH.
|
||||
* @internal
|
||||
*/
|
||||
virtual int32_t internalGetMonth() const;
|
||||
|
||||
/**
|
||||
* Use this function instead of internalGet(UCAL_MONTH, defaultValue). The implementation
|
||||
* check the timestamp of UCAL_MONTH and UCAL_ORDINAL_MONTH and use the
|
||||
* one set later. The subclass should override it to conver the value of UCAL_ORDINAL_MONTH
|
||||
* to UCAL_MONTH correctly if UCAL_ORDINAL_MONTH has higher priority.
|
||||
*
|
||||
* @param defaultValue a default value used if the UCAL_MONTH and
|
||||
* UCAL_ORDINAL are both unset.
|
||||
* @return The value for the UCAL_MONTH.
|
||||
* @internal
|
||||
*/
|
||||
virtual int32_t internalGetMonth(int32_t defaultValue) const;
|
||||
|
||||
#endif /* U_HIDE_INTERNAL_API */
|
||||
|
||||
#ifndef U_HIDE_DEPRECATED_API
|
||||
|
@ -1569,7 +1654,6 @@ protected:
|
|||
*/
|
||||
virtual int32_t getLimit(UCalendarDateFields field, ELimitType limitType) const;
|
||||
|
||||
|
||||
/**
|
||||
* Return the Julian day number of day before the first day of the
|
||||
* given month in the given extended year. Subclasses should override
|
||||
|
@ -1722,6 +1806,13 @@ protected:
|
|||
*/
|
||||
static const UFieldResolutionTable kDOWPrecedence[];
|
||||
|
||||
/**
|
||||
* Precedence table for Months
|
||||
* @see #resolveFields
|
||||
* @internal
|
||||
*/
|
||||
static const UFieldResolutionTable kMonthPrecedence[];
|
||||
|
||||
/**
|
||||
* Given a precedence table, return the newest field combination in
|
||||
* the table, or UCAL_FIELD_COUNT if none is found.
|
||||
|
@ -1749,7 +1840,7 @@ protected:
|
|||
* match, then UCAL_FIELD_COUNT is returned.
|
||||
* @internal
|
||||
*/
|
||||
UCalendarDateFields resolveFields(const UFieldResolutionTable *precedenceTable);
|
||||
UCalendarDateFields resolveFields(const UFieldResolutionTable *precedenceTable) const;
|
||||
#endif /* U_HIDE_INTERNAL_API */
|
||||
|
||||
|
||||
|
|
|
@ -442,6 +442,33 @@ enum UCalendarDateFields {
|
|||
*/
|
||||
UCAL_IS_LEAP_MONTH,
|
||||
|
||||
#ifndef U_HIDE_DRAFT_API
|
||||
/**
|
||||
* Field number indicating the month. This is a calendar-specific value.
|
||||
* Differ from UCAL_MONTH, this value is continuous and unique within a
|
||||
* year and range from 0 to 11 or 0 to 12 depending on how many months in a
|
||||
* year, the calendar system has leap month or not, and in leap year or not.
|
||||
* It is the ordinal position of that month in the corresponding year of
|
||||
* the calendar. For Chinese, Dangi, and Hebrew calendar, the range is
|
||||
* 0 to 11 in non-leap years and 0 to 12 in leap years. For Coptic and Ethiopian
|
||||
* calendar, the range is always 0 to 12. For other calendars supported by
|
||||
* ICU now, the range is 0 to 11. When the number of months in a year of the
|
||||
* identified calendar is variable, a different UCAL_ORDINAL_MONTH value can
|
||||
* be used for dates that are part of the same named month in different years.
|
||||
* For example, in the Hebrew calendar, "1 Nisan 5781" is associated with
|
||||
* UCAL_ORDINAL_MONTH value 6 while "1 Nisan 5782" is associated with
|
||||
* UCAL_ORDINAL_MONTH value 7 because 5782 is a leap year and Nisan follows
|
||||
* the insertion of Adar I. In Chinese calendar, "Year 4664 Month 6 Day 2"
|
||||
* is associated with UCAL_ORDINAL_MONTH value 5 while "Year 4665 Month 6 Day 2"
|
||||
* is associated with UCAL_ORDINAL_MONTH value 6 because 4665 is a leap year
|
||||
* and there is an extra "Leap Month 5" which associated with UCAL_ORDINAL_MONTH
|
||||
* value 5 before "Month 6" of year 4664.
|
||||
*
|
||||
* @draft ICU 73
|
||||
*/
|
||||
UCAL_ORDINAL_MONTH,
|
||||
#endif // U_HIDE_DRAFT_API
|
||||
|
||||
/* Do not conditionalize the following with #ifndef U_HIDE_DEPRECATED_API,
|
||||
* it is needed for layout of Calendar, DateFormat, and other objects */
|
||||
#ifndef U_FORCE_HIDE_DEPRECATED_API
|
||||
|
@ -449,7 +476,12 @@ enum UCalendarDateFields {
|
|||
* One more than the highest normal UCalendarDateFields value.
|
||||
* @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420.
|
||||
*/
|
||||
UCAL_FIELD_COUNT,
|
||||
#ifdef U_HIDE_DRAFT_API
|
||||
UCAL_FIELD_COUNT = UCAL_IS_LEAP_MONTH + 1,
|
||||
#else // U_HIDE_DRAFT_API (for UCAL_ORDINAL_MONTH)
|
||||
UCAL_FIELD_COUNT = UCAL_ORDINAL_MONTH + 1,
|
||||
#endif // U_HIDE_DRAFT_API (for UCAL_ORDINAL_MONTH)
|
||||
|
||||
#endif // U_FORCE_HIDE_DEPRECATED_API
|
||||
|
||||
/**
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -285,6 +285,53 @@ public: // package
|
|||
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);
|
||||
|
||||
void TestGregorianCalendarInTemporalLeapYear(void);
|
||||
void TestChineseCalendarInTemporalLeapYear(void);
|
||||
void TestDangiCalendarInTemporalLeapYear(void);
|
||||
void TestHebrewCalendarInTemporalLeapYear(void);
|
||||
void TestIslamicCalendarInTemporalLeapYear(void);
|
||||
void TestIslamicCivilCalendarInTemporalLeapYear(void);
|
||||
void TestIslamicUmalquraCalendarInTemporalLeapYear(void);
|
||||
void TestIslamicRGSACalendarInTemporalLeapYear(void);
|
||||
void TestIslamicTBLACalendarInTemporalLeapYear(void);
|
||||
void TestPersianCalendarInTemporalLeapYear(void);
|
||||
void TestIndianCalendarInTemporalLeapYear(void);
|
||||
void TestTaiwanCalendarInTemporalLeapYear(void);
|
||||
void TestJapaneseCalendarInTemporalLeapYear(void);
|
||||
void TestBuddhistCalendarInTemporalLeapYear(void);
|
||||
void TestCopticCalendarInTemporalLeapYear(void);
|
||||
void TestEthiopicCalendarInTemporalLeapYear(void);
|
||||
void TestEthiopicAmeteAlemCalendarInTemporalLeapYear(void);
|
||||
|
||||
void TestChineseCalendarGetTemporalMonthCode(void);
|
||||
void TestDangiCalendarGetTemporalMonthCode(void);
|
||||
void TestHebrewCalendarGetTemporalMonthCode(void);
|
||||
void TestCopticCalendarGetTemporalMonthCode(void);
|
||||
void TestEthiopicCalendarGetTemporalMonthCode(void);
|
||||
void TestEthiopicAmeteAlemCalendarGetTemporalMonthCode(void);
|
||||
|
||||
void TestGregorianCalendarSetTemporalMonthCode(void);
|
||||
void TestChineseCalendarSetTemporalMonthCode(void);
|
||||
void TestHebrewCalendarSetTemporalMonthCode(void);
|
||||
void TestCopticCalendarSetTemporalMonthCode(void);
|
||||
void TestEthiopicCalendarSetTemporalMonthCode(void);
|
||||
|
||||
void TestMostCalendarsOrdinalMonthSet(void);
|
||||
void TestChineseCalendarOrdinalMonthSet(void);
|
||||
void TestDangiCalendarOrdinalMonthSet(void);
|
||||
void TestHebrewCalendarOrdinalMonthSet(void);
|
||||
|
||||
void TestCalendarAddOrdinalMonth(void);
|
||||
void TestCalendarRollOrdinalMonth(void);
|
||||
void TestLimitsOrdinalMonth(void);
|
||||
void TestActualLimitsOrdinalMonth(void);
|
||||
|
||||
void RunChineseCalendarInTemporalLeapYearTest(Calendar* cal);
|
||||
void RunIslamicCalendarInTemporalLeapYearTest(Calendar* cal);
|
||||
void Run366DaysIsLeapYearCalendarInTemporalLeapYearTest(Calendar* cal);
|
||||
void RunChineseCalendarGetTemporalMonthCode(Calendar* cal);
|
||||
void RunCECalendarGetTemporalMonthCode(Calendar* cal);
|
||||
};
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
|
|
@ -1091,7 +1091,14 @@ void IntlCalendarTest::checkConsistency(const char* locale) {
|
|||
" Gregorian(e=" + g->get(UCAL_ERA, status) + " " +
|
||||
g->get(UCAL_YEAR, status) + "/" +
|
||||
(g->get(UCAL_MONTH, status) + 1) + "/" +
|
||||
g->get(UCAL_DATE, status) + ") ");
|
||||
g->get(UCAL_DATE, status) + ") \n" +
|
||||
" Calendar[" + base->getType() +
|
||||
"](e=" + base->get(UCAL_ERA, status) + " " +
|
||||
base->get(UCAL_YEAR, status) + "/" +
|
||||
(base->get(UCAL_MONTH, status) + 1) + "/" +
|
||||
base->get(UCAL_DATE, status) + ") ordinalMonth=" +
|
||||
base->get(UCAL_ORDINAL_MONTH, status));
|
||||
|
||||
status.errIfFailureAndReset();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -107,6 +107,9 @@ static const Field names_UCalendarDateFields[] =
|
|||
FIELD_NAME_STR( LEN_UCAL, UCAL_JULIAN_DAY ),
|
||||
FIELD_NAME_STR( LEN_UCAL, UCAL_MILLISECONDS_IN_DAY ),
|
||||
FIELD_NAME_STR( LEN_UCAL, UCAL_IS_LEAP_MONTH ),
|
||||
#ifndef U_HIDE_DRAFT_API
|
||||
FIELD_NAME_STR( LEN_UCAL, UCAL_ORDINAL_MONTH ),
|
||||
#endif // U_HIDE_DRAFT_API
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue