#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#if U_PLATFORM_HAS_WINUWP_API == 0
#include <stdlib.h> // getenv() is not available in UWP env
#else
#ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
#endif
# define VC_EXTRALEAN
# define NOUSER
# define NOSERVICE
# define NOIME
# define NOMCX
#include <windows.h>
#endif
#include "cmemory.h"
#include "erarules.h"
#include "japancal.h"
#include "unicode/gregocal.h"
#include "umutex.h"
#include "uassert.h"
#include "ucln_in.h"
#include "cstring.h"
static icu::EraRules * gJapaneseEraRules = nullptr;
static icu::UInitOnce gJapaneseEraRulesInitOnce = U_INITONCE_INITIALIZER;
static int32_t gCurrentEra = 0;
U_CDECL_BEGIN
static UBool japanese_calendar_cleanup(void) {
if (gJapaneseEraRules) {
delete gJapaneseEraRules;
gJapaneseEraRules = nullptr;
}
gCurrentEra = 0;
gJapaneseEraRulesInitOnce.reset();
return TRUE;
}
U_CDECL_END
U_NAMESPACE_BEGIN
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(JapaneseCalendar)
static const int32_t kGregorianEpoch = 1970; static const char* TENTATIVE_ERA_VAR_NAME = "ICU_ENABLE_TENTATIVE_ERA";
UBool JapaneseCalendar::enableTentativeEra() {
UBool includeTentativeEra = FALSE;
#if U_PLATFORM_HAS_WINUWP_API == 1
UChar varName[26] = {};
u_charsToUChars(TENTATIVE_ERA_VAR_NAME, varName, static_cast<int32_t>(uprv_strlen(TENTATIVE_ERA_VAR_NAME)));
WCHAR varValue[5] = {};
DWORD ret = GetEnvironmentVariableW(reinterpret_cast<WCHAR*>(varName), varValue, UPRV_LENGTHOF(varValue));
if ((ret == 4) && (_wcsicmp(varValue, L"true") == 0)) {
includeTentativeEra = TRUE;
}
#else
char *envVarVal = getenv(TENTATIVE_ERA_VAR_NAME);
if (envVarVal != NULL && uprv_stricmp(envVarVal, "true") == 0) {
includeTentativeEra = TRUE;
}
#endif
return includeTentativeEra;
}
static void U_CALLCONV initializeEras(UErrorCode &status) {
gJapaneseEraRules = EraRules::createInstance("japanese", JapaneseCalendar::enableTentativeEra(), status);
if (U_FAILURE(status)) {
return;
}
gCurrentEra = gJapaneseEraRules->getCurrentEraIndex();
}
static void init(UErrorCode &status) {
umtx_initOnce(gJapaneseEraRulesInitOnce, &initializeEras, status);
ucln_i18n_registerCleanup(UCLN_I18N_JAPANESE_CALENDAR, japanese_calendar_cleanup);
}
uint32_t JapaneseCalendar::getCurrentEra() {
return gCurrentEra;
}
JapaneseCalendar::JapaneseCalendar(const Locale& aLocale, UErrorCode& success)
: GregorianCalendar(aLocale, success)
{
init(success);
setTimeInMillis(getNow(), success); }
JapaneseCalendar::~JapaneseCalendar()
{
}
JapaneseCalendar::JapaneseCalendar(const JapaneseCalendar& source)
: GregorianCalendar(source)
{
UErrorCode status = U_ZERO_ERROR;
init(status);
U_ASSERT(U_SUCCESS(status));
}
JapaneseCalendar& JapaneseCalendar::operator= ( const JapaneseCalendar& right)
{
GregorianCalendar::operator=(right);
return *this;
}
Calendar* JapaneseCalendar::clone(void) const
{
return new JapaneseCalendar(*this);
}
const char *JapaneseCalendar::getType() const
{
return "japanese";
}
int32_t JapaneseCalendar::getDefaultMonthInYear(int32_t eyear)
{
int32_t era = internalGetEra();
int32_t month = 0;
int32_t eraStart[3] = { 0,0,0 };
UErrorCode status = U_ZERO_ERROR;
gJapaneseEraRules->getStartDate(era, eraStart, status);
U_ASSERT(U_SUCCESS(status));
if(eyear == eraStart[0]) {
return eraStart[1] -1; }
return month;
}
int32_t JapaneseCalendar::getDefaultDayInMonth(int32_t eyear, int32_t month)
{
int32_t era = internalGetEra();
int32_t day = 1;
int32_t eraStart[3] = { 0,0,0 };
UErrorCode status = U_ZERO_ERROR;
gJapaneseEraRules->getStartDate(era, eraStart, status);
U_ASSERT(U_SUCCESS(status));
if(eyear == eraStart[0]) {
if(month == eraStart[1] - 1) {
return eraStart[2];
}
}
return day;
}
int32_t JapaneseCalendar::internalGetEra() const
{
return internalGet(UCAL_ERA, gCurrentEra);
}
int32_t JapaneseCalendar::handleGetExtendedYear()
{
int32_t year;
if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR &&
newerField(UCAL_EXTENDED_YEAR, UCAL_ERA) == UCAL_EXTENDED_YEAR) {
year = internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch);
} else {
UErrorCode status = U_ZERO_ERROR;
int32_t eraStartYear = gJapaneseEraRules->getStartYear(internalGet(UCAL_ERA, gCurrentEra), status);
U_ASSERT(U_SUCCESS(status));
year = internalGet(UCAL_YEAR, 1) + eraStartYear - 1; }
return year;
}
void JapaneseCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status)
{
GregorianCalendar::handleComputeFields(julianDay, status);
int32_t year = internalGet(UCAL_EXTENDED_YEAR); int32_t eraIdx = gJapaneseEraRules->getEraIndex(year, internalGet(UCAL_MONTH) + 1, internalGet(UCAL_DAY_OF_MONTH), status);
internalSet(UCAL_ERA, eraIdx);
internalSet(UCAL_YEAR, year - gJapaneseEraRules->getStartYear(eraIdx, status) + 1);
}
UBool JapaneseCalendar::haveDefaultCentury() const
{
return FALSE;
}
UDate JapaneseCalendar::defaultCenturyStart() const
{
return 0;}
int32_t JapaneseCalendar::defaultCenturyStartYear() const
{
return 0;
}
int32_t JapaneseCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const
{
switch(field) {
case UCAL_ERA:
if (limitType == UCAL_LIMIT_MINIMUM || limitType == UCAL_LIMIT_GREATEST_MINIMUM) {
return 0;
}
return gJapaneseEraRules->getNumberOfEras() - 1; case UCAL_YEAR:
{
switch (limitType) {
case UCAL_LIMIT_MINIMUM:
case UCAL_LIMIT_GREATEST_MINIMUM:
return 1;
case UCAL_LIMIT_LEAST_MAXIMUM:
return 1;
case UCAL_LIMIT_COUNT: case UCAL_LIMIT_MAXIMUM:
{
UErrorCode status = U_ZERO_ERROR;
int32_t eraStartYear = gJapaneseEraRules->getStartYear(gCurrentEra, status);
U_ASSERT(U_SUCCESS(status));
return GregorianCalendar::handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM) - eraStartYear;
}
default:
return 1; }
}
default:
return GregorianCalendar::handleGetLimit(field,limitType);
}
}
int32_t JapaneseCalendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const {
if (field == UCAL_YEAR) {
int32_t era = get(UCAL_ERA, status);
if (U_FAILURE(status)) {
return 0; }
if (era == gJapaneseEraRules->getNumberOfEras() - 1) { return handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM);
} else {
int32_t nextEraStart[3] = { 0,0,0 };
gJapaneseEraRules->getStartDate(era + 1, nextEraStart, status);
int32_t nextEraYear = nextEraStart[0];
int32_t nextEraMonth = nextEraStart[1]; int32_t nextEraDate = nextEraStart[2];
int32_t eraStartYear = gJapaneseEraRules->getStartYear(era, status);
int32_t maxYear = nextEraYear - eraStartYear + 1; if (nextEraMonth == 1 && nextEraDate == 1) {
maxYear--;
}
return maxYear;
}
}
return GregorianCalendar::getActualMaximum(field, status);
}
U_NAMESPACE_END
#endif