diff options
Diffstat (limited to 'intl/icu/source/i18n/japancal.cpp')
-rw-r--r-- | intl/icu/source/i18n/japancal.cpp | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/intl/icu/source/i18n/japancal.cpp b/intl/icu/source/i18n/japancal.cpp new file mode 100644 index 0000000000..fc18d6c0eb --- /dev/null +++ b/intl/icu/source/i18n/japancal.cpp @@ -0,0 +1,309 @@ +// © 2016 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html +/* +******************************************************************************* +* Copyright (C) 2003-2009,2012,2016 International Business Machines Corporation and +* others. All Rights Reserved. +******************************************************************************* +* +* File JAPANCAL.CPP +* +* Modification History: +* 05/16/2003 srl copied from buddhcal.cpp +* +*/ + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#if U_PLATFORM_HAS_WINUWP_API == 0 +#include <stdlib.h> // getenv() is not available in UWP env +#else +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +# define VC_EXTRALEAN +# define NOUSER +# define NOSERVICE +# define NOIME +# define NOMCX +#include <windows.h> +#endif +#include "cmemory.h" +#include "erarules.h" +#include "japancal.h" +#include "unicode/gregocal.h" +#include "umutex.h" +#include "uassert.h" +#include "ucln_in.h" +#include "cstring.h" + +static icu::EraRules * gJapaneseEraRules = nullptr; +static icu::UInitOnce gJapaneseEraRulesInitOnce {}; +static int32_t gCurrentEra = 0; + +U_CDECL_BEGIN +static UBool japanese_calendar_cleanup() { + if (gJapaneseEraRules) { + delete gJapaneseEraRules; + gJapaneseEraRules = nullptr; + } + gCurrentEra = 0; + gJapaneseEraRulesInitOnce.reset(); + return true; +} +U_CDECL_END + +U_NAMESPACE_BEGIN + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(JapaneseCalendar) + +static const int32_t kGregorianEpoch = 1970; // used as the default value of EXTENDED_YEAR +static const char* TENTATIVE_ERA_VAR_NAME = "ICU_ENABLE_TENTATIVE_ERA"; + + +// Export the following for use by test code. +UBool JapaneseCalendar::enableTentativeEra() { + // Although start date of next Japanese era is planned ahead, a name of + // new era might not be available. This implementation allows tester to + // check a new era without era names by settings below (in priority order). + // By default, such tentative era is disabled. + + // 1. Environment variable ICU_ENABLE_TENTATIVE_ERA=true or false + + UBool includeTentativeEra = false; + +#if U_PLATFORM_HAS_WINUWP_API == 1 + // UWP doesn't allow access to getenv(), but we can call GetEnvironmentVariableW to do the same thing. + char16_t varName[26] = {}; + u_charsToUChars(TENTATIVE_ERA_VAR_NAME, varName, static_cast<int32_t>(uprv_strlen(TENTATIVE_ERA_VAR_NAME))); + WCHAR varValue[5] = {}; + DWORD ret = GetEnvironmentVariableW(reinterpret_cast<WCHAR*>(varName), varValue, UPRV_LENGTHOF(varValue)); + if ((ret == 4) && (_wcsicmp(varValue, L"true") == 0)) { + includeTentativeEra = true; + } +#else + char *envVarVal = getenv(TENTATIVE_ERA_VAR_NAME); + if (envVarVal != nullptr && uprv_stricmp(envVarVal, "true") == 0) { + includeTentativeEra = true; + } +#endif + return includeTentativeEra; +} + + +// Initialize global Japanese era data +static void U_CALLCONV initializeEras(UErrorCode &status) { + gJapaneseEraRules = EraRules::createInstance("japanese", JapaneseCalendar::enableTentativeEra(), status); + if (U_FAILURE(status)) { + return; + } + gCurrentEra = gJapaneseEraRules->getCurrentEraIndex(); +} + +static void init(UErrorCode &status) { + umtx_initOnce(gJapaneseEraRulesInitOnce, &initializeEras, status); + ucln_i18n_registerCleanup(UCLN_I18N_JAPANESE_CALENDAR, japanese_calendar_cleanup); +} + +/* Some platforms don't like to export constants, like old Palm OS and some z/OS configurations. */ +uint32_t JapaneseCalendar::getCurrentEra() { + return gCurrentEra; +} + +JapaneseCalendar::JapaneseCalendar(const Locale& aLocale, UErrorCode& success) +: GregorianCalendar(aLocale, success) +{ + init(success); + setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly. +} + +JapaneseCalendar::~JapaneseCalendar() +{ +} + +JapaneseCalendar::JapaneseCalendar(const JapaneseCalendar& source) +: GregorianCalendar(source) +{ + UErrorCode status = U_ZERO_ERROR; + init(status); + U_ASSERT(U_SUCCESS(status)); +} + +JapaneseCalendar& JapaneseCalendar::operator= ( const JapaneseCalendar& right) +{ + GregorianCalendar::operator=(right); + return *this; +} + +JapaneseCalendar* JapaneseCalendar::clone() const +{ + return new JapaneseCalendar(*this); +} + +const char *JapaneseCalendar::getType() const +{ + return "japanese"; +} + +int32_t JapaneseCalendar::getDefaultMonthInYear(int32_t eyear) +{ + int32_t era = internalGetEra(); + // TODO do we assume we can trust 'era'? What if it is denormalized? + + int32_t month = 0; + + // Find out if we are at the edge of an era + int32_t eraStart[3] = { 0,0,0 }; + UErrorCode status = U_ZERO_ERROR; + gJapaneseEraRules->getStartDate(era, eraStart, status); + U_ASSERT(U_SUCCESS(status)); + if(eyear == eraStart[0]) { + // Yes, we're in the first year of this era. + return eraStart[1] // month + -1; // return 0-based month + } + + return month; +} + +int32_t JapaneseCalendar::getDefaultDayInMonth(int32_t eyear, int32_t month) +{ + int32_t era = internalGetEra(); + int32_t day = 1; + + int32_t eraStart[3] = { 0,0,0 }; + UErrorCode status = U_ZERO_ERROR; + gJapaneseEraRules->getStartDate(era, eraStart, status); + U_ASSERT(U_SUCCESS(status)); + if(eyear == eraStart[0]) { + if(month == eraStart[1] - 1) { + return eraStart[2]; + } + } + + return day; +} + + +int32_t JapaneseCalendar::internalGetEra() const +{ + return internalGet(UCAL_ERA, gCurrentEra); +} + +int32_t JapaneseCalendar::handleGetExtendedYear() +{ + // EXTENDED_YEAR in JapaneseCalendar is a Gregorian year + // The default value of EXTENDED_YEAR is 1970 (Showa 45) + int32_t year; + + if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR && + newerField(UCAL_EXTENDED_YEAR, UCAL_ERA) == UCAL_EXTENDED_YEAR) { + year = internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch); + } else { + UErrorCode status = U_ZERO_ERROR; + int32_t eraStartYear = gJapaneseEraRules->getStartYear(internalGet(UCAL_ERA, gCurrentEra), status); + U_ASSERT(U_SUCCESS(status)); + + // extended year is a gregorian year, where 1 = 1AD, 0 = 1BC, -1 = 2BC, etc + year = internalGet(UCAL_YEAR, 1) // pin to minimum of year 1 (first year) + + eraStartYear // add gregorian starting year + - 1; // Subtract one because year starts at 1 + } + return year; +} + + +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, internalGetMonth() + 1, internalGet(UCAL_DAY_OF_MONTH), status); + + internalSet(UCAL_ERA, eraIdx); + internalSet(UCAL_YEAR, year - gJapaneseEraRules->getStartYear(eraIdx, status) + 1); +} + +/* +Disable pivoting +*/ +UBool JapaneseCalendar::haveDefaultCentury() const +{ + return false; +} + +UDate JapaneseCalendar::defaultCenturyStart() const +{ + return 0;// WRONG +} + +int32_t JapaneseCalendar::defaultCenturyStartYear() const +{ + return 0; +} + +int32_t JapaneseCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const +{ + switch(field) { + case UCAL_ERA: + if (limitType == UCAL_LIMIT_MINIMUM || limitType == UCAL_LIMIT_GREATEST_MINIMUM) { + return 0; + } + return gJapaneseEraRules->getNumberOfEras() - 1; // max known era, not gCurrentEra + case UCAL_YEAR: + { + switch (limitType) { + case UCAL_LIMIT_MINIMUM: + case UCAL_LIMIT_GREATEST_MINIMUM: + return 1; + case UCAL_LIMIT_LEAST_MAXIMUM: + return 1; + case UCAL_LIMIT_COUNT: //added to avoid warning + case UCAL_LIMIT_MAXIMUM: + { + UErrorCode status = U_ZERO_ERROR; + int32_t eraStartYear = gJapaneseEraRules->getStartYear(gCurrentEra, status); + U_ASSERT(U_SUCCESS(status)); + return GregorianCalendar::handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM) - eraStartYear; + } + default: + return 1; // Error condition, invalid limitType + } + } + default: + return GregorianCalendar::handleGetLimit(field,limitType); + } +} + +int32_t JapaneseCalendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const { + if (field == UCAL_YEAR) { + int32_t era = get(UCAL_ERA, status); + if (U_FAILURE(status)) { + return 0; // error case... any value + } + if (era == gJapaneseEraRules->getNumberOfEras() - 1) { // max known era, not gCurrentEra + // TODO: Investigate what value should be used here - revisit after 4.0. + return handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM); + } else { + int32_t nextEraStart[3] = { 0,0,0 }; + gJapaneseEraRules->getStartDate(era + 1, nextEraStart, status); + int32_t nextEraYear = nextEraStart[0]; + int32_t nextEraMonth = nextEraStart[1]; // 1-base + int32_t nextEraDate = nextEraStart[2]; + + int32_t eraStartYear = gJapaneseEraRules->getStartYear(era, status); + int32_t maxYear = nextEraYear - eraStartYear + 1; // 1-base + if (nextEraMonth == 1 && nextEraDate == 1) { + // Subtract 1, because the next era starts at Jan 1 + maxYear--; + } + return maxYear; + } + } + return GregorianCalendar::getActualMaximum(field, status); +} + +U_NAMESPACE_END + +#endif |