]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/japancal.cpp
ICU-62141.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / japancal.cpp
CommitLineData
f3c0d7a5
A
1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
b75a7d8f
A
3/*
4*******************************************************************************
2ca993e8
A
5* Copyright (C) 2003-2009,2012,2016 International Business Machines Corporation and
6* others. All Rights Reserved.
b75a7d8f
A
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
1546d4af
A
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
2ca993e8 32#include "cmemory.h"
1546d4af 33#include "erarules.h"
b75a7d8f
A
34#include "japancal.h"
35#include "unicode/gregocal.h"
46f4442e 36#include "umutex.h"
374ca955 37#include "uassert.h"
1546d4af
A
38#include "ucln_in.h"
39#include "cstring.h"
40
41static icu::EraRules * gJapaneseEraRules = nullptr;
42static icu::UInitOnce gJapaneseEraRulesInitOnce = U_INITONCE_INITIALIZER;
43static int32_t gCurrentEra = 0;
44
45U_CDECL_BEGIN
46static 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}
55U_CDECL_END
b75a7d8f
A
56
57U_NAMESPACE_BEGIN
58
374ca955 59UOBJECT_DEFINE_RTTI_IMPLEMENTATION(JapaneseCalendar)
b75a7d8f 60
46f4442e 61static const int32_t kGregorianEpoch = 1970; // used as the default value of EXTENDED_YEAR
1546d4af
A
62static const char* TENTATIVE_ERA_VAR_NAME = "ICU_ENABLE_TENTATIVE_ERA";
63
64
65// Export the following for use by test code.
66UBool 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 UChar 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 != NULL && uprv_stricmp(envVarVal, "true") == 0) {
88 includeTentativeEra = TRUE;
89 }
90#endif
91 return includeTentativeEra;
92}
93
94
95// Initialize global Japanese era data
96static 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
104static void init(UErrorCode &status) {
105 umtx_initOnce(gJapaneseEraRulesInitOnce, &initializeEras, status);
106 ucln_i18n_registerCleanup(UCLN_I18N_JAPANESE_CALENDAR, japanese_calendar_cleanup);
107}
46f4442e
A
108
109/* Some platforms don't like to export constants, like old Palm OS and some z/OS configurations. */
110uint32_t JapaneseCalendar::getCurrentEra() {
1546d4af 111 return gCurrentEra;
46f4442e 112}
b75a7d8f
A
113
114JapaneseCalendar::JapaneseCalendar(const Locale& aLocale, UErrorCode& success)
46f4442e 115: GregorianCalendar(aLocale, success)
b75a7d8f 116{
1546d4af 117 init(success);
b75a7d8f
A
118 setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
119}
120
121JapaneseCalendar::~JapaneseCalendar()
122{
123}
124
125JapaneseCalendar::JapaneseCalendar(const JapaneseCalendar& source)
46f4442e 126: GregorianCalendar(source)
b75a7d8f 127{
1546d4af
A
128 UErrorCode status = U_ZERO_ERROR;
129 init(status);
130 U_ASSERT(U_SUCCESS(status));
b75a7d8f
A
131}
132
133JapaneseCalendar& JapaneseCalendar::operator= ( const JapaneseCalendar& right)
134{
46f4442e
A
135 GregorianCalendar::operator=(right);
136 return *this;
b75a7d8f
A
137}
138
139Calendar* JapaneseCalendar::clone(void) const
140{
46f4442e 141 return new JapaneseCalendar(*this);
b75a7d8f
A
142}
143
144const char *JapaneseCalendar::getType() const
145{
46f4442e 146 return "japanese";
b75a7d8f
A
147}
148
729e4ab9 149int32_t JapaneseCalendar::getDefaultMonthInYear(int32_t eyear)
b75a7d8f 150{
46f4442e 151 int32_t era = internalGetEra();
46f4442e 152 // TODO do we assume we can trust 'era'? What if it is denormalized?
b75a7d8f 153
729e4ab9 154 int32_t month = 0;
b75a7d8f 155
46f4442e 156 // Find out if we are at the edge of an era
1546d4af
A
157 int32_t eraStart[3] = { 0,0,0 };
158 UErrorCode status = U_ZERO_ERROR;
159 gJapaneseEraRules->getStartDate(era, eraStart, status);
160 U_ASSERT(U_SUCCESS(status));
161 if(eyear == eraStart[0]) {
46f4442e 162 // Yes, we're in the first year of this era.
1546d4af
A
163 return eraStart[1] // month
164 -1; // return 0-based month
46f4442e 165 }
b75a7d8f 166
46f4442e 167 return month;
b75a7d8f
A
168}
169
729e4ab9 170int32_t JapaneseCalendar::getDefaultDayInMonth(int32_t eyear, int32_t month)
b75a7d8f 171{
46f4442e 172 int32_t era = internalGetEra();
729e4ab9 173 int32_t day = 1;
46f4442e 174
1546d4af
A
175 int32_t eraStart[3] = { 0,0,0 };
176 UErrorCode status = U_ZERO_ERROR;
177 gJapaneseEraRules->getStartDate(era, eraStart, status);
178 U_ASSERT(U_SUCCESS(status));
179 if(eyear == eraStart[0]) {
180 if(month == eraStart[1] - 1) {
181 return eraStart[2];
46f4442e 182 }
b75a7d8f 183 }
b75a7d8f 184
46f4442e 185 return day;
b75a7d8f
A
186}
187
188
189int32_t JapaneseCalendar::internalGetEra() const
190{
1546d4af 191 return internalGet(UCAL_ERA, gCurrentEra);
b75a7d8f
A
192}
193
374ca955 194int32_t JapaneseCalendar::handleGetExtendedYear()
b75a7d8f 195{
46f4442e
A
196 // EXTENDED_YEAR in JapaneseCalendar is a Gregorian year
197 // The default value of EXTENDED_YEAR is 1970 (Showa 45)
198 int32_t year;
199
200 if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR &&
201 newerField(UCAL_EXTENDED_YEAR, UCAL_ERA) == UCAL_EXTENDED_YEAR) {
1546d4af
A
202 year = internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch);
203 } else {
204 UErrorCode status = U_ZERO_ERROR;
205 int32_t eraStartYear = gJapaneseEraRules->getStartYear(internalGet(UCAL_ERA, gCurrentEra), status);
206 U_ASSERT(U_SUCCESS(status));
207
208 // extended year is a gregorian year, where 1 = 1AD, 0 = 1BC, -1 = 2BC, etc
209 year = internalGet(UCAL_YEAR, 1) // pin to minimum of year 1 (first year)
210 + eraStartYear // add gregorian starting year
211 - 1; // Subtract one because year starts at 1
212 }
213 return year;
b75a7d8f
A
214}
215
374ca955
A
216
217void JapaneseCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status)
b75a7d8f 218{
46f4442e
A
219 //Calendar::timeToFields(theTime, quick, status);
220 GregorianCalendar::handleComputeFields(julianDay, status);
221 int32_t year = internalGet(UCAL_EXTENDED_YEAR); // Gregorian year
1546d4af 222 int32_t eraIdx = gJapaneseEraRules->getEraIndex(year, internalGet(UCAL_MONTH) + 1, internalGet(UCAL_DAY_OF_MONTH), status);
46f4442e 223
1546d4af
A
224 internalSet(UCAL_ERA, eraIdx);
225 internalSet(UCAL_YEAR, year - gJapaneseEraRules->getStartYear(eraIdx, status) + 1);
b75a7d8f
A
226}
227
228/*
46f4442e 229Disable pivoting
b75a7d8f
A
230*/
231UBool JapaneseCalendar::haveDefaultCentury() const
232{
46f4442e 233 return FALSE;
b75a7d8f
A
234}
235
236UDate JapaneseCalendar::defaultCenturyStart() const
237{
46f4442e 238 return 0;// WRONG
b75a7d8f
A
239}
240
241int32_t JapaneseCalendar::defaultCenturyStartYear() const
242{
46f4442e 243 return 0;
b75a7d8f
A
244}
245
374ca955
A
246int32_t JapaneseCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const
247{
46f4442e
A
248 switch(field) {
249 case UCAL_ERA:
250 if (limitType == UCAL_LIMIT_MINIMUM || limitType == UCAL_LIMIT_GREATEST_MINIMUM) {
51004dcb 251 return 0;
374ca955 252 }
1546d4af 253 return gJapaneseEraRules->getNumberOfEras() - 1; // <rdar://problem/49714633> max known era, not gCurrentEra
46f4442e
A
254 case UCAL_YEAR:
255 {
256 switch (limitType) {
257 case UCAL_LIMIT_MINIMUM:
258 case UCAL_LIMIT_GREATEST_MINIMUM:
259 return 1;
260 case UCAL_LIMIT_LEAST_MAXIMUM:
261 return 1;
262 case UCAL_LIMIT_COUNT: //added to avoid warning
263 case UCAL_LIMIT_MAXIMUM:
1546d4af
A
264 {
265 UErrorCode status = U_ZERO_ERROR;
266 int32_t eraStartYear = gJapaneseEraRules->getStartYear(gCurrentEra, status);
267 U_ASSERT(U_SUCCESS(status));
268 return GregorianCalendar::handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM) - eraStartYear;
269 }
729e4ab9
A
270 default:
271 return 1; // Error condition, invalid limitType
46f4442e 272 }
374ca955 273 }
374ca955 274 default:
46f4442e 275 return GregorianCalendar::handleGetLimit(field,limitType);
374ca955 276 }
374ca955 277}
b75a7d8f 278
46f4442e
A
279int32_t JapaneseCalendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const {
280 if (field == UCAL_YEAR) {
281 int32_t era = get(UCAL_ERA, status);
282 if (U_FAILURE(status)) {
283 return 0; // error case... any value
284 }
1546d4af 285 if (era == gJapaneseEraRules->getNumberOfEras() - 1) { // <rdar://problem/49714633>
46f4442e
A
286 // TODO: Investigate what value should be used here - revisit after 4.0.
287 return handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM);
288 } else {
1546d4af
A
289 int32_t nextEraStart[3] = { 0,0,0 };
290 gJapaneseEraRules->getStartDate(era + 1, nextEraStart, status);
291 int32_t nextEraYear = nextEraStart[0];
292 int32_t nextEraMonth = nextEraStart[1]; // 1-base
293 int32_t nextEraDate = nextEraStart[2];
294
295 int32_t eraStartYear = gJapaneseEraRules->getStartYear(era, status);
296 int32_t maxYear = nextEraYear - eraStartYear + 1; // 1-base
46f4442e
A
297 if (nextEraMonth == 1 && nextEraDate == 1) {
298 // Subtract 1, because the next era starts at Jan 1
299 maxYear--;
300 }
301 return maxYear;
302 }
303 }
304 return GregorianCalendar::getActualMaximum(field, status);
305}
b75a7d8f
A
306
307U_NAMESPACE_END
308
309#endif