| 1 | // © 2016 and later: Unicode, Inc. and others. | 
| 2 | // License & terms of use: http://www.unicode.org/copyright.html | 
| 3 | /* | 
| 4 | ******************************************************************************* | 
| 5 | * Copyright (C) 2003-2009,2012,2016 International Business Machines Corporation and | 
| 6 | * others. All Rights Reserved. | 
| 7 | ******************************************************************************* | 
| 8 | * | 
| 9 | * File JAPANCAL.CPP | 
| 10 | * | 
| 11 | * Modification History: | 
| 12 | *  05/16/2003    srl     copied from buddhcal.cpp | 
| 13 | * | 
| 14 | */ | 
| 15 |  | 
| 16 | #include "unicode/utypes.h" | 
| 17 |  | 
| 18 | #if !UCONFIG_NO_FORMATTING | 
| 19 | #if U_PLATFORM_HAS_WINUWP_API == 0 | 
| 20 | #include <stdlib.h> // getenv() is not available in UWP env | 
| 21 | #else | 
| 22 | #ifndef WIN32_LEAN_AND_MEAN | 
| 23 | #   define WIN32_LEAN_AND_MEAN | 
| 24 | #endif | 
| 25 | #   define VC_EXTRALEAN | 
| 26 | #   define NOUSER | 
| 27 | #   define NOSERVICE | 
| 28 | #   define NOIME | 
| 29 | #   define NOMCX | 
| 30 | #include <windows.h> | 
| 31 | #endif | 
| 32 | #include "cmemory.h" | 
| 33 | #include "erarules.h" | 
| 34 | #include "japancal.h" | 
| 35 | #include "unicode/gregocal.h" | 
| 36 | #include "umutex.h" | 
| 37 | #include "uassert.h" | 
| 38 | #include "ucln_in.h" | 
| 39 | #include "cstring.h" | 
| 40 |  | 
| 41 | static icu::EraRules * gJapaneseEraRules = nullptr; | 
| 42 | static icu::UInitOnce gJapaneseEraRulesInitOnce = U_INITONCE_INITIALIZER; | 
| 43 | static int32_t gCurrentEra = 0; | 
| 44 |  | 
| 45 | U_CDECL_BEGIN | 
| 46 | static UBool japanese_calendar_cleanup(void) { | 
| 47 |     if (gJapaneseEraRules) { | 
| 48 |         delete gJapaneseEraRules; | 
| 49 |         gJapaneseEraRules = nullptr; | 
| 50 |     } | 
| 51 |     gCurrentEra = 0; | 
| 52 |     gJapaneseEraRulesInitOnce.reset(); | 
| 53 |     return TRUE; | 
| 54 | } | 
| 55 | U_CDECL_END | 
| 56 |  | 
| 57 | U_NAMESPACE_BEGIN | 
| 58 |  | 
| 59 | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(JapaneseCalendar) | 
| 60 |  | 
| 61 | static const int32_t kGregorianEpoch = 1970;    // used as the default value of EXTENDED_YEAR | 
| 62 | static const char* TENTATIVE_ERA_VAR_NAME = "ICU_ENABLE_TENTATIVE_ERA" ; | 
| 63 |  | 
| 64 |  | 
| 65 | // Export the following for use by test code. | 
| 66 | UBool JapaneseCalendar::enableTentativeEra() { | 
| 67 |     // Although start date of next Japanese era is planned ahead, a name of | 
| 68 |     // new era might not be available. This implementation allows tester to | 
| 69 |     // check a new era without era names by settings below (in priority order). | 
| 70 |     // By default, such tentative era is disabled. | 
| 71 |  | 
| 72 |     // 1. Environment variable ICU_ENABLE_TENTATIVE_ERA=true or false | 
| 73 |  | 
| 74 |     UBool includeTentativeEra = FALSE; | 
| 75 |  | 
| 76 | #if U_PLATFORM_HAS_WINUWP_API == 1 | 
| 77 |     // UWP doesn't allow access to getenv(), but we can call GetEnvironmentVariableW to do the same thing. | 
| 78 |     UChar varName[26] = {}; | 
| 79 |     u_charsToUChars(TENTATIVE_ERA_VAR_NAME, varName, static_cast<int32_t>(uprv_strlen(TENTATIVE_ERA_VAR_NAME))); | 
| 80 |     WCHAR varValue[5] = {}; | 
| 81 |     DWORD ret = GetEnvironmentVariableW(reinterpret_cast<WCHAR*>(varName), varValue, UPRV_LENGTHOF(varValue)); | 
| 82 |     if ((ret == 4) && (_wcsicmp(varValue, L"true" ) == 0)) { | 
| 83 |         includeTentativeEra = TRUE; | 
| 84 |     } | 
| 85 | #else | 
| 86 |     char *envVarVal = getenv(TENTATIVE_ERA_VAR_NAME); | 
| 87 |     if (envVarVal != NULL && uprv_stricmp(envVarVal, "true" ) == 0) { | 
| 88 |         includeTentativeEra = TRUE; | 
| 89 |     } | 
| 90 | #endif | 
| 91 |     return includeTentativeEra; | 
| 92 | } | 
| 93 |  | 
| 94 |  | 
| 95 | // Initialize global Japanese era data | 
| 96 | static void U_CALLCONV initializeEras(UErrorCode &status) { | 
| 97 |     gJapaneseEraRules = EraRules::createInstance("japanese" , JapaneseCalendar::enableTentativeEra(), status); | 
| 98 |     if (U_FAILURE(status)) { | 
| 99 |         return; | 
| 100 |     } | 
| 101 |     gCurrentEra = gJapaneseEraRules->getCurrentEraIndex(); | 
| 102 | } | 
| 103 |  | 
| 104 | static void init(UErrorCode &status) { | 
| 105 |     umtx_initOnce(gJapaneseEraRulesInitOnce, &initializeEras, status); | 
| 106 |     ucln_i18n_registerCleanup(UCLN_I18N_JAPANESE_CALENDAR, japanese_calendar_cleanup); | 
| 107 | } | 
| 108 |  | 
| 109 | /* Some platforms don't like to export constants, like old Palm OS and some z/OS configurations. */ | 
| 110 | uint32_t JapaneseCalendar::getCurrentEra() { | 
| 111 |     return gCurrentEra; | 
| 112 | } | 
| 113 |  | 
| 114 | JapaneseCalendar::JapaneseCalendar(const Locale& aLocale, UErrorCode& success) | 
| 115 | :   GregorianCalendar(aLocale, success) | 
| 116 | { | 
| 117 |     init(success); | 
| 118 |     setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly. | 
| 119 | } | 
| 120 |  | 
| 121 | JapaneseCalendar::~JapaneseCalendar() | 
| 122 | { | 
| 123 | } | 
| 124 |  | 
| 125 | JapaneseCalendar::JapaneseCalendar(const JapaneseCalendar& source) | 
| 126 | : GregorianCalendar(source) | 
| 127 | { | 
| 128 |     UErrorCode status = U_ZERO_ERROR; | 
| 129 |     init(status); | 
| 130 |     U_ASSERT(U_SUCCESS(status)); | 
| 131 | } | 
| 132 |  | 
| 133 | JapaneseCalendar& JapaneseCalendar::operator= ( const JapaneseCalendar& right) | 
| 134 | { | 
| 135 |     GregorianCalendar::operator=(right); | 
| 136 |     return *this; | 
| 137 | } | 
| 138 |  | 
| 139 | JapaneseCalendar* JapaneseCalendar::clone() const | 
| 140 | { | 
| 141 |     return new JapaneseCalendar(*this); | 
| 142 | } | 
| 143 |  | 
| 144 | const char *JapaneseCalendar::getType() const | 
| 145 | { | 
| 146 |     return "japanese" ; | 
| 147 | } | 
| 148 |  | 
| 149 | int32_t JapaneseCalendar::getDefaultMonthInYear(int32_t eyear)  | 
| 150 | { | 
| 151 |     int32_t era = internalGetEra(); | 
| 152 |     // TODO do we assume we can trust 'era'?  What if it is denormalized? | 
| 153 |  | 
| 154 |     int32_t month = 0; | 
| 155 |  | 
| 156 |     // Find out if we are at the edge of an era | 
| 157 |     int32_t eraStart[3] = { 0,0,0 }; | 
| 158 |     UErrorCode status = U_ZERO_ERROR; | 
| 159 |     gJapaneseEraRules->getStartDate(era, eraStart, status); | 
| 160 |     U_ASSERT(U_SUCCESS(status)); | 
| 161 |     if(eyear == eraStart[0]) { | 
| 162 |         // Yes, we're in the first year of this era. | 
| 163 |         return eraStart[1]  // month | 
| 164 |                 -1;         // return 0-based month | 
| 165 |     } | 
| 166 |  | 
| 167 |     return month; | 
| 168 | } | 
| 169 |  | 
| 170 | int32_t JapaneseCalendar::getDefaultDayInMonth(int32_t eyear, int32_t month)  | 
| 171 | { | 
| 172 |     int32_t era = internalGetEra(); | 
| 173 |     int32_t day = 1; | 
| 174 |  | 
| 175 |     int32_t eraStart[3] = { 0,0,0 }; | 
| 176 |     UErrorCode status = U_ZERO_ERROR; | 
| 177 |     gJapaneseEraRules->getStartDate(era, eraStart, status); | 
| 178 |     U_ASSERT(U_SUCCESS(status)); | 
| 179 |     if(eyear == eraStart[0]) { | 
| 180 |         if(month == eraStart[1] - 1) { | 
| 181 |             return eraStart[2]; | 
| 182 |         } | 
| 183 |     } | 
| 184 |  | 
| 185 |     return day; | 
| 186 | } | 
| 187 |  | 
| 188 |  | 
| 189 | int32_t JapaneseCalendar::internalGetEra() const | 
| 190 | { | 
| 191 |     return internalGet(UCAL_ERA, gCurrentEra); | 
| 192 | } | 
| 193 |  | 
| 194 | int32_t JapaneseCalendar::handleGetExtendedYear() | 
| 195 | { | 
| 196 |     // EXTENDED_YEAR in JapaneseCalendar is a Gregorian year | 
| 197 |     // The default value of EXTENDED_YEAR is 1970 (Showa 45) | 
| 198 |     int32_t year; | 
| 199 |  | 
| 200 |     if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR && | 
| 201 |         newerField(UCAL_EXTENDED_YEAR, UCAL_ERA) == UCAL_EXTENDED_YEAR) { | 
| 202 |         year = internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch); | 
| 203 |     } else { | 
| 204 |         UErrorCode status = U_ZERO_ERROR; | 
| 205 |         int32_t eraStartYear = gJapaneseEraRules->getStartYear(internalGet(UCAL_ERA, gCurrentEra), status); | 
| 206 |         U_ASSERT(U_SUCCESS(status)); | 
| 207 |  | 
| 208 |         // extended year is a gregorian year, where 1 = 1AD,  0 = 1BC, -1 = 2BC, etc | 
| 209 |         year = internalGet(UCAL_YEAR, 1)    // pin to minimum of year 1 (first year) | 
| 210 |             + eraStartYear                  // add gregorian starting year | 
| 211 |             - 1;                            // Subtract one because year starts at 1 | 
| 212 |     } | 
| 213 |     return year; | 
| 214 | } | 
| 215 |  | 
| 216 |  | 
| 217 | void JapaneseCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status) | 
| 218 | { | 
| 219 |     //Calendar::timeToFields(theTime, quick, status); | 
| 220 |     GregorianCalendar::handleComputeFields(julianDay, status); | 
| 221 |     int32_t year = internalGet(UCAL_EXTENDED_YEAR); // Gregorian year | 
| 222 |     int32_t eraIdx = gJapaneseEraRules->getEraIndex(year, internalGet(UCAL_MONTH) + 1, internalGet(UCAL_DAY_OF_MONTH), status); | 
| 223 |  | 
| 224 |     internalSet(UCAL_ERA, eraIdx); | 
| 225 |     internalSet(UCAL_YEAR, year - gJapaneseEraRules->getStartYear(eraIdx, status) + 1); | 
| 226 | } | 
| 227 |  | 
| 228 | /* | 
| 229 | Disable pivoting  | 
| 230 | */ | 
| 231 | UBool JapaneseCalendar::haveDefaultCentury() const | 
| 232 | { | 
| 233 |     return FALSE; | 
| 234 | } | 
| 235 |  | 
| 236 | UDate JapaneseCalendar::defaultCenturyStart() const | 
| 237 | { | 
| 238 |     return 0;// WRONG | 
| 239 | } | 
| 240 |  | 
| 241 | int32_t JapaneseCalendar::defaultCenturyStartYear() const | 
| 242 | { | 
| 243 |     return 0; | 
| 244 | } | 
| 245 |  | 
| 246 | int32_t JapaneseCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const | 
| 247 | { | 
| 248 |     switch(field) { | 
| 249 |     case UCAL_ERA: | 
| 250 |         if (limitType == UCAL_LIMIT_MINIMUM || limitType == UCAL_LIMIT_GREATEST_MINIMUM) { | 
| 251 |             return 0; | 
| 252 |         } | 
| 253 |         return gJapaneseEraRules->getNumberOfEras() - 1; // max known era, not gCurrentEra | 
| 254 |     case UCAL_YEAR: | 
| 255 |         { | 
| 256 |             switch (limitType) { | 
| 257 |             case UCAL_LIMIT_MINIMUM: | 
| 258 |             case UCAL_LIMIT_GREATEST_MINIMUM: | 
| 259 |                 return 1; | 
| 260 |             case UCAL_LIMIT_LEAST_MAXIMUM: | 
| 261 |                 return 1; | 
| 262 |             case  UCAL_LIMIT_COUNT: //added to avoid warning | 
| 263 |             case UCAL_LIMIT_MAXIMUM: | 
| 264 |             { | 
| 265 |                 UErrorCode status = U_ZERO_ERROR; | 
| 266 |                 int32_t eraStartYear = gJapaneseEraRules->getStartYear(gCurrentEra, status); | 
| 267 |                 U_ASSERT(U_SUCCESS(status)); | 
| 268 |                 return GregorianCalendar::handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM) - eraStartYear; | 
| 269 |             } | 
| 270 |             default: | 
| 271 |                 return 1;    // Error condition, invalid limitType | 
| 272 |             } | 
| 273 |         } | 
| 274 |     default: | 
| 275 |         return GregorianCalendar::handleGetLimit(field,limitType); | 
| 276 |     } | 
| 277 | } | 
| 278 |  | 
| 279 | int32_t JapaneseCalendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const { | 
| 280 |     if (field == UCAL_YEAR) { | 
| 281 |         int32_t era = get(UCAL_ERA, status); | 
| 282 |         if (U_FAILURE(status)) { | 
| 283 |             return 0; // error case... any value | 
| 284 |         } | 
| 285 |         if (era == gJapaneseEraRules->getNumberOfEras() - 1) { // max known era, not gCurrentEra | 
| 286 |             // TODO: Investigate what value should be used here - revisit after 4.0. | 
| 287 |             return handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM); | 
| 288 |         } else { | 
| 289 |             int32_t nextEraStart[3] = { 0,0,0 }; | 
| 290 |             gJapaneseEraRules->getStartDate(era + 1, nextEraStart, status); | 
| 291 |             int32_t nextEraYear = nextEraStart[0]; | 
| 292 |             int32_t nextEraMonth = nextEraStart[1]; // 1-base | 
| 293 |             int32_t nextEraDate = nextEraStart[2]; | 
| 294 |  | 
| 295 |             int32_t eraStartYear = gJapaneseEraRules->getStartYear(era, status); | 
| 296 |             int32_t maxYear = nextEraYear - eraStartYear + 1;   // 1-base | 
| 297 |             if (nextEraMonth == 1 && nextEraDate == 1) { | 
| 298 |                 // Subtract 1, because the next era starts at Jan 1 | 
| 299 |                 maxYear--; | 
| 300 |             } | 
| 301 |             return maxYear; | 
| 302 |         } | 
| 303 |     } | 
| 304 |     return GregorianCalendar::getActualMaximum(field, status); | 
| 305 | } | 
| 306 |  | 
| 307 | U_NAMESPACE_END | 
| 308 |  | 
| 309 | #endif | 
| 310 |  |