Coverage Report

Created: 2025-06-24 06:43

/src/icu/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 = U_INITONCE_INITIALIZER;
43
static int32_t gCurrentEra = 0;
44
45
U_CDECL_BEGIN
46
0
static UBool japanese_calendar_cleanup(void) {
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
0
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
0
    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
0
    char *envVarVal = getenv(TENTATIVE_ERA_VAR_NAME);
87
0
    if (envVarVal != NULL && uprv_stricmp(envVarVal, "true") == 0) {
88
0
        includeTentativeEra = TRUE;
89
0
    }
90
0
#endif
91
0
    return includeTentativeEra;
92
0
}
93
94
95
// Initialize global Japanese era data
96
0
static void U_CALLCONV initializeEras(UErrorCode &status) {
97
0
    gJapaneseEraRules = EraRules::createInstance("japanese", JapaneseCalendar::enableTentativeEra(), status);
98
0
    if (U_FAILURE(status)) {
99
0
        return;
100
0
    }
101
0
    gCurrentEra = gJapaneseEraRules->getCurrentEraIndex();
102
0
}
103
104
0
static void init(UErrorCode &status) {
105
0
    umtx_initOnce(gJapaneseEraRulesInitOnce, &initializeEras, status);
106
0
    ucln_i18n_registerCleanup(UCLN_I18N_JAPANESE_CALENDAR, japanese_calendar_cleanup);
107
0
}
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
0
:   GregorianCalendar(aLocale, success)
116
0
{
117
0
    init(success);
118
0
    setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
119
0
}
120
121
JapaneseCalendar::~JapaneseCalendar()
122
0
{
123
0
}
124
125
JapaneseCalendar::JapaneseCalendar(const JapaneseCalendar& source)
126
0
: GregorianCalendar(source)
127
0
{
128
0
    UErrorCode status = U_ZERO_ERROR;
129
0
    init(status);
130
0
    U_ASSERT(U_SUCCESS(status));
131
0
}
132
133
JapaneseCalendar& JapaneseCalendar::operator= ( const JapaneseCalendar& right)
134
0
{
135
0
    GregorianCalendar::operator=(right);
136
0
    return *this;
137
0
}
138
139
JapaneseCalendar* JapaneseCalendar::clone() const
140
0
{
141
0
    return new JapaneseCalendar(*this);
142
0
}
143
144
const char *JapaneseCalendar::getType() const
145
0
{
146
0
    return "japanese";
147
0
}
148
149
int32_t JapaneseCalendar::getDefaultMonthInYear(int32_t eyear) 
150
0
{
151
0
    int32_t era = internalGetEra();
152
    // TODO do we assume we can trust 'era'?  What if it is denormalized?
153
154
0
    int32_t month = 0;
155
156
    // Find out if we are at the edge of an era
157
0
    int32_t eraStart[3] = { 0,0,0 };
158
0
    UErrorCode status = U_ZERO_ERROR;
159
0
    gJapaneseEraRules->getStartDate(era, eraStart, status);
160
0
    U_ASSERT(U_SUCCESS(status));
161
0
    if(eyear == eraStart[0]) {
162
        // Yes, we're in the first year of this era.
163
0
        return eraStart[1]  // month
164
0
                -1;         // return 0-based month
165
0
    }
166
167
0
    return month;
168
0
}
169
170
int32_t JapaneseCalendar::getDefaultDayInMonth(int32_t eyear, int32_t month) 
171
0
{
172
0
    int32_t era = internalGetEra();
173
0
    int32_t day = 1;
174
175
0
    int32_t eraStart[3] = { 0,0,0 };
176
0
    UErrorCode status = U_ZERO_ERROR;
177
0
    gJapaneseEraRules->getStartDate(era, eraStart, status);
178
0
    U_ASSERT(U_SUCCESS(status));
179
0
    if(eyear == eraStart[0]) {
180
0
        if(month == eraStart[1] - 1) {
181
0
            return eraStart[2];
182
0
        }
183
0
    }
184
185
0
    return day;
186
0
}
187
188
189
int32_t JapaneseCalendar::internalGetEra() const
190
0
{
191
0
    return internalGet(UCAL_ERA, gCurrentEra);
192
0
}
193
194
int32_t JapaneseCalendar::handleGetExtendedYear()
195
0
{
196
    // EXTENDED_YEAR in JapaneseCalendar is a Gregorian year
197
    // The default value of EXTENDED_YEAR is 1970 (Showa 45)
198
0
    int32_t year;
199
200
0
    if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR &&
201
0
        newerField(UCAL_EXTENDED_YEAR, UCAL_ERA) == UCAL_EXTENDED_YEAR) {
202
0
        year = internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch);
203
0
    } else {
204
0
        UErrorCode status = U_ZERO_ERROR;
205
0
        int32_t eraStartYear = gJapaneseEraRules->getStartYear(internalGet(UCAL_ERA, gCurrentEra), status);
206
0
        U_ASSERT(U_SUCCESS(status));
207
208
        // extended year is a gregorian year, where 1 = 1AD,  0 = 1BC, -1 = 2BC, etc
209
0
        year = internalGet(UCAL_YEAR, 1)    // pin to minimum of year 1 (first year)
210
0
            + eraStartYear                  // add gregorian starting year
211
0
            - 1;                            // Subtract one because year starts at 1
212
0
    }
213
0
    return year;
214
0
}
215
216
217
void JapaneseCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status)
218
0
{
219
    //Calendar::timeToFields(theTime, quick, status);
220
0
    GregorianCalendar::handleComputeFields(julianDay, status);
221
0
    int32_t year = internalGet(UCAL_EXTENDED_YEAR); // Gregorian year
222
0
    int32_t eraIdx = gJapaneseEraRules->getEraIndex(year, internalGet(UCAL_MONTH) + 1, internalGet(UCAL_DAY_OF_MONTH), status);
223
224
0
    internalSet(UCAL_ERA, eraIdx);
225
0
    internalSet(UCAL_YEAR, year - gJapaneseEraRules->getStartYear(eraIdx, status) + 1);
226
0
}
227
228
/*
229
Disable pivoting 
230
*/
231
UBool JapaneseCalendar::haveDefaultCentury() const
232
0
{
233
0
    return FALSE;
234
0
}
235
236
UDate JapaneseCalendar::defaultCenturyStart() const
237
0
{
238
0
    return 0;// WRONG
239
0
}
240
241
int32_t JapaneseCalendar::defaultCenturyStartYear() const
242
0
{
243
0
    return 0;
244
0
}
245
246
int32_t JapaneseCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const
247
0
{
248
0
    switch(field) {
249
0
    case UCAL_ERA:
250
0
        if (limitType == UCAL_LIMIT_MINIMUM || limitType == UCAL_LIMIT_GREATEST_MINIMUM) {
251
0
            return 0;
252
0
        }
253
0
        return gJapaneseEraRules->getNumberOfEras() - 1; // max known era, not gCurrentEra
254
0
    case UCAL_YEAR:
255
0
        {
256
0
            switch (limitType) {
257
0
            case UCAL_LIMIT_MINIMUM:
258
0
            case UCAL_LIMIT_GREATEST_MINIMUM:
259
0
                return 1;
260
0
            case UCAL_LIMIT_LEAST_MAXIMUM:
261
0
                return 1;
262
0
            case  UCAL_LIMIT_COUNT: //added to avoid warning
263
0
            case UCAL_LIMIT_MAXIMUM:
264
0
            {
265
0
                UErrorCode status = U_ZERO_ERROR;
266
0
                int32_t eraStartYear = gJapaneseEraRules->getStartYear(gCurrentEra, status);
267
0
                U_ASSERT(U_SUCCESS(status));
268
0
                return GregorianCalendar::handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM) - eraStartYear;
269
0
            }
270
0
            default:
271
0
                return 1;    // Error condition, invalid limitType
272
0
            }
273
0
        }
274
0
    default:
275
0
        return GregorianCalendar::handleGetLimit(field,limitType);
276
0
    }
277
0
}
278
279
0
int32_t JapaneseCalendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const {
280
0
    if (field == UCAL_YEAR) {
281
0
        int32_t era = get(UCAL_ERA, status);
282
0
        if (U_FAILURE(status)) {
283
0
            return 0; // error case... any value
284
0
        }
285
0
        if (era == gJapaneseEraRules->getNumberOfEras() - 1) { // max known era, not gCurrentEra
286
            // TODO: Investigate what value should be used here - revisit after 4.0.
287
0
            return handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM);
288
0
        } else {
289
0
            int32_t nextEraStart[3] = { 0,0,0 };
290
0
            gJapaneseEraRules->getStartDate(era + 1, nextEraStart, status);
291
0
            int32_t nextEraYear = nextEraStart[0];
292
0
            int32_t nextEraMonth = nextEraStart[1]; // 1-base
293
0
            int32_t nextEraDate = nextEraStart[2];
294
295
0
            int32_t eraStartYear = gJapaneseEraRules->getStartYear(era, status);
296
0
            int32_t maxYear = nextEraYear - eraStartYear + 1;   // 1-base
297
0
            if (nextEraMonth == 1 && nextEraDate == 1) {
298
                // Subtract 1, because the next era starts at Jan 1
299
0
                maxYear--;
300
0
            }
301
0
            return maxYear;
302
0
        }
303
0
    }
304
0
    return GregorianCalendar::getActualMaximum(field, status);
305
0
}
306
307
U_NAMESPACE_END
308
309
#endif