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