Coverage Report

Created: 2025-06-13 06:38

/src/icu/icu4c/source/i18n/japancal.cpp
Line
Count
Source (jump to first uncovered line)
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
46
0
static UBool japanese_calendar_cleanup() {
47
0
    if (gJapaneseEraRules) {
48
0
        delete gJapaneseEraRules;
49
0
        gJapaneseEraRules = nullptr;
50
0
    }
51
0
    gCurrentEra = 0;
52
0
    gJapaneseEraRulesInitOnce.reset();
53
0
    return true;
54
0
}
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.
66
1
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
1
    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
1
    char *envVarVal = getenv(TENTATIVE_ERA_VAR_NAME);
87
1
    if (envVarVal != nullptr && uprv_stricmp(envVarVal, "true") == 0) {
88
0
        includeTentativeEra = true;
89
0
    }
90
1
#endif
91
1
    return includeTentativeEra;
92
1
}
93
94
95
// Initialize global Japanese era data
96
1
static void U_CALLCONV initializeEras(UErrorCode &status) {
97
1
    gJapaneseEraRules = EraRules::createInstance("japanese", JapaneseCalendar::enableTentativeEra(), status);
98
1
    if (U_FAILURE(status)) {
99
0
        return;
100
0
    }
101
1
    gCurrentEra = gJapaneseEraRules->getCurrentEraIndex();
102
1
}
103
104
38.0k
static void init(UErrorCode &status) {
105
38.0k
    umtx_initOnce(gJapaneseEraRulesInitOnce, &initializeEras, status);
106
38.0k
    ucln_i18n_registerCleanup(UCLN_I18N_JAPANESE_CALENDAR, japanese_calendar_cleanup);
107
38.0k
}
108
109
/* Some platforms don't like to export constants, like old Palm OS and some z/OS configurations. */
110
0
uint32_t JapaneseCalendar::getCurrentEra() {
111
0
    return gCurrentEra;
112
0
}
113
114
JapaneseCalendar::JapaneseCalendar(const Locale& aLocale, UErrorCode& success)
115
242
:   GregorianCalendar(aLocale, success)
116
242
{
117
242
    init(success);
118
242
}
119
120
JapaneseCalendar::~JapaneseCalendar()
121
38.0k
{
122
38.0k
}
123
124
JapaneseCalendar::JapaneseCalendar(const JapaneseCalendar& source)
125
37.8k
: GregorianCalendar(source)
126
37.8k
{
127
37.8k
    UErrorCode status = U_ZERO_ERROR;
128
37.8k
    init(status);
129
37.8k
    U_ASSERT(U_SUCCESS(status));
130
37.8k
}
131
132
JapaneseCalendar* JapaneseCalendar::clone() const
133
37.8k
{
134
37.8k
    return new JapaneseCalendar(*this);
135
37.8k
}
136
137
const char *JapaneseCalendar::getType() const
138
0
{
139
0
    return "japanese";
140
0
}
141
142
int32_t JapaneseCalendar::getDefaultMonthInYear(int32_t eyear, UErrorCode& status) 
143
454
{
144
454
    if (U_FAILURE(status)) {
145
0
      return 0;
146
0
    }
147
454
    int32_t era = internalGetEra();
148
    // TODO do we assume we can trust 'era'?  What if it is denormalized?
149
150
454
    int32_t month = 0;
151
152
    // Find out if we are at the edge of an era
153
454
    int32_t eraStart[3] = { 0,0,0 };
154
454
    gJapaneseEraRules->getStartDate(era, eraStart, status);
155
454
    if (U_FAILURE(status)) {
156
51
        return 0;
157
51
    }
158
403
    if(eyear == eraStart[0]) {
159
        // Yes, we're in the first year of this era.
160
48
        return eraStart[1]  // month
161
48
                -1;         // return 0-based month
162
48
    }
163
164
355
    return month;
165
403
}
166
167
int32_t JapaneseCalendar::getDefaultDayInMonth(int32_t eyear, int32_t month, UErrorCode& status) 
168
344
{
169
344
    if (U_FAILURE(status)) {
170
0
        return 0;
171
0
    }
172
344
    int32_t era = internalGetEra();
173
344
    int32_t day = 1;
174
175
344
    int32_t eraStart[3] = { 0,0,0 };
176
344
    gJapaneseEraRules->getStartDate(era, eraStart, status);
177
344
    if (U_FAILURE(status)) {
178
6
        return 0;
179
6
    }
180
338
    if (eyear == eraStart[0] && (month == eraStart[1] - 1)) {
181
31
        return eraStart[2];
182
31
    }
183
307
    return day;
184
338
}
185
186
187
int32_t JapaneseCalendar::internalGetEra() const
188
798
{
189
798
    return internalGet(UCAL_ERA, gCurrentEra);
190
798
}
191
192
int32_t JapaneseCalendar::handleGetExtendedYear(UErrorCode& status)
193
39.6k
{
194
39.6k
    if (U_FAILURE(status)) {
195
0
        return 0;
196
0
    }
197
    // EXTENDED_YEAR in JapaneseCalendar is a Gregorian year
198
    // The default value of EXTENDED_YEAR is 1970 (Showa 45)
199
200
39.6k
    if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR &&
201
39.6k
        newerField(UCAL_EXTENDED_YEAR, UCAL_ERA) == UCAL_EXTENDED_YEAR) {
202
37.6k
        return internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch);
203
37.6k
    }
204
2.05k
    int32_t eraStartYear = gJapaneseEraRules->getStartYear(internalGet(UCAL_ERA, gCurrentEra), status);
205
2.05k
    if (U_FAILURE(status)) {
206
88
        return 0;
207
88
    }
208
209
    // extended year is a gregorian year, where 1 = 1AD,  0 = 1BC, -1 = 2BC, etc
210
1.96k
    int32_t year = internalGet(UCAL_YEAR, 1);   // pin to minimum of year 1 (first year)
211
    // add gregorian starting year, subtract one because year starts at 1
212
1.96k
    if (uprv_add32_overflow(year, eraStartYear - 1,  &year)) {
213
18
        status = U_ILLEGAL_ARGUMENT_ERROR;
214
18
        return 0;
215
18
    }
216
1.95k
    return year;
217
1.96k
}
218
219
220
void JapaneseCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status)
221
82.7k
{
222
    //Calendar::timeToFields(theTime, quick, status);
223
82.7k
    GregorianCalendar::handleComputeFields(julianDay, status);
224
82.7k
    int32_t year = internalGet(UCAL_EXTENDED_YEAR); // Gregorian year
225
82.7k
    int32_t eraIdx = gJapaneseEraRules->getEraIndex(year, internalGetMonth(status) + 1, internalGet(UCAL_DAY_OF_MONTH), status);
226
227
82.7k
    int32_t startYear = gJapaneseEraRules->getStartYear(eraIdx, status) - 1;
228
82.7k
    if (U_FAILURE(status)) {
229
35
        return;
230
35
    }
231
82.6k
    if (uprv_add32_overflow(year, -startYear,  &year)) {
232
0
        status = U_ILLEGAL_ARGUMENT_ERROR;
233
0
        return;
234
0
    }
235
82.6k
    internalSet(UCAL_ERA, eraIdx);
236
82.6k
    internalSet(UCAL_YEAR, year);
237
82.6k
}
238
239
/*
240
Disable pivoting 
241
*/
242
UBool JapaneseCalendar::haveDefaultCentury() const
243
0
{
244
0
    return false;
245
0
}
246
247
UDate JapaneseCalendar::defaultCenturyStart() const
248
0
{
249
0
    return 0;// WRONG
250
0
}
251
252
int32_t JapaneseCalendar::defaultCenturyStartYear() const
253
0
{
254
0
    return 0;
255
0
}
256
257
int32_t JapaneseCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const
258
76.6k
{
259
76.6k
    switch(field) {
260
1.41k
    case UCAL_ERA:
261
1.41k
        if (limitType == UCAL_LIMIT_MINIMUM || limitType == UCAL_LIMIT_GREATEST_MINIMUM) {
262
470
            return 0;
263
470
        }
264
940
        return gJapaneseEraRules->getNumberOfEras() - 1; // max known era, not gCurrentEra
265
22
    case UCAL_YEAR:
266
22
        {
267
22
            switch (limitType) {
268
0
            case UCAL_LIMIT_MINIMUM:
269
0
            case UCAL_LIMIT_GREATEST_MINIMUM:
270
0
                return 1;
271
0
            case UCAL_LIMIT_LEAST_MAXIMUM:
272
0
                return 1;
273
0
            case  UCAL_LIMIT_COUNT: //added to avoid warning
274
22
            case UCAL_LIMIT_MAXIMUM:
275
22
            {
276
22
                UErrorCode status = U_ZERO_ERROR;
277
22
                int32_t eraStartYear = gJapaneseEraRules->getStartYear(gCurrentEra, status);
278
22
                U_ASSERT(U_SUCCESS(status));
279
22
                return GregorianCalendar::handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM) - eraStartYear;
280
0
            }
281
0
            default:
282
0
                return 1;    // Error condition, invalid limitType
283
22
            }
284
22
        }
285
75.2k
    default:
286
75.2k
        return GregorianCalendar::handleGetLimit(field,limitType);
287
76.6k
    }
288
76.6k
}
289
290
38.1k
int32_t JapaneseCalendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const {
291
38.1k
    if (field != UCAL_YEAR) {
292
38.0k
        return GregorianCalendar::getActualMaximum(field, status);
293
38.0k
    }
294
100
    int32_t era = get(UCAL_ERA, status);
295
100
    if (U_FAILURE(status)) {
296
0
        return 0; // error case... any value
297
0
    }
298
100
    if (era == gJapaneseEraRules->getNumberOfEras() - 1) { // max known era, not gCurrentEra
299
        // TODO: Investigate what value should be used here - revisit after 4.0.
300
22
        return handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM);
301
22
    }
302
78
    int32_t nextEraStart[3] = { 0,0,0 };
303
78
    gJapaneseEraRules->getStartDate(era + 1, nextEraStart, status);
304
78
    int32_t nextEraYear = nextEraStart[0];
305
78
    int32_t nextEraMonth = nextEraStart[1]; // 1-base
306
78
    int32_t nextEraDate = nextEraStart[2];
307
308
78
    int32_t eraStartYear = gJapaneseEraRules->getStartYear(era, status);
309
78
    int32_t maxYear = nextEraYear - eraStartYear + 1;   // 1-base
310
78
    if (nextEraMonth == 1 && nextEraDate == 1) {
311
        // Subtract 1, because the next era starts at Jan 1
312
18
        maxYear--;
313
18
    }
314
78
    return maxYear;
315
100
}
316
317
U_NAMESPACE_END
318
319
#endif