Line data Source code
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 "gregoimp.h" // Math
19 : #include "uassert.h"
20 : #include "ucln_in.h"
21 : #include "umutex.h"
22 : #include "unicode/rbtz.h"
23 : #include "unicode/tzrule.h"
24 :
25 : // --- The cache --
26 : static icu::TimeZone *gDangiCalendarZoneAstroCalc = NULL;
27 : static icu::UInitOnce gDangiCalendarInitOnce = U_INITONCE_INITIALIZER;
28 :
29 : /**
30 : * The start year of the Korean traditional calendar (Dan-gi) is the inaugural
31 : * year of Dan-gun (BC 2333).
32 : */
33 : static const int32_t DANGI_EPOCH_YEAR = -2332; // Gregorian year
34 :
35 : U_CDECL_BEGIN
36 0 : static UBool calendar_dangi_cleanup(void) {
37 0 : if (gDangiCalendarZoneAstroCalc) {
38 0 : delete gDangiCalendarZoneAstroCalc;
39 0 : gDangiCalendarZoneAstroCalc = NULL;
40 : }
41 0 : gDangiCalendarInitOnce.reset();
42 0 : return TRUE;
43 : }
44 : U_CDECL_END
45 :
46 : U_NAMESPACE_BEGIN
47 :
48 : // Implementation of the DangiCalendar class
49 :
50 : //-------------------------------------------------------------------------
51 : // Constructors...
52 : //-------------------------------------------------------------------------
53 :
54 0 : DangiCalendar::DangiCalendar(const Locale& aLocale, UErrorCode& success)
55 0 : : ChineseCalendar(aLocale, DANGI_EPOCH_YEAR, getDangiCalZoneAstroCalc(), success)
56 : {
57 0 : }
58 :
59 0 : DangiCalendar::DangiCalendar (const DangiCalendar& other)
60 0 : : ChineseCalendar(other)
61 : {
62 0 : }
63 :
64 0 : DangiCalendar::~DangiCalendar()
65 : {
66 0 : }
67 :
68 : Calendar*
69 0 : DangiCalendar::clone() const
70 : {
71 0 : return new DangiCalendar(*this);
72 : }
73 :
74 0 : const char *DangiCalendar::getType() const {
75 0 : return "dangi";
76 : }
77 :
78 : /**
79 : * The time zone used for performing astronomical computations for
80 : * Dangi calendar. In Korea various timezones have been used historically
81 : * (cf. http://www.math.snu.ac.kr/~kye/others/lunar.html):
82 : *
83 : * - 1908/04/01: GMT+8
84 : * 1908/04/01 - 1911/12/31: GMT+8.5
85 : * 1912/01/01 - 1954/03/20: GMT+9
86 : * 1954/03/21 - 1961/08/09: GMT+8.5
87 : * 1961/08/10 - : GMT+9
88 : *
89 : * Note that, in 1908-1911, the government did not apply the timezone change
90 : * but used GMT+8. In addition, 1954-1961's timezone change does not affect
91 : * the lunar date calculation. Therefore, the following simpler rule works:
92 : *
93 : * -1911: GMT+8
94 : * 1912-: GMT+9
95 : *
96 : * Unfortunately, our astronomer's approximation doesn't agree with the
97 : * references (http://www.math.snu.ac.kr/~kye/others/lunar.html and
98 : * http://astro.kasi.re.kr/Life/ConvertSolarLunarForm.aspx?MenuID=115)
99 : * in 1897/7/30. So the following ad hoc fix is used here:
100 : *
101 : * -1896: GMT+8
102 : * 1897: GMT+7
103 : * 1898-1911: GMT+8
104 : * 1912- : GMT+9
105 : */
106 0 : static void U_CALLCONV initDangiCalZoneAstroCalc(void) {
107 0 : U_ASSERT(gDangiCalendarZoneAstroCalc == NULL);
108 0 : const UDate millis1897[] = { (UDate)((1897 - 1970) * 365 * kOneDay) }; // some days of error is not a problem here
109 0 : const UDate millis1898[] = { (UDate)((1898 - 1970) * 365 * kOneDay) }; // some days of error is not a problem here
110 0 : const UDate millis1912[] = { (UDate)((1912 - 1970) * 365 * kOneDay) }; // this doesn't create an issue for 1911/12/20
111 0 : InitialTimeZoneRule* initialTimeZone = new InitialTimeZoneRule(UNICODE_STRING_SIMPLE("GMT+8"), 8*kOneHour, 0);
112 0 : TimeZoneRule* rule1897 = new TimeArrayTimeZoneRule(UNICODE_STRING_SIMPLE("Korean 1897"), 7*kOneHour, 0, millis1897, 1, DateTimeRule::STANDARD_TIME);
113 0 : TimeZoneRule* rule1898to1911 = new TimeArrayTimeZoneRule(UNICODE_STRING_SIMPLE("Korean 1898-1911"), 8*kOneHour, 0, millis1898, 1, DateTimeRule::STANDARD_TIME);
114 0 : TimeZoneRule* ruleFrom1912 = new TimeArrayTimeZoneRule(UNICODE_STRING_SIMPLE("Korean 1912-"), 9*kOneHour, 0, millis1912, 1, DateTimeRule::STANDARD_TIME);
115 0 : UErrorCode status = U_ZERO_ERROR;
116 0 : RuleBasedTimeZone* dangiCalZoneAstroCalc = new RuleBasedTimeZone(UNICODE_STRING_SIMPLE("KOREA_ZONE"), initialTimeZone); // adopts initialTimeZone
117 0 : dangiCalZoneAstroCalc->addTransitionRule(rule1897, status); // adopts rule1897
118 0 : dangiCalZoneAstroCalc->addTransitionRule(rule1898to1911, status);
119 0 : dangiCalZoneAstroCalc->addTransitionRule(ruleFrom1912, status);
120 0 : dangiCalZoneAstroCalc->complete(status);
121 0 : if (U_SUCCESS(status)) {
122 0 : gDangiCalendarZoneAstroCalc = dangiCalZoneAstroCalc;
123 : } else {
124 0 : delete dangiCalZoneAstroCalc;
125 0 : gDangiCalendarZoneAstroCalc = NULL;
126 : }
127 0 : ucln_i18n_registerCleanup(UCLN_I18N_DANGI_CALENDAR, calendar_dangi_cleanup);
128 0 : }
129 :
130 0 : const TimeZone* DangiCalendar::getDangiCalZoneAstroCalc(void) const {
131 0 : umtx_initOnce(gDangiCalendarInitOnce, &initDangiCalZoneAstroCalc);
132 0 : return gDangiCalendarZoneAstroCalc;
133 : }
134 :
135 :
136 0 : UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DangiCalendar)
137 :
138 : U_NAMESPACE_END
139 :
140 : #endif
141 :
|