303 lines
9.3 KiB
C++
303 lines
9.3 KiB
C++
// © 2016 and later: Unicode, Inc. and others.
|
|
// License & terms of use: http://www.unicode.org/copyright.html
|
|
/*
|
|
*******************************************************************************
|
|
* Copyright (C) 2003-2009,2012,2016 International Business Machines Corporation and
|
|
* others. All Rights Reserved.
|
|
*******************************************************************************
|
|
*
|
|
* File JAPANCAL.CPP
|
|
*
|
|
* Modification History:
|
|
* 05/16/2003 srl copied from buddhcal.cpp
|
|
*
|
|
*/
|
|
|
|
#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; // used as the default value of EXTENDED_YEAR
|
|
static const char* TENTATIVE_ERA_VAR_NAME = "ICU_ENABLE_TENTATIVE_ERA";
|
|
|
|
// Initialize global Japanese era data
|
|
static void U_CALLCONV initializeEras(UErrorCode &status) {
|
|
// Although start date of next Japanese era is planned ahead, a name of
|
|
// new era might not be available. This implementation allows tester to
|
|
// check a new era without era names by settings below (in priority order).
|
|
// By default, such tentative era is disabled.
|
|
|
|
// 1. Environment variable ICU_ENABLE_TENTATIVE_ERA=true or false
|
|
|
|
UBool includeTentativeEra = FALSE;
|
|
|
|
#if U_PLATFORM_HAS_WINUWP_API == 1
|
|
// UWP doesn't allow access to getenv(), but we can call GetEnvironmentVariableW to do the same thing.
|
|
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
|
|
gJapaneseEraRules = EraRules::createInstance("japanese", includeTentativeEra, 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);
|
|
}
|
|
|
|
/* Some platforms don't like to export constants, like old Palm OS and some z/OS configurations. */
|
|
uint32_t JapaneseCalendar::getCurrentEra() {
|
|
return gCurrentEra;
|
|
}
|
|
|
|
JapaneseCalendar::JapaneseCalendar(const Locale& aLocale, UErrorCode& success)
|
|
: GregorianCalendar(aLocale, success)
|
|
{
|
|
init(success);
|
|
setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
|
|
}
|
|
|
|
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();
|
|
// TODO do we assume we can trust 'era'? What if it is denormalized?
|
|
|
|
int32_t month = 0;
|
|
|
|
// Find out if we are at the edge of an era
|
|
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]) {
|
|
// Yes, we're in the first year of this era.
|
|
return eraStart[1] // month
|
|
-1; // return 0-based month
|
|
}
|
|
|
|
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()
|
|
{
|
|
// EXTENDED_YEAR in JapaneseCalendar is a Gregorian year
|
|
// The default value of EXTENDED_YEAR is 1970 (Showa 45)
|
|
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));
|
|
|
|
// extended year is a gregorian year, where 1 = 1AD, 0 = 1BC, -1 = 2BC, etc
|
|
year = internalGet(UCAL_YEAR, 1) // pin to minimum of year 1 (first year)
|
|
+ eraStartYear // add gregorian starting year
|
|
- 1; // Subtract one because year starts at 1
|
|
}
|
|
return year;
|
|
}
|
|
|
|
|
|
void JapaneseCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status)
|
|
{
|
|
//Calendar::timeToFields(theTime, quick, status);
|
|
GregorianCalendar::handleComputeFields(julianDay, status);
|
|
int32_t year = internalGet(UCAL_EXTENDED_YEAR); // Gregorian 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);
|
|
}
|
|
|
|
/*
|
|
Disable pivoting
|
|
*/
|
|
UBool JapaneseCalendar::haveDefaultCentury() const
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
UDate JapaneseCalendar::defaultCenturyStart() const
|
|
{
|
|
return 0;// WRONG
|
|
}
|
|
|
|
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 gCurrentEra;
|
|
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: //added to avoid warning
|
|
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; // Error condition, invalid limitType
|
|
}
|
|
}
|
|
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; // error case... any value
|
|
}
|
|
if (era == gCurrentEra) {
|
|
// TODO: Investigate what value should be used here - revisit after 4.0.
|
|
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]; // 1-base
|
|
int32_t nextEraDate = nextEraStart[2];
|
|
|
|
int32_t eraStartYear = gJapaneseEraRules->getStartYear(era, status);
|
|
int32_t maxYear = nextEraYear - eraStartYear + 1; // 1-base
|
|
if (nextEraMonth == 1 && nextEraDate == 1) {
|
|
// Subtract 1, because the next era starts at Jan 1
|
|
maxYear--;
|
|
}
|
|
return maxYear;
|
|
}
|
|
}
|
|
return GregorianCalendar::getActualMaximum(field, status);
|
|
}
|
|
|
|
U_NAMESPACE_END
|
|
|
|
#endif
|