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