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 // Initialize global Japanese era data 65 static void U_CALLCONV initializeEras(UErrorCode &status) { 66 // Although start date of next Japanese era is planned ahead, a name of 67 // new era might not be available. This implementation allows tester to 68 // check a new era without era names by settings below (in priority order). 69 // By default, such tentative era is disabled. 70 71 // 1. Environment variable ICU_ENABLE_TENTATIVE_ERA=true or false 72 73 UBool includeTentativeEra = FALSE; 74 75 #if U_PLATFORM_HAS_WINUWP_API == 1 76 // UWP doesn't allow access to getenv(), but we can call GetEnvironmentVariableW to do the same thing. 77 UChar varName[26] = {}; 78 u_charsToUChars(TENTATIVE_ERA_VAR_NAME, varName, static_cast<int32_t>(uprv_strlen(TENTATIVE_ERA_VAR_NAME))); 79 WCHAR varValue[5] = {}; 80 DWORD ret = GetEnvironmentVariableW(reinterpret_cast<WCHAR*>(varName), varValue, UPRV_LENGTHOF(varValue)); 81 if ((ret == 4) && (_wcsicmp(varValue, L"true") == 0)) { 82 includeTentativeEra = TRUE; 83 } 84 #else 85 char *envVarVal = getenv(TENTATIVE_ERA_VAR_NAME); 86 if (envVarVal != NULL && uprv_stricmp(envVarVal, "true") == 0) { 87 includeTentativeEra = TRUE; 88 } 89 #endif 90 gJapaneseEraRules = EraRules::createInstance("japanese", includeTentativeEra, status); 91 if (U_FAILURE(status)) { 92 return; 93 } 94 gCurrentEra = gJapaneseEraRules->getCurrentEraIndex(); 95 } 96 97 static void init(UErrorCode &status) { 98 umtx_initOnce(gJapaneseEraRulesInitOnce, &initializeEras, status); 99 ucln_i18n_registerCleanup(UCLN_I18N_JAPANESE_CALENDAR, japanese_calendar_cleanup); 100 } 101 102 /* Some platforms don't like to export constants, like old Palm OS and some z/OS configurations. */ 103 uint32_t JapaneseCalendar::getCurrentEra() { 104 return gCurrentEra; 105 } 106 107 JapaneseCalendar::JapaneseCalendar(const Locale& aLocale, UErrorCode& success) 108 : GregorianCalendar(aLocale, success) 109 { 110 init(success); 111 setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly. 112 } 113 114 JapaneseCalendar::~JapaneseCalendar() 115 { 116 } 117 118 JapaneseCalendar::JapaneseCalendar(const JapaneseCalendar& source) 119 : GregorianCalendar(source) 120 { 121 UErrorCode status = U_ZERO_ERROR; 122 init(status); 123 U_ASSERT(U_SUCCESS(status)); 124 } 125 126 JapaneseCalendar& JapaneseCalendar::operator= ( const JapaneseCalendar& right) 127 { 128 GregorianCalendar::operator=(right); 129 return *this; 130 } 131 132 Calendar* JapaneseCalendar::clone(void) 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) 143 { 144 int32_t era = internalGetEra(); 145 // TODO do we assume we can trust 'era'? What if it is denormalized? 146 147 int32_t month = 0; 148 149 // Find out if we are at the edge of an era 150 int32_t eraStart[3] = { 0,0,0 }; 151 UErrorCode status = U_ZERO_ERROR; 152 gJapaneseEraRules->getStartDate(era, eraStart, status); 153 U_ASSERT(U_SUCCESS(status)); 154 if(eyear == eraStart[0]) { 155 // Yes, we're in the first year of this era. 156 return eraStart[1] // month 157 -1; // return 0-based month 158 } 159 160 return month; 161 } 162 163 int32_t JapaneseCalendar::getDefaultDayInMonth(int32_t eyear, int32_t month) 164 { 165 int32_t era = internalGetEra(); 166 int32_t day = 1; 167 168 int32_t eraStart[3] = { 0,0,0 }; 169 UErrorCode status = U_ZERO_ERROR; 170 gJapaneseEraRules->getStartDate(era, eraStart, status); 171 U_ASSERT(U_SUCCESS(status)); 172 if(eyear == eraStart[0]) { 173 if(month == eraStart[1] - 1) { 174 return eraStart[2]; 175 } 176 } 177 178 return day; 179 } 180 181 182 int32_t JapaneseCalendar::internalGetEra() const 183 { 184 return internalGet(UCAL_ERA, gCurrentEra); 185 } 186 187 int32_t JapaneseCalendar::handleGetExtendedYear() 188 { 189 // EXTENDED_YEAR in JapaneseCalendar is a Gregorian year 190 // The default value of EXTENDED_YEAR is 1970 (Showa 45) 191 int32_t year; 192 193 if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR && 194 newerField(UCAL_EXTENDED_YEAR, UCAL_ERA) == UCAL_EXTENDED_YEAR) { 195 year = internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch); 196 } else { 197 UErrorCode status = U_ZERO_ERROR; 198 int32_t eraStartYear = gJapaneseEraRules->getStartYear(internalGet(UCAL_ERA, gCurrentEra), status); 199 U_ASSERT(U_SUCCESS(status)); 200 201 // extended year is a gregorian year, where 1 = 1AD, 0 = 1BC, -1 = 2BC, etc 202 year = internalGet(UCAL_YEAR, 1) // pin to minimum of year 1 (first year) 203 + eraStartYear // add gregorian starting year 204 - 1; // Subtract one because year starts at 1 205 } 206 return year; 207 } 208 209 210 void JapaneseCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status) 211 { 212 //Calendar::timeToFields(theTime, quick, status); 213 GregorianCalendar::handleComputeFields(julianDay, status); 214 int32_t year = internalGet(UCAL_EXTENDED_YEAR); // Gregorian year 215 int32_t eraIdx = gJapaneseEraRules->getEraIndex(year, internalGet(UCAL_MONTH) + 1, internalGet(UCAL_DAY_OF_MONTH), status); 216 217 internalSet(UCAL_ERA, eraIdx); 218 internalSet(UCAL_YEAR, year - gJapaneseEraRules->getStartYear(eraIdx, status) + 1); 219 } 220 221 /* 222 Disable pivoting 223 */ 224 UBool JapaneseCalendar::haveDefaultCentury() const 225 { 226 return FALSE; 227 } 228 229 UDate JapaneseCalendar::defaultCenturyStart() const 230 { 231 return 0;// WRONG 232 } 233 234 int32_t JapaneseCalendar::defaultCenturyStartYear() const 235 { 236 return 0; 237 } 238 239 int32_t JapaneseCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const 240 { 241 switch(field) { 242 case UCAL_ERA: 243 if (limitType == UCAL_LIMIT_MINIMUM || limitType == UCAL_LIMIT_GREATEST_MINIMUM) { 244 return 0; 245 } 246 return gCurrentEra; 247 case UCAL_YEAR: 248 { 249 switch (limitType) { 250 case UCAL_LIMIT_MINIMUM: 251 case UCAL_LIMIT_GREATEST_MINIMUM: 252 return 1; 253 case UCAL_LIMIT_LEAST_MAXIMUM: 254 return 1; 255 case UCAL_LIMIT_COUNT: //added to avoid warning 256 case UCAL_LIMIT_MAXIMUM: 257 { 258 UErrorCode status = U_ZERO_ERROR; 259 int32_t eraStartYear = gJapaneseEraRules->getStartYear(gCurrentEra, status); 260 U_ASSERT(U_SUCCESS(status)); 261 return GregorianCalendar::handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM) - eraStartYear; 262 } 263 default: 264 return 1; // Error condition, invalid limitType 265 } 266 } 267 default: 268 return GregorianCalendar::handleGetLimit(field,limitType); 269 } 270 } 271 272 int32_t JapaneseCalendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const { 273 if (field == UCAL_YEAR) { 274 int32_t era = get(UCAL_ERA, status); 275 if (U_FAILURE(status)) { 276 return 0; // error case... any value 277 } 278 if (era == gCurrentEra) { 279 // TODO: Investigate what value should be used here - revisit after 4.0. 280 return handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM); 281 } else { 282 int32_t nextEraStart[3] = { 0,0,0 }; 283 gJapaneseEraRules->getStartDate(era + 1, nextEraStart, status); 284 int32_t nextEraYear = nextEraStart[0]; 285 int32_t nextEraMonth = nextEraStart[1]; // 1-base 286 int32_t nextEraDate = nextEraStart[2]; 287 288 int32_t eraStartYear = gJapaneseEraRules->getStartYear(era, status); 289 int32_t maxYear = nextEraYear - eraStartYear + 1; // 1-base 290 if (nextEraMonth == 1 && nextEraDate == 1) { 291 // Subtract 1, because the next era starts at Jan 1 292 maxYear--; 293 } 294 return maxYear; 295 } 296 } 297 return GregorianCalendar::getActualMaximum(field, status); 298 } 299 300 U_NAMESPACE_END 301 302 #endif 303