japancal.cpp (9704B)
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 {}; 43 static int32_t gCurrentEra = 0; 44 45 U_CDECL_BEGIN 46 static UBool japanese_calendar_cleanup() { 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 char16_t 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 != nullptr && 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->getCurrentEraCode(); 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 } 119 120 JapaneseCalendar::~JapaneseCalendar() 121 { 122 } 123 124 JapaneseCalendar::JapaneseCalendar(const JapaneseCalendar& source) 125 : GregorianCalendar(source) 126 { 127 UErrorCode status = U_ZERO_ERROR; 128 init(status); 129 U_ASSERT(U_SUCCESS(status)); 130 } 131 132 JapaneseCalendar* JapaneseCalendar::clone() const 133 { 134 return new JapaneseCalendar(*this); 135 } 136 137 const char *JapaneseCalendar::getType() const 138 { 139 return "japanese"; 140 } 141 142 int32_t JapaneseCalendar::getDefaultMonthInYear(int32_t eyear, UErrorCode& status) 143 { 144 if (U_FAILURE(status)) { 145 return 0; 146 } 147 int32_t era = internalGetEra(); 148 // TODO do we assume we can trust 'era'? What if it is denormalized? 149 150 int32_t month = 0; 151 152 // Find out if we are at the edge of an era 153 int32_t eraStart[3] = { 0,0,0 }; 154 gJapaneseEraRules->getStartDate(era, eraStart, status); 155 if (U_FAILURE(status)) { 156 return 0; 157 } 158 if(eyear == eraStart[0]) { 159 // Yes, we're in the first year of this era. 160 return eraStart[1] // month 161 -1; // return 0-based month 162 } 163 164 return month; 165 } 166 167 int32_t JapaneseCalendar::getDefaultDayInMonth(int32_t eyear, int32_t month, UErrorCode& status) 168 { 169 if (U_FAILURE(status)) { 170 return 0; 171 } 172 int32_t era = internalGetEra(); 173 int32_t day = 1; 174 175 int32_t eraStart[3] = { 0,0,0 }; 176 gJapaneseEraRules->getStartDate(era, eraStart, status); 177 if (U_FAILURE(status)) { 178 return 0; 179 } 180 if (eyear == eraStart[0] && (month == eraStart[1] - 1)) { 181 return eraStart[2]; 182 } 183 return day; 184 } 185 186 187 int32_t JapaneseCalendar::internalGetEra() const 188 { 189 return internalGet(UCAL_ERA, gCurrentEra); 190 } 191 192 int32_t JapaneseCalendar::handleGetExtendedYear(UErrorCode& status) 193 { 194 if (U_FAILURE(status)) { 195 return 0; 196 } 197 // EXTENDED_YEAR in JapaneseCalendar is a Gregorian year 198 // The default value of EXTENDED_YEAR is 1970 (Showa 45) 199 200 if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR && 201 newerField(UCAL_EXTENDED_YEAR, UCAL_ERA) == UCAL_EXTENDED_YEAR) { 202 return internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch); 203 } 204 int32_t eraStartYear = gJapaneseEraRules->getStartYear(internalGet(UCAL_ERA, gCurrentEra), status); 205 if (U_FAILURE(status)) { 206 return 0; 207 } 208 209 // extended year is a gregorian year, where 1 = 1AD, 0 = 1BC, -1 = 2BC, etc 210 int32_t year = internalGet(UCAL_YEAR, 1); // pin to minimum of year 1 (first year) 211 // add gregorian starting year, subtract one because year starts at 1 212 if (uprv_add32_overflow(year, eraStartYear - 1, &year)) { 213 status = U_ILLEGAL_ARGUMENT_ERROR; 214 return 0; 215 } 216 return year; 217 } 218 219 220 void JapaneseCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status) 221 { 222 //Calendar::timeToFields(theTime, quick, status); 223 GregorianCalendar::handleComputeFields(julianDay, status); 224 int32_t year = internalGet(UCAL_EXTENDED_YEAR); // Gregorian year 225 int32_t eraCode = gJapaneseEraRules->getEraCode(year, internalGetMonth(status) + 1, internalGet(UCAL_DAY_OF_MONTH), status); 226 227 int32_t startYear = gJapaneseEraRules->getStartYear(eraCode, status) - 1; 228 if (U_FAILURE(status)) { 229 return; 230 } 231 if (uprv_add32_overflow(year, -startYear, &year)) { 232 status = U_ILLEGAL_ARGUMENT_ERROR; 233 return; 234 } 235 internalSet(UCAL_ERA, eraCode); 236 internalSet(UCAL_YEAR, year); 237 } 238 239 /* 240 Disable pivoting 241 */ 242 UBool JapaneseCalendar::haveDefaultCentury() const 243 { 244 return false; 245 } 246 247 UDate JapaneseCalendar::defaultCenturyStart() const 248 { 249 return 0;// WRONG 250 } 251 252 int32_t JapaneseCalendar::defaultCenturyStartYear() const 253 { 254 return 0; 255 } 256 257 int32_t JapaneseCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const 258 { 259 switch(field) { 260 case UCAL_ERA: 261 if (limitType == UCAL_LIMIT_MINIMUM || limitType == UCAL_LIMIT_GREATEST_MINIMUM) { 262 return 0; 263 } 264 return gJapaneseEraRules->getMaxEraCode(); // max known era, not gCurrentEra 265 case UCAL_YEAR: 266 { 267 switch (limitType) { 268 case UCAL_LIMIT_MINIMUM: 269 case UCAL_LIMIT_GREATEST_MINIMUM: 270 return 1; 271 case UCAL_LIMIT_LEAST_MAXIMUM: 272 return 1; 273 case UCAL_LIMIT_COUNT: //added to avoid warning 274 case UCAL_LIMIT_MAXIMUM: 275 { 276 UErrorCode status = U_ZERO_ERROR; 277 int32_t eraStartYear = gJapaneseEraRules->getStartYear(gCurrentEra, status); 278 U_ASSERT(U_SUCCESS(status)); 279 return GregorianCalendar::handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM) - eraStartYear; 280 } 281 default: 282 return 1; // Error condition, invalid limitType 283 } 284 } 285 default: 286 return GregorianCalendar::handleGetLimit(field,limitType); 287 } 288 } 289 290 int32_t JapaneseCalendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const { 291 if (field != UCAL_YEAR) { 292 return GregorianCalendar::getActualMaximum(field, status); 293 } 294 int32_t era = get(UCAL_ERA, status); 295 if (U_FAILURE(status)) { 296 return 0; // error case... any value 297 } 298 if (era == gJapaneseEraRules->getMaxEraCode()) { // max known era, not gCurrentEra 299 // TODO: Investigate what value should be used here - revisit after 4.0. 300 return handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM); 301 } 302 int32_t nextEraStart[3] = { 0,0,0 }; 303 gJapaneseEraRules->getStartDate(era + 1, nextEraStart, status); 304 int32_t nextEraYear = nextEraStart[0]; 305 int32_t nextEraMonth = nextEraStart[1]; // 1-base 306 int32_t nextEraDate = nextEraStart[2]; 307 308 int32_t eraStartYear = gJapaneseEraRules->getStartYear(era, status); 309 int32_t maxYear = nextEraYear - eraStartYear + 1; // 1-base 310 if (nextEraMonth == 1 && nextEraDate == 1) { 311 // Subtract 1, because the next era starts at Jan 1 312 maxYear--; 313 } 314 return maxYear; 315 } 316 317 U_NAMESPACE_END 318 319 #endif