Home | History | Annotate | Download | only in i18n
      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 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
     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 
     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. */
    103 uint32_t JapaneseCalendar::getCurrentEra() {
    104     return gCurrentEra;
    105 }
    106 
    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 
    114 JapaneseCalendar::~JapaneseCalendar()
    115 {
    116 }
    117 
    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 
    126 JapaneseCalendar& JapaneseCalendar::operator= ( const JapaneseCalendar& right)
    127 {
    128     GregorianCalendar::operator=(right);
    129     return *this;
    130 }
    131 
    132 Calendar* JapaneseCalendar::clone(void) const
    133 {
    134     return new JapaneseCalendar(*this);
    135 }
    136 
    137 const char *JapaneseCalendar::getType() const
    138 {
    139     return "japanese";
    140 }
    141 
    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 
    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 
    182 int32_t JapaneseCalendar::internalGetEra() const
    183 {
    184     return internalGet(UCAL_ERA, gCurrentEra);
    185 }
    186 
    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 
    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 */
    224 UBool JapaneseCalendar::haveDefaultCentury() const
    225 {
    226     return FALSE;
    227 }
    228 
    229 UDate JapaneseCalendar::defaultCenturyStart() const
    230 {
    231     return 0;// WRONG
    232 }
    233 
    234 int32_t JapaneseCalendar::defaultCenturyStartYear() const
    235 {
    236     return 0;
    237 }
    238 
    239 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 
    272 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