dangical.cpp (5485B)
1 // © 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 /* 4 ****************************************************************************** 5 * Copyright (C) 2013, International Business Machines Corporation 6 * and others. All Rights Reserved. 7 ****************************************************************************** 8 * 9 * File DANGICAL.CPP 10 ***************************************************************************** 11 */ 12 13 #include "chnsecal.h" 14 #include "dangical.h" 15 16 #if !UCONFIG_NO_FORMATTING 17 18 #include "astro.h" // CalendarCache 19 #include "gregoimp.h" // Math 20 #include "uassert.h" 21 #include "ucln_in.h" 22 #include "umutex.h" 23 #include "unicode/rbtz.h" 24 #include "unicode/tzrule.h" 25 26 // --- The cache -- 27 // Lazy Creation & Access synchronized by class CalendarCache with a mutex. 28 static icu::CalendarCache *gWinterSolsticeCache = nullptr; 29 static icu::CalendarCache *gNewYearCache = nullptr; 30 31 // gAstronomerTimeZone 32 static icu::TimeZone *gAstronomerTimeZone = nullptr; 33 static icu::UInitOnce gAstronomerTimeZoneInitOnce {}; 34 35 U_CDECL_BEGIN 36 static UBool calendar_dangi_cleanup() { 37 if (gWinterSolsticeCache) { 38 delete gWinterSolsticeCache; 39 gWinterSolsticeCache = nullptr; 40 } 41 if (gNewYearCache) { 42 delete gNewYearCache; 43 gNewYearCache = nullptr; 44 } 45 46 if (gAstronomerTimeZone) { 47 delete gAstronomerTimeZone; 48 gAstronomerTimeZone = nullptr; 49 } 50 gAstronomerTimeZoneInitOnce.reset(); 51 return true; 52 } 53 U_CDECL_END 54 55 U_NAMESPACE_BEGIN 56 57 // Implementation of the DangiCalendar class 58 59 //------------------------------------------------------------------------- 60 // Constructors... 61 //------------------------------------------------------------------------- 62 63 const TimeZone* getAstronomerTimeZone(UErrorCode &status); 64 65 DangiCalendar::DangiCalendar(const Locale& aLocale, UErrorCode& success) 66 : ChineseCalendar(aLocale, success) 67 { 68 } 69 70 DangiCalendar::DangiCalendar (const DangiCalendar& other) 71 : ChineseCalendar(other) 72 { 73 } 74 75 DangiCalendar::~DangiCalendar() 76 { 77 } 78 79 DangiCalendar* 80 DangiCalendar::clone() const 81 { 82 return new DangiCalendar(*this); 83 } 84 85 const char *DangiCalendar::getType() const { 86 return "dangi"; 87 } 88 89 /** 90 * The time zone used for performing astronomical computations for 91 * Dangi calendar. In Korea various timezones have been used historically 92 * (cf. http://www.math.snu.ac.kr/~kye/others/lunar.html): 93 * 94 * - 1908/04/01: GMT+8 95 * 1908/04/01 - 1911/12/31: GMT+8.5 96 * 1912/01/01 - 1954/03/20: GMT+9 97 * 1954/03/21 - 1961/08/09: GMT+8.5 98 * 1961/08/10 - : GMT+9 99 * 100 * Note that, in 1908-1911, the government did not apply the timezone change 101 * but used GMT+8. In addition, 1954-1961's timezone change does not affect 102 * the lunar date calculation. Therefore, the following simpler rule works: 103 * 104 * -1911: GMT+8 105 * 1912-: GMT+9 106 * 107 * Unfortunately, our astronomer's approximation doesn't agree with the 108 * references (http://www.math.snu.ac.kr/~kye/others/lunar.html and 109 * http://astro.kasi.re.kr/Life/ConvertSolarLunarForm.aspx?MenuID=115) 110 * in 1897/7/30. So the following ad hoc fix is used here: 111 * 112 * -1896: GMT+8 113 * 1897: GMT+7 114 * 1898-1911: GMT+8 115 * 1912- : GMT+9 116 */ 117 static void U_CALLCONV initAstronomerTimeZone(UErrorCode &status) { 118 U_ASSERT(gAstronomerTimeZone == nullptr); 119 const UDate millis1897[] = { static_cast<UDate>((1897 - 1970) * 365 * kOneDay) }; // some days of error is not a problem here 120 const UDate millis1898[] = { static_cast<UDate>((1898 - 1970) * 365 * kOneDay) }; // some days of error is not a problem here 121 const UDate millis1912[] = { static_cast<UDate>((1912 - 1970) * 365 * kOneDay) }; // this doesn't create an issue for 1911/12/20 122 LocalPointer<InitialTimeZoneRule> initialTimeZone(new InitialTimeZoneRule( 123 UnicodeString(u"GMT+8"), 8*kOneHour, 0), status); 124 125 LocalPointer<TimeZoneRule> rule1897(new TimeArrayTimeZoneRule( 126 UnicodeString(u"Korean 1897"), 7*kOneHour, 0, millis1897, 1, DateTimeRule::STANDARD_TIME), status); 127 128 LocalPointer<TimeZoneRule> rule1898to1911(new TimeArrayTimeZoneRule( 129 UnicodeString(u"Korean 1898-1911"), 8*kOneHour, 0, millis1898, 1, DateTimeRule::STANDARD_TIME), status); 130 131 LocalPointer<TimeZoneRule> ruleFrom1912(new TimeArrayTimeZoneRule( 132 UnicodeString(u"Korean 1912-"), 9*kOneHour, 0, millis1912, 1, DateTimeRule::STANDARD_TIME), status); 133 134 LocalPointer<RuleBasedTimeZone> zone(new RuleBasedTimeZone( 135 UnicodeString(u"KOREA_ZONE"), initialTimeZone.orphan()), status); // adopts initialTimeZone 136 137 if (U_FAILURE(status)) { 138 return; 139 } 140 zone->addTransitionRule(rule1897.orphan(), status); // adopts rule1897 141 zone->addTransitionRule(rule1898to1911.orphan(), status); 142 zone->addTransitionRule(ruleFrom1912.orphan(), status); 143 zone->complete(status); 144 if (U_SUCCESS(status)) { 145 gAstronomerTimeZone = zone.orphan(); 146 } 147 ucln_i18n_registerCleanup(UCLN_I18N_DANGI_CALENDAR, calendar_dangi_cleanup); 148 } 149 150 const TimeZone* getAstronomerTimeZone(UErrorCode &status) { 151 umtx_initOnce(gAstronomerTimeZoneInitOnce, &initAstronomerTimeZone, status); 152 return gAstronomerTimeZone; 153 } 154 155 ChineseCalendar::Setting DangiCalendar::getSetting(UErrorCode& status) const { 156 return { 157 getAstronomerTimeZone(status), 158 &gWinterSolsticeCache, &gNewYearCache 159 }; 160 } 161 162 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DangiCalendar) 163 164 U_NAMESPACE_END 165 166 #endif