• 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 = U_INITONCE_INITIALIZER;
43 static int32_t gCurrentEra = 0;
44 
45 U_CDECL_BEGIN
japanese_calendar_cleanup(void)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
initializeEras(UErrorCode & status)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 
init(UErrorCode & status)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. */
getCurrentEra()103 uint32_t JapaneseCalendar::getCurrentEra() {
104     return gCurrentEra;
105 }
106 
JapaneseCalendar(const Locale & aLocale,UErrorCode & success)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 
~JapaneseCalendar()114 JapaneseCalendar::~JapaneseCalendar()
115 {
116 }
117 
JapaneseCalendar(const JapaneseCalendar & source)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 
operator =(const JapaneseCalendar & right)126 JapaneseCalendar& JapaneseCalendar::operator= ( const JapaneseCalendar& right)
127 {
128     GregorianCalendar::operator=(right);
129     return *this;
130 }
131 
clone(void) const132 Calendar* JapaneseCalendar::clone(void) const
133 {
134     return new JapaneseCalendar(*this);
135 }
136 
getType() const137 const char *JapaneseCalendar::getType() const
138 {
139     return "japanese";
140 }
141 
getDefaultMonthInYear(int32_t eyear)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 
getDefaultDayInMonth(int32_t eyear,int32_t month)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 
internalGetEra() const182 int32_t JapaneseCalendar::internalGetEra() const
183 {
184     return internalGet(UCAL_ERA, gCurrentEra);
185 }
186 
handleGetExtendedYear()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 
handleComputeFields(int32_t julianDay,UErrorCode & status)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 */
haveDefaultCentury() const224 UBool JapaneseCalendar::haveDefaultCentury() const
225 {
226     return FALSE;
227 }
228 
defaultCenturyStart() const229 UDate JapaneseCalendar::defaultCenturyStart() const
230 {
231     return 0;// WRONG
232 }
233 
defaultCenturyStartYear() const234 int32_t JapaneseCalendar::defaultCenturyStartYear() const
235 {
236     return 0;
237 }
238 
handleGetLimit(UCalendarDateFields field,ELimitType limitType) const239 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 
getActualMaximum(UCalendarDateFields field,UErrorCode & status) const272 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