Refactory NumberFormatter.
[platform/framework/native/appfw.git] / src / locales / FLclGregorianCalendar.cpp
1 //
2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Apache License, Version 2.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 /**
18 * @file         FLclGregorianCalendar.cpp
19 * @brief        This is the implementation file for GregorianCalendar class.
20 */
21
22 #include <unique_ptr.h>
23
24 #include <FBaseDateTime.h>
25 #include <FBaseSysLog.h>
26 #include <FLclGregorianCalendar.h>
27 #include "FLcl_CalendarImpl.h"
28 #include "FLcl_LocaleManagerImpl.h"
29
30 using namespace Tizen::Base;
31
32 namespace Tizen { namespace Locales
33 {
34
35 //////////////////////////////////////////////////////////////////////////////////
36 // Set monthLength[]
37 const int GregorianCalendar::MONTH_LENGTH[24] =
38 {
39         31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,                             // Days in month in normal year
40         31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31                              // Days in month in leap year
41 };
42
43 // Set cumulative number of days at first day of month
44 const int GregorianCalendar::NUM_DAYS[24] =
45 {
46         0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,       // Cumulative number of days at first day of month in normal year
47         0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335        // Cumulative number of days at first day of month in leap year
48 };
49
50 GregorianCalendar::GregorianCalendar(void)
51         : __normalizedGregorianCutover(DEFAULT_GREGORIAN_CUTOVER)
52         , __gregorianCutoverYear(1582)
53         , __cutoverJulianDay(GregorianCalendar::CUTOVER_JULIAN_DAY)
54         , __pGregorianCalendarImpl(null)
55 {
56 }
57
58 GregorianCalendar::~GregorianCalendar(void)
59 {
60         delete _pCalendarImpl;
61         _pCalendarImpl = null;
62 }
63
64 // This method is copy constructor
65 result
66 GregorianCalendar::Construct(const GregorianCalendar& gc)
67 {
68         // Object is not allowed to construct twice
69         SysAssertf(_pCalendarImpl == null,
70                 "Already constructed! Calling Construct() twice or more on a same instance is not allowed for this class");
71
72         if (gc._pCalendarImpl != null)
73         {
74                 std::unique_ptr< Calendar > pCalendar(gc._pCalendarImpl->CloneN());
75                 SysTryReturnResult(NID_LCL, pCalendar != null, E_OUT_OF_MEMORY, "Memory allocation failed");
76
77                 _pCalendarImpl = dynamic_cast< _CalendarImpl* >(pCalendar.get());
78                 if (_pCalendarImpl != null)
79                 {
80                         pCalendar.release();
81
82                         __cutoverJulianDay = gc.__cutoverJulianDay;
83                         __normalizedGregorianCutover = gc.__normalizedGregorianCutover;
84                         __gregorianCutoverYear = gc.__gregorianCutoverYear;
85                 }
86         }
87
88         return E_SUCCESS;
89 }
90
91 result
92 GregorianCalendar::Construct(void)
93 {
94         return Construct(TimeZone::GetGmtTimeZone(), _LocaleManagerImpl::GetSystemLocale());
95 }
96
97 result
98 GregorianCalendar::Construct(const TimeZone& timezone)
99 {
100         return Construct(timezone, _LocaleManagerImpl::GetSystemLocale());
101 }
102
103 result
104 GregorianCalendar::Construct(const Locale& locale)
105 {
106         return Construct(TimeZone::GetGmtTimeZone(), locale);
107 }
108
109 result
110 GregorianCalendar::Construct(const TimeZone& timezone, const Locale& locale)
111 {
112         // Object is not allowed to construct twice
113         SysAssertf(_pCalendarImpl == null,
114                 "Already constructed! Calling Construct() twice or more on a same instance is not allowed for this class");
115
116         std::unique_ptr< _CalendarImpl > pCalendarImpl(new (std::nothrow) _CalendarImpl);
117         SysTryReturnResult(NID_LCL, pCalendarImpl != null, E_OUT_OF_MEMORY, "Memory allocation failed");
118
119         result r = pCalendarImpl->Construct(timezone, locale);
120         if (!IsFailed(r))
121         {
122                 _pCalendarImpl = pCalendarImpl.release();
123
124                 SetGregorianChange(GetGregorianChange());
125                 return E_SUCCESS;
126         }
127
128         return r;
129 }
130
131 result
132 GregorianCalendar::Construct(int year, int month, int day, int hourOfDay, int minute, int second)
133 {
134         result r = Construct(TimeZone::GetGmtTimeZone(), _LocaleManagerImpl::GetSystemLocale());
135         if (!IsFailed(r))
136         {
137                 r = SetTime(year, month, day, hourOfDay, minute, second);
138         }
139         return r;
140 }
141
142 result
143 GregorianCalendar::Construct(const DateTime& dateTime)
144 {
145         return Construct(dateTime.GetYear(),
146                                          dateTime.GetMonth(),
147                                          dateTime.GetDay(),
148                                          dateTime.GetHour(),
149                                          dateTime.GetMinute(),
150                                          dateTime.GetSecond());
151 }
152
153 result
154 GregorianCalendar::AddTimeField(TimeField field, int amount)
155 {
156         SysAssertf(_pCalendarImpl != null, "Not yet constructed! Construct() should be called before use.");
157         return _pCalendarImpl->AddTimeField(field, amount);
158 }
159
160 void
161 GregorianCalendar::DayToFields(int day, int& year, int& month, int& dayOfMonth, int& dayOfWeek, int& dayOfYear)
162 {
163         _CalendarImpl calImpl;
164         result r = calImpl.Construct();
165         if (!IsFailed(r))
166         {
167                 r = calImpl.SetJulianDay(day + GregorianCalendar::EPOCH_START_AS_JULIAN_DAY);
168                 if (!IsFailed(r))
169                 {
170                         year = calImpl.GetTimeField(TIME_FIELD_YEAR);
171                         month = calImpl.GetTimeField(TIME_FIELD_MONTH);
172                         dayOfMonth = calImpl.GetTimeField(TIME_FIELD_DAY_OF_MONTH);
173                         dayOfWeek = calImpl.GetTimeField(TIME_FIELD_DAY_OF_WEEK);
174                         dayOfYear = calImpl.GetTimeField(TIME_FIELD_DAY_OF_YEAR);
175                 }
176         }
177 }
178
179 // This method gets the actual minimum value that a given field could have.
180 // For Gregorian calendar, it is the same as GetMinTimeField() and GetGreatestMinimum()
181 int
182 GregorianCalendar::GetActualMinTimeField(TimeField field) const
183 {
184         SysAssertf(_pCalendarImpl != null, "Not yet constructed! Construct() should be called before use.");
185         return _pCalendarImpl->GetActualMinTimeField(field);
186 }
187
188 //
189 // This method gets the actual maximum value that this field could have, given the current date.
190 // This method has a limitation (also GetActualMinimum). It will not behave properly at the extreme limits of Gregorian calendar's
191 // representable range.
192 // For calendars with the default Gregorian cutover, these limits are Sun Dec 02 16:47:04 GMT 292269055 BC to Sun
193 // Aug 17 07:12:55 GMT 292278994 AD, somewhat different for non-GMT zones.
194 // As a result, if the calendar is set to Aug 1 292278994 AD, the actual maximum of DAY_OF_MONTH is 17, not 30.
195 //
196 int
197 GregorianCalendar::GetActualMaxTimeField(TimeField field) const
198 {
199         SysAssertf(_pCalendarImpl != null, "Not yet constructed! Construct() should be called before use.");
200         return _pCalendarImpl->GetActualMaxTimeField(field);
201 }
202
203 //This method returns the Gregorian cutover.
204 long long
205 GregorianCalendar::GetGregorianChange(void) const
206 {
207         SysAssertf(_pCalendarImpl != null, "Not yet constructed! Construct() should be called before use.");
208         return _pCalendarImpl->GetGregorianChange();
209 }
210
211 CalendarType
212 GregorianCalendar::GetType(void) const
213 {
214         return CALENDAR_GREGORIAN;
215 }
216
217 result
218 GregorianCalendar::IsInDst(bool& isInDst) const
219 {
220         SysAssertf(_pCalendarImpl != null, "Not yet constructed! Construct() should be called before use.");
221         return _pCalendarImpl->IsInDst(isInDst);
222 }
223
224 bool
225 GregorianCalendar::IsLeapYear(int year) const
226 {
227         SysAssertf(_pCalendarImpl != null, "Not yet constructed! Construct() should be called before use.");
228         return _pCalendarImpl->IsLeapYear(year);
229 }
230
231 result
232 GregorianCalendar::Roll(TimeField field, int amount)
233 {
234         SysAssertf(_pCalendarImpl != null, "Not yet constructed! Construct() should be called before use.");
235         return _pCalendarImpl->Roll(field, amount);
236 }
237
238 result
239 GregorianCalendar::SetGregorianChange(long long change)
240 {
241         SysAssertf(_pCalendarImpl != null, "Not yet constructed! Construct() should be called before use.");
242
243         result r = E_SUCCESS;
244         if (_pCalendarImpl->GetGregorianChange() != change)
245         {
246                 r = _pCalendarImpl->SetGregorianChange(change);
247         }
248
249         std::unique_ptr< Calendar > pCalendar(_pCalendarImpl->CloneN());
250         SysTryReturnResult(NID_LCL, pCalendar != null, E_OUT_OF_MEMORY, "Memory allocation failed");
251
252         _CalendarImpl* pCalImpl = dynamic_cast< _CalendarImpl* >(pCalendar.get());
253         if (pCalImpl != null)
254         {
255                 pCalImpl->SetTimeInMillisec(change);
256
257                 __cutoverJulianDay = pCalImpl->GetJulianDay();
258                 //        __normalizedGregorianCutover = change * Calendar::ONE_DAY_IN_MILLISEC;
259
260                 __gregorianCutoverYear = pCalImpl->GetTimeField(TIME_FIELD_YEAR);
261                 if (pCalImpl->GetTimeField(TIME_FIELD_ERA) == GREGORIAN_CALENDAR_BC)
262                 {
263                         __gregorianCutoverYear = 1 - __gregorianCutoverYear;                    // update __gregorianCutoverYear for BC, 0 based
264                 }
265
266                 long long julianDayFromEpoch = __cutoverJulianDay - GregorianCalendar::EPOCH_START_AS_JULIAN_DAY;
267                 __normalizedGregorianCutover = julianDayFromEpoch * Calendar::ONE_DAY_IN_MILLISEC;
268
269                 // Handle the rare case of numeric overflow
270                 if (julianDayFromEpoch < 0 && __normalizedGregorianCutover > 0)
271                 {
272                         __normalizedGregorianCutover = (julianDayFromEpoch + 1) * Calendar::ONE_DAY_IN_MILLISEC;
273                 }
274         }
275
276         return r;
277 }
278
279 bool
280 GregorianCalendar::IsGregorian(void) const
281 {
282         return true;
283 }
284
285 long long
286 GregorianCalendar::GetNormalizedGregorianCutover(void) const
287 {
288         SysAssertf(_pCalendarImpl != null, "Not yet constructed! Construct() should be called before use.");
289         return __normalizedGregorianCutover;
290 }
291
292 int
293 GregorianCalendar::GetGregorianCutoverYear(void) const
294 {
295         SysAssertf(_pCalendarImpl != null, "Not yet constructed! Construct() should be called before use.");
296         return __gregorianCutoverYear;
297 }
298
299 int
300 GregorianCalendar::GetCutoverJulianDay(void) const
301 {
302         SysAssertf(_pCalendarImpl != null, "Not yet constructed! Construct() should be called before use.");
303         return __cutoverJulianDay;
304 }
305
306 result
307 GregorianCalendar::GetTimeInMillisecFromEpoch(long long& millisec) const
308 {
309         SysAssertf(_pCalendarImpl != null, "Not yet constructed! Construct() should be called before use.");
310         result r = _pCalendarImpl->GetTimeInMillisec(millisec);
311         if (!IsFailed(r))
312         {
313                 millisec -= GregorianCalendar::EPOCH_OFFSET_IN_MILLISEC;
314         }
315         return r;
316 }
317
318 result
319 GregorianCalendar::SetTimeInMillisecFromEpoch(long long millisec)
320 {
321         SysAssertf(_pCalendarImpl != null, "Not yet constructed! Construct() should be called before use.");
322
323         millisec += GregorianCalendar::EPOCH_OFFSET_IN_MILLISEC;
324         return _pCalendarImpl->SetTimeInMillisec(millisec);
325 }
326
327 // added for backward compatibility
328 result
329 GregorianCalendar::RollWithSingleUnit(TimeField field, bool up)
330 {
331         return E_UNSUPPORTED_OPERATION;
332 }
333
334 // added for backward compatibility
335 result
336 GregorianCalendar::ComputeTimeFields(void)
337 {
338         return E_UNSUPPORTED_OPERATION;
339 }
340
341 // added for backward compatibility
342 result
343 GregorianCalendar::ComputeTime(void)
344 {
345         return E_UNSUPPORTED_OPERATION;
346 }
347
348 // added for backward compatibility
349 int
350 GregorianCalendar::GetMonthLength(int extendedYear, int month) const
351 {
352         SetLastResult(E_UNSUPPORTED_OPERATION);
353         return -1;
354 }
355
356 // added for backward compatibility
357 int
358 GregorianCalendar::HandleGetLimit(TimeField field, CalendarLimitType limitType) const
359 {
360         SetLastResult(E_UNSUPPORTED_OPERATION);
361         return -1;
362 }
363
364 // added for backward compatibility
365 Calendar*
366 GregorianCalendar::CloneN(void) const
367 {
368         SetLastResult(E_UNSUPPORTED_OPERATION);
369         return null;
370 }
371
372
373 };
374 };      // Tizen::Locales