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 - 2013, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 *******************************************************************************
8 */
9 
10 #include "unicode/utypes.h"
11 
12 #if !UCONFIG_NO_FORMATTING
13 
14 #include "umutex.h"
15 #include "ethpccal.h"
16 #include "cecal.h"
17 #include <float.h>
18 
19 U_NAMESPACE_BEGIN
20 
21 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(EthiopicCalendar)
22 
23 //static const int32_t JD_EPOCH_OFFSET_AMETE_ALEM = -285019;
24 static const int32_t JD_EPOCH_OFFSET_AMETE_MIHRET = 1723856;
25 static const int32_t AMETE_MIHRET_DELTA = 5500; // 5501 - 1 (Amete Alem 5501 = Amete Mihret 1)
26 
27 //-------------------------------------------------------------------------
28 // Constructors...
29 //-------------------------------------------------------------------------
30 
31 EthiopicCalendar::EthiopicCalendar(const Locale& aLocale,
32                                    UErrorCode& success,
33                                    EEraType type /*= AMETE_MIHRET_ERA*/)
34 :   CECalendar(aLocale, success),
35     eraType(type)
36 {
37 }
38 
39 EthiopicCalendar::EthiopicCalendar(const EthiopicCalendar& other)
40 :   CECalendar(other),
41     eraType(other.eraType)
42 {
43 }
44 
45 EthiopicCalendar::~EthiopicCalendar()
46 {
47 }
48 
49 Calendar*
50 EthiopicCalendar::clone() const
51 {
52     return new EthiopicCalendar(*this);
53 }
54 
55 const char *
56 EthiopicCalendar::getType() const
57 {
58     if (isAmeteAlemEra()) {
59         return "ethiopic-amete-alem";
60     }
61     return "ethiopic";
62 }
63 
64 void
65 EthiopicCalendar::setAmeteAlemEra(UBool onOff)
66 {
67     eraType = onOff ? AMETE_ALEM_ERA : AMETE_MIHRET_ERA;
68 }
69 
70 UBool
71 EthiopicCalendar::isAmeteAlemEra() const
72 {
73     return (eraType == AMETE_ALEM_ERA);
74 }
75 
76 //-------------------------------------------------------------------------
77 // Calendar framework
78 //-------------------------------------------------------------------------
79 
80 int32_t
81 EthiopicCalendar::handleGetExtendedYear()
82 {
83     // Ethiopic calendar uses EXTENDED_YEAR aligned to
84     // Amelete Hihret year always.
85     int32_t eyear;
86     if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
87         eyear = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
88     } else if (isAmeteAlemEra()) {
89         eyear = internalGet(UCAL_YEAR, 1 + AMETE_MIHRET_DELTA)
90             - AMETE_MIHRET_DELTA; // Default to year 1 of Amelete Mihret
91     } else {
92         // The year defaults to the epoch start, the era to AMETE_MIHRET
93         int32_t era = internalGet(UCAL_ERA, AMETE_MIHRET);
94         if (era == AMETE_MIHRET) {
95             eyear = internalGet(UCAL_YEAR, 1); // Default to year 1
96         } else {
97             eyear = internalGet(UCAL_YEAR, 1) - AMETE_MIHRET_DELTA;
98         }
99     }
100     return eyear;
101 }
102 
103 void
104 EthiopicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &/*status*/)
105 {
106     int32_t eyear, month, day, era, year;
107     jdToCE(julianDay, getJDEpochOffset(), eyear, month, day);
108 
109     if (isAmeteAlemEra()) {
110         era = AMETE_ALEM;
111         year = eyear + AMETE_MIHRET_DELTA;
112     } else {
113         if (eyear > 0) {
114             era = AMETE_MIHRET;
115             year = eyear;
116         } else {
117             era = AMETE_ALEM;
118             year = eyear + AMETE_MIHRET_DELTA;
119         }
120     }
121 
122     internalSet(UCAL_EXTENDED_YEAR, eyear);
123     internalSet(UCAL_ERA, era);
124     internalSet(UCAL_YEAR, year);
125     internalSet(UCAL_MONTH, month);
126     internalSet(UCAL_DATE, day);
127     internalSet(UCAL_DAY_OF_YEAR, (30 * month) + day);
128 }
129 
130 int32_t
131 EthiopicCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const
132 {
133     if (isAmeteAlemEra() && field == UCAL_ERA) {
134         return 0; // Only one era in this mode, era is always 0
135     }
136     return CECalendar::handleGetLimit(field, limitType);
137 }
138 
139 /**
140  * The system maintains a static default century start date and Year.  They are
141  * initialized the first time they are used.  Once the system default century date
142  * and year are set, they do not change.
143  */
144 static UDate           gSystemDefaultCenturyStart       = DBL_MIN;
145 static int32_t         gSystemDefaultCenturyStartYear   = -1;
146 static icu::UInitOnce  gSystemDefaultCenturyInit        = U_INITONCE_INITIALIZER;
147 
148 static void U_CALLCONV initializeSystemDefaultCentury()
149 {
150     UErrorCode status = U_ZERO_ERROR;
151     EthiopicCalendar calendar(Locale("@calendar=ethiopic"), status);
152     if (U_SUCCESS(status)) {
153         calendar.setTime(Calendar::getNow(), status);
154         calendar.add(UCAL_YEAR, -80, status);
155 
156         gSystemDefaultCenturyStart = calendar.getTime(status);
157         gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status);
158     }
159     // We have no recourse upon failure unless we want to propagate the failure
160     // out.
161 }
162 
163 UDate
164 EthiopicCalendar::defaultCenturyStart() const
165 {
166     // lazy-evaluate systemDefaultCenturyStart
167     umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
168     return gSystemDefaultCenturyStart;
169 }
170 
171 int32_t
172 EthiopicCalendar::defaultCenturyStartYear() const
173 {
174     // lazy-evaluate systemDefaultCenturyStartYear
175     umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
176     if (isAmeteAlemEra()) {
177         return gSystemDefaultCenturyStartYear + AMETE_MIHRET_DELTA;
178     }
179     return gSystemDefaultCenturyStartYear;
180 }
181 
182 
183 int32_t
184 EthiopicCalendar::getJDEpochOffset() const
185 {
186     return JD_EPOCH_OFFSET_AMETE_MIHRET;
187 }
188 
189 
190 #if 0
191 // We do not want to introduce this API in ICU4C.
192 // It was accidentally introduced in ICU4J as a public API.
193 
194 //-------------------------------------------------------------------------
195 // Calendar system Conversion methods...
196 //-------------------------------------------------------------------------
197 
198 int32_t
199 EthiopicCalendar::ethiopicToJD(int32_t year, int32_t month, int32_t date)
200 {
201     return ceToJD(year, month, date, JD_EPOCH_OFFSET_AMETE_MIHRET);
202 }
203 #endif
204 
205 U_NAMESPACE_END
206 
207 #endif
208