japancal.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  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. #include "unicode/utypes.h"
  16. #if !UCONFIG_NO_FORMATTING
  17. #if U_PLATFORM_HAS_WINUWP_API == 0
  18. #include <stdlib.h> // getenv() is not available in UWP env
  19. #else
  20. #ifndef WIN32_LEAN_AND_MEAN
  21. # define WIN32_LEAN_AND_MEAN
  22. #endif
  23. # define VC_EXTRALEAN
  24. # define NOUSER
  25. # define NOSERVICE
  26. # define NOIME
  27. # define NOMCX
  28. #include <windows.h>
  29. #endif
  30. #include "cmemory.h"
  31. #include "erarules.h"
  32. #include "japancal.h"
  33. #include "unicode/gregocal.h"
  34. #include "umutex.h"
  35. #include "uassert.h"
  36. #include "ucln_in.h"
  37. #include "cstring.h"
  38. static icu::EraRules * gJapaneseEraRules = nullptr;
  39. static icu::UInitOnce gJapaneseEraRulesInitOnce {};
  40. static int32_t gCurrentEra = 0;
  41. U_CDECL_BEGIN
  42. static UBool japanese_calendar_cleanup() {
  43. if (gJapaneseEraRules) {
  44. delete gJapaneseEraRules;
  45. gJapaneseEraRules = nullptr;
  46. }
  47. gCurrentEra = 0;
  48. gJapaneseEraRulesInitOnce.reset();
  49. return true;
  50. }
  51. U_CDECL_END
  52. U_NAMESPACE_BEGIN
  53. UOBJECT_DEFINE_RTTI_IMPLEMENTATION(JapaneseCalendar)
  54. static const int32_t kGregorianEpoch = 1970; // used as the default value of EXTENDED_YEAR
  55. static const char* TENTATIVE_ERA_VAR_NAME = "ICU_ENABLE_TENTATIVE_ERA";
  56. // Export the following for use by test code.
  57. UBool JapaneseCalendar::enableTentativeEra() {
  58. // Although start date of next Japanese era is planned ahead, a name of
  59. // new era might not be available. This implementation allows tester to
  60. // check a new era without era names by settings below (in priority order).
  61. // By default, such tentative era is disabled.
  62. // 1. Environment variable ICU_ENABLE_TENTATIVE_ERA=true or false
  63. UBool includeTentativeEra = false;
  64. #if U_PLATFORM_HAS_WINUWP_API == 1
  65. // UWP doesn't allow access to getenv(), but we can call GetEnvironmentVariableW to do the same thing.
  66. char16_t varName[26] = {};
  67. u_charsToUChars(TENTATIVE_ERA_VAR_NAME, varName, static_cast<int32_t>(uprv_strlen(TENTATIVE_ERA_VAR_NAME)));
  68. WCHAR varValue[5] = {};
  69. DWORD ret = GetEnvironmentVariableW(reinterpret_cast<WCHAR*>(varName), varValue, UPRV_LENGTHOF(varValue));
  70. if ((ret == 4) && (_wcsicmp(varValue, L"true") == 0)) {
  71. includeTentativeEra = true;
  72. }
  73. #else
  74. char *envVarVal = getenv(TENTATIVE_ERA_VAR_NAME);
  75. if (envVarVal != nullptr && uprv_stricmp(envVarVal, "true") == 0) {
  76. includeTentativeEra = true;
  77. }
  78. #endif
  79. return includeTentativeEra;
  80. }
  81. // Initialize global Japanese era data
  82. static void U_CALLCONV initializeEras(UErrorCode &status) {
  83. gJapaneseEraRules = EraRules::createInstance("japanese", JapaneseCalendar::enableTentativeEra(), status);
  84. if (U_FAILURE(status)) {
  85. return;
  86. }
  87. gCurrentEra = gJapaneseEraRules->getCurrentEraIndex();
  88. }
  89. static void init(UErrorCode &status) {
  90. umtx_initOnce(gJapaneseEraRulesInitOnce, &initializeEras, status);
  91. ucln_i18n_registerCleanup(UCLN_I18N_JAPANESE_CALENDAR, japanese_calendar_cleanup);
  92. }
  93. /* Some platforms don't like to export constants, like old Palm OS and some z/OS configurations. */
  94. uint32_t JapaneseCalendar::getCurrentEra() {
  95. return gCurrentEra;
  96. }
  97. JapaneseCalendar::JapaneseCalendar(const Locale& aLocale, UErrorCode& success)
  98. : GregorianCalendar(aLocale, success)
  99. {
  100. init(success);
  101. setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
  102. }
  103. JapaneseCalendar::~JapaneseCalendar()
  104. {
  105. }
  106. JapaneseCalendar::JapaneseCalendar(const JapaneseCalendar& source)
  107. : GregorianCalendar(source)
  108. {
  109. UErrorCode status = U_ZERO_ERROR;
  110. init(status);
  111. U_ASSERT(U_SUCCESS(status));
  112. }
  113. JapaneseCalendar& JapaneseCalendar::operator= ( const JapaneseCalendar& right)
  114. {
  115. GregorianCalendar::operator=(right);
  116. return *this;
  117. }
  118. JapaneseCalendar* JapaneseCalendar::clone() const
  119. {
  120. return new JapaneseCalendar(*this);
  121. }
  122. const char *JapaneseCalendar::getType() const
  123. {
  124. return "japanese";
  125. }
  126. int32_t JapaneseCalendar::getDefaultMonthInYear(int32_t eyear)
  127. {
  128. int32_t era = internalGetEra();
  129. // TODO do we assume we can trust 'era'? What if it is denormalized?
  130. int32_t month = 0;
  131. // Find out if we are at the edge of an era
  132. int32_t eraStart[3] = { 0,0,0 };
  133. UErrorCode status = U_ZERO_ERROR;
  134. gJapaneseEraRules->getStartDate(era, eraStart, status);
  135. U_ASSERT(U_SUCCESS(status));
  136. if(eyear == eraStart[0]) {
  137. // Yes, we're in the first year of this era.
  138. return eraStart[1] // month
  139. -1; // return 0-based month
  140. }
  141. return month;
  142. }
  143. int32_t JapaneseCalendar::getDefaultDayInMonth(int32_t eyear, int32_t month)
  144. {
  145. int32_t era = internalGetEra();
  146. int32_t day = 1;
  147. int32_t eraStart[3] = { 0,0,0 };
  148. UErrorCode status = U_ZERO_ERROR;
  149. gJapaneseEraRules->getStartDate(era, eraStart, status);
  150. U_ASSERT(U_SUCCESS(status));
  151. if(eyear == eraStart[0]) {
  152. if(month == eraStart[1] - 1) {
  153. return eraStart[2];
  154. }
  155. }
  156. return day;
  157. }
  158. int32_t JapaneseCalendar::internalGetEra() const
  159. {
  160. return internalGet(UCAL_ERA, gCurrentEra);
  161. }
  162. int32_t JapaneseCalendar::handleGetExtendedYear()
  163. {
  164. // EXTENDED_YEAR in JapaneseCalendar is a Gregorian year
  165. // The default value of EXTENDED_YEAR is 1970 (Showa 45)
  166. int32_t year;
  167. if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR &&
  168. newerField(UCAL_EXTENDED_YEAR, UCAL_ERA) == UCAL_EXTENDED_YEAR) {
  169. year = internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch);
  170. } else {
  171. UErrorCode status = U_ZERO_ERROR;
  172. int32_t eraStartYear = gJapaneseEraRules->getStartYear(internalGet(UCAL_ERA, gCurrentEra), status);
  173. U_ASSERT(U_SUCCESS(status));
  174. // extended year is a gregorian year, where 1 = 1AD, 0 = 1BC, -1 = 2BC, etc
  175. year = internalGet(UCAL_YEAR, 1) // pin to minimum of year 1 (first year)
  176. + eraStartYear // add gregorian starting year
  177. - 1; // Subtract one because year starts at 1
  178. }
  179. return year;
  180. }
  181. void JapaneseCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status)
  182. {
  183. //Calendar::timeToFields(theTime, quick, status);
  184. GregorianCalendar::handleComputeFields(julianDay, status);
  185. int32_t year = internalGet(UCAL_EXTENDED_YEAR); // Gregorian year
  186. int32_t eraIdx = gJapaneseEraRules->getEraIndex(year, internalGetMonth() + 1, internalGet(UCAL_DAY_OF_MONTH), status);
  187. internalSet(UCAL_ERA, eraIdx);
  188. internalSet(UCAL_YEAR, year - gJapaneseEraRules->getStartYear(eraIdx, status) + 1);
  189. }
  190. /*
  191. Disable pivoting
  192. */
  193. UBool JapaneseCalendar::haveDefaultCentury() const
  194. {
  195. return false;
  196. }
  197. UDate JapaneseCalendar::defaultCenturyStart() const
  198. {
  199. return 0;// WRONG
  200. }
  201. int32_t JapaneseCalendar::defaultCenturyStartYear() const
  202. {
  203. return 0;
  204. }
  205. int32_t JapaneseCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const
  206. {
  207. switch(field) {
  208. case UCAL_ERA:
  209. if (limitType == UCAL_LIMIT_MINIMUM || limitType == UCAL_LIMIT_GREATEST_MINIMUM) {
  210. return 0;
  211. }
  212. return gJapaneseEraRules->getNumberOfEras() - 1; // max known era, not gCurrentEra
  213. case UCAL_YEAR:
  214. {
  215. switch (limitType) {
  216. case UCAL_LIMIT_MINIMUM:
  217. case UCAL_LIMIT_GREATEST_MINIMUM:
  218. return 1;
  219. case UCAL_LIMIT_LEAST_MAXIMUM:
  220. return 1;
  221. case UCAL_LIMIT_COUNT: //added to avoid warning
  222. case UCAL_LIMIT_MAXIMUM:
  223. {
  224. UErrorCode status = U_ZERO_ERROR;
  225. int32_t eraStartYear = gJapaneseEraRules->getStartYear(gCurrentEra, status);
  226. U_ASSERT(U_SUCCESS(status));
  227. return GregorianCalendar::handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM) - eraStartYear;
  228. }
  229. default:
  230. return 1; // Error condition, invalid limitType
  231. }
  232. }
  233. default:
  234. return GregorianCalendar::handleGetLimit(field,limitType);
  235. }
  236. }
  237. int32_t JapaneseCalendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const {
  238. if (field == UCAL_YEAR) {
  239. int32_t era = get(UCAL_ERA, status);
  240. if (U_FAILURE(status)) {
  241. return 0; // error case... any value
  242. }
  243. if (era == gJapaneseEraRules->getNumberOfEras() - 1) { // max known era, not gCurrentEra
  244. // TODO: Investigate what value should be used here - revisit after 4.0.
  245. return handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM);
  246. } else {
  247. int32_t nextEraStart[3] = { 0,0,0 };
  248. gJapaneseEraRules->getStartDate(era + 1, nextEraStart, status);
  249. int32_t nextEraYear = nextEraStart[0];
  250. int32_t nextEraMonth = nextEraStart[1]; // 1-base
  251. int32_t nextEraDate = nextEraStart[2];
  252. int32_t eraStartYear = gJapaneseEraRules->getStartYear(era, status);
  253. int32_t maxYear = nextEraYear - eraStartYear + 1; // 1-base
  254. if (nextEraMonth == 1 && nextEraDate == 1) {
  255. // Subtract 1, because the next era starts at Jan 1
  256. maxYear--;
  257. }
  258. return maxYear;
  259. }
  260. }
  261. return GregorianCalendar::getActualMaximum(field, status);
  262. }
  263. U_NAMESPACE_END
  264. #endif