|
1 // Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // Implementation of the TChineseCalendar class. |
|
15 // |
|
16 |
|
17 #include "chinesecalendar.h" |
|
18 #include "arithmeticaldate.h" |
|
19 #include "gregoriancalendar.h" |
|
20 |
|
21 #if defined(_DEBUG) |
|
22 _LIT(KCalconPanic,"Calcon"); |
|
23 #endif |
|
24 |
|
25 const TUint KMonthInvalid=0; |
|
26 const TUint K29DayMonth=1; |
|
27 const TUint K30DayMonth=2; |
|
28 const TUint K29DayLeapMonth=3; |
|
29 const TUint K30DayLeapMonth=4; |
|
30 |
|
31 const TUint KMonthMask=1<<15; |
|
32 const TUint KLeapMonthShift=28; |
|
33 |
|
34 const TInt KNoOfYearsInCycle = 60; |
|
35 |
|
36 enum TCalconPanic |
|
37 { |
|
38 ECalconChineseFromFixedMonthInvalid=0, |
|
39 ECalconChineseToFixedLeapYearInvalid, |
|
40 ECalconGetDataYearOutOfRange, |
|
41 ECalconGetDataMonthOutOfRange, |
|
42 ECalconGetNewYearYearOutOfRange |
|
43 }; |
|
44 |
|
45 TUint TCalconData::GetData(TInt aCycle, TInt aYear, TInt aMonth) const |
|
46 { |
|
47 __ASSERT_DEBUG((aYear>=0 && aYear<=59), User::Panic(_L("Calcon"), ECalconGetDataYearOutOfRange)); //year range is 0..59 |
|
48 __ASSERT_DEBUG((aMonth>=0 && aMonth<=12), User::Panic(_L("Calcon"), ECalconGetDataMonthOutOfRange));//month range is 0..12 |
|
49 |
|
50 TInt y=(aCycle*KNoOfYearsInCycle)+aYear; |
|
51 y-=(KFirstYear-1); //there are KFirstYear-1 entries missing from the head of the table |
|
52 TUint16 x=iCalConDataMonth[y]; |
|
53 |
|
54 TUint mask=KMonthMask>>aMonth; |
|
55 |
|
56 TInt flag=K29DayMonth; |
|
57 if (x & mask) |
|
58 flag=K30DayMonth; |
|
59 |
|
60 TUint leapMonth=iCalConDataYear[y]>>KLeapMonthShift; |
|
61 leapMonth--; |
|
62 |
|
63 if ((TUint)aMonth==leapMonth) |
|
64 flag+=2; //--> K29/30DayLeapMonth |
|
65 |
|
66 if ((aMonth==12) && (leapMonth==0)) |
|
67 flag=KMonthInvalid;//month doesn't exist |
|
68 |
|
69 return flag; |
|
70 } |
|
71 |
|
72 TUint TCalconData::GetNewYear(TInt aCycle, TInt aYear) const |
|
73 { |
|
74 __ASSERT_DEBUG((aYear>=0 && aYear<=59), User::Panic(_L("Calcon"), ECalconGetNewYearYearOutOfRange)); |
|
75 TInt y=(aCycle*KNoOfYearsInCycle)+aYear; |
|
76 y-=(KFirstYear-1); |
|
77 return (iCalConDataYear[y] & 0x0fffffff); |
|
78 } |
|
79 |
|
80 //------------------------------------------------------ |
|
81 // Class: TChineseCalendar |
|
82 // Function: ChineseToDateTime |
|
83 // Arguments: TDateTime & |
|
84 // |
|
85 // Comments: This function converts the date held within |
|
86 // the TChineseCalendar class to a TDateTime format and |
|
87 // places it in the TDateTime class provided. |
|
88 // |
|
89 // Return: void |
|
90 //------------------------------------------------------ |
|
91 void TChineseCalendar::ChineseToDateTime(TDateTime &aDT) |
|
92 { |
|
93 TArithmeticalDate gregDate; |
|
94 TGregorianCalendar greg(iJulianDay); |
|
95 |
|
96 greg.GregFromJulianDay(gregDate,iJulianDay); |
|
97 aDT.Set(0,EJanuary,0,0,0,0,0); |
|
98 |
|
99 aDT.SetDay(gregDate.iDay - KCalConvMonthOffsetByOne); |
|
100 aDT.SetMonth((TMonth)(gregDate.iMonth - KCalConvMonthOffsetByOne)); |
|
101 aDT.SetYear(gregDate.iYear); |
|
102 } |
|
103 |
|
104 //------------------------------------------------------ |
|
105 // Class: TChineseCalendar |
|
106 // Function: DateTimeToChinese |
|
107 // Arguments: TDateTime & |
|
108 // |
|
109 // Comments: Sets the date held in the given TDateTime |
|
110 // class to the TChineseCalendar class |
|
111 // |
|
112 // Return: void |
|
113 //------------------------------------------------------ |
|
114 void TChineseCalendar::DateTimeToChinese(const TDateTime &aDT) |
|
115 { |
|
116 TArithmeticalDate gregDate; |
|
117 TGregorianCalendar greg; |
|
118 |
|
119 gregDate.iDay = aDT.Day() + KCalConvMonthOffsetByOne; |
|
120 gregDate.iMonth = (TInt)aDT.Month() + KCalConvMonthOffsetByOne; |
|
121 gregDate.iYear = aDT.Year(); |
|
122 |
|
123 iJulianDay = greg.GregToJulianDay(gregDate); |
|
124 } |
|
125 |
|
126 //------------------------------------------------------ |
|
127 // Class: TChineseCalendar |
|
128 // Function: SetDate |
|
129 // Arguments: TChineseDate& |
|
130 // |
|
131 // Comments: this function sets the julian day value |
|
132 // in the base class from the given |
|
133 // TChineseDate |
|
134 // |
|
135 // Return: None |
|
136 //------------------------------------------------------ |
|
137 TInt TChineseCalendar::SetDate(const TChineseDate &aDate) |
|
138 { |
|
139 TReal jD; |
|
140 TChineseDate ChinDate = aDate; |
|
141 |
|
142 if(!ValidDate(ChinDate)) |
|
143 return KErrArgument; |
|
144 |
|
145 if (!ChineseToFixed(aDate,jD)) |
|
146 return KErrArgument; |
|
147 |
|
148 if (jD<KFirstJulianDate || jD>KLastJulianDate) |
|
149 return KErrArgument; |
|
150 |
|
151 iJulianDay = (TInt)jD; |
|
152 return KErrNone; |
|
153 } |
|
154 //------------------------------------------------------ |
|
155 // Class: TChineseCalendar |
|
156 // Function: GetDate |
|
157 // Arguments: TChineseDate & |
|
158 // |
|
159 // Comments: This function Determines the chinese date and |
|
160 // places it in the TChineseDate class provided |
|
161 // for the julian day value held internally in the |
|
162 // Chinese class. |
|
163 // |
|
164 // Return: None |
|
165 //------------------------------------------------------ |
|
166 TInt TChineseCalendar::GetDate(TChineseDate &aDate) |
|
167 { |
|
168 return ChineseFromFixed(aDate,iJulianDay); |
|
169 } |
|
170 |
|
171 //------------------------------------------------------ |
|
172 // Class: TChineseCalendar |
|
173 // Function: ChineseToFixed |
|
174 // Arguments: TChineseDate , TReal & |
|
175 // TChineseDate members start at 1 (not zero) |
|
176 // |
|
177 // Comments: This function converts a chinese date to |
|
178 // to a julian day value. |
|
179 // |
|
180 // Return: TBool ETrue if date valid, else EFalse |
|
181 //------------------------------------------------------ |
|
182 TBool TChineseCalendar::ChineseToFixed(const TChineseDate& aDate, TReal &aJulianDay) const |
|
183 { |
|
184 TInt cycle=aDate.iCycle-KFirstCycle; //cycle starts from zero |
|
185 TInt year=aDate.iYear-1; //year is 0..59 |
|
186 |
|
187 TInt days=0; |
|
188 |
|
189 TInt targetMonth=aDate.iMonth; //targetMonth is 1..12 |
|
190 TBool leap=aDate.iLeapMonth; |
|
191 if (leap) |
|
192 { |
|
193 targetMonth++; |
|
194 if (iData.GetData(cycle, year, targetMonth-1)<3) |
|
195 return EFalse; //not a leap month |
|
196 } |
|
197 |
|
198 TInt month=1; |
|
199 while (month<=targetMonth) |
|
200 { |
|
201 TInt daysFlag=iData.GetData(cycle, year, month-1); |
|
202 |
|
203 //We need to handle case where targetMonth is a leap month |
|
204 //Eg if Chinese month==6 targetMonth will be 6 |
|
205 //Eg but if Chinese month 5 is a leap month, month 6 will be 5(leap) so we need to take it into account |
|
206 //BUT Eg if Chinese momth== 7(leap) we've already taken this into account. |
|
207 if (month==targetMonth) |
|
208 if ((leap) || (daysFlag<3)) |
|
209 break; |
|
210 |
|
211 switch (daysFlag) |
|
212 { |
|
213 case KMonthInvalid: |
|
214 return EFalse; |
|
215 case K29DayMonth: |
|
216 days+=29; |
|
217 break; |
|
218 case K30DayMonth: |
|
219 days+=30; |
|
220 break; |
|
221 case K29DayLeapMonth: |
|
222 __ASSERT_DEBUG(!leap, User::Panic(KCalconPanic,ECalconChineseToFixedLeapYearInvalid)); |
|
223 leap=ETrue; |
|
224 targetMonth++; |
|
225 days+=29; |
|
226 break; |
|
227 case K30DayLeapMonth: |
|
228 __ASSERT_DEBUG(!leap, User::Panic(KCalconPanic,ECalconChineseToFixedLeapYearInvalid)); |
|
229 leap=ETrue; |
|
230 targetMonth++; |
|
231 days+=30; |
|
232 break; |
|
233 } |
|
234 month++; |
|
235 } |
|
236 |
|
237 //Check that if days==30, the requested month actually has 30 days |
|
238 TInt checkMonth = aDate.iMonth; |
|
239 if (leap) |
|
240 checkMonth++; //this is the month requested by the user |
|
241 TUint daysFlag=iData.GetData(cycle, year, checkMonth-1); |
|
242 |
|
243 if ((aDate.iDay==30) && ((daysFlag==K29DayMonth) || (daysFlag==K29DayLeapMonth))) |
|
244 return EFalse; |
|
245 |
|
246 days+=aDate.iDay-1; |
|
247 |
|
248 days+=iData.GetNewYear(cycle, year);//add the New Year |
|
249 aJulianDay=days; |
|
250 return ETrue; |
|
251 } |
|
252 |
|
253 //------------------------------------------------------ |
|
254 // Class: TChineseCalendar |
|
255 // Function: ChineseFromFixed |
|
256 // Arguments: TChineseDate &, TReal |
|
257 // |
|
258 // Comments: this function converts a julian day value to |
|
259 // a chinese date in the form TChineseDate |
|
260 // |
|
261 // Return: None |
|
262 //------------------------------------------------------ |
|
263 TInt TChineseCalendar::ChineseFromFixed(TChineseDate &aDate, const TReal& aJulianDay) const |
|
264 { |
|
265 if ((aJulianDay<KFirstJulianDate) |
|
266 || (aJulianDay>KLastJulianDate)) |
|
267 return KErrArgument; |
|
268 |
|
269 TInt cycleIndex=0; |
|
270 |
|
271 while ((cycleIndex < KLastCycle-KFirstCycle) |
|
272 && (aJulianDay >= iData.GetNewYear(cycleIndex+1,0))) |
|
273 cycleIndex++; |
|
274 |
|
275 aDate.iCycle=cycleIndex + KFirstCycle; |
|
276 TInt chineseNewYear; |
|
277 TInt yearCount=0; |
|
278 if (cycleIndex==0) |
|
279 yearCount=KFirstYear-1; |
|
280 |
|
281 while (yearCount<60 && aJulianDay >= iData.GetNewYear(cycleIndex,yearCount)) |
|
282 yearCount++; |
|
283 |
|
284 aDate.iYear=yearCount; |
|
285 chineseNewYear = iData.GetNewYear(cycleIndex,--yearCount); |
|
286 |
|
287 TInt addedNumberOfDays = 0; |
|
288 TInt previousAddedNumberOfDays = 0; |
|
289 TInt monthCount = 1; |
|
290 aDate.iMonth = 0; |
|
291 |
|
292 TInt monthNumber; // 0=No month exists, 1 = 29 day month, 2 = 30 day month, 3 = 29 day leap month, 4 = 30 day leap month |
|
293 |
|
294 while (aJulianDay >= (chineseNewYear + addedNumberOfDays)) |
|
295 { |
|
296 previousAddedNumberOfDays = addedNumberOfDays; |
|
297 monthNumber = iData.GetData(cycleIndex,yearCount,monthCount-1); |
|
298 |
|
299 switch (monthNumber) |
|
300 { |
|
301 case KMonthInvalid: |
|
302 __ASSERT_DEBUG(0, User::Panic(_L("Calcon"),ECalconChineseFromFixedMonthInvalid)); |
|
303 break; |
|
304 case K29DayMonth: |
|
305 addedNumberOfDays += 29; |
|
306 aDate.iMonth++; |
|
307 aDate.iLeapMonth = EFalse; |
|
308 break; |
|
309 case K30DayMonth: |
|
310 addedNumberOfDays += 30; |
|
311 aDate.iMonth++; |
|
312 aDate.iLeapMonth = EFalse; |
|
313 break; |
|
314 case K29DayLeapMonth: |
|
315 addedNumberOfDays += 29; |
|
316 aDate.iLeapMonth = ETrue; |
|
317 break; |
|
318 case K30DayLeapMonth: |
|
319 addedNumberOfDays += 30; |
|
320 aDate.iLeapMonth = ETrue; |
|
321 break; |
|
322 } |
|
323 monthCount++; |
|
324 } |
|
325 |
|
326 aDate.iDay = (TInt)aJulianDay - chineseNewYear-previousAddedNumberOfDays; |
|
327 aDate.iDay++; |
|
328 return KErrNone; |
|
329 } |
|
330 |
|
331 //------------------------------------------------------ |
|
332 // Class: TChineseCalendar |
|
333 // Function: ValidDate |
|
334 // Arguments: TChineseDate & |
|
335 // |
|
336 // Comments: This function Determines whether the given |
|
337 // date is a valid chinese date |
|
338 // |
|
339 // Return: TBool - ETrue if date is valid, else EFalse |
|
340 //------------------------------------------------------ |
|
341 TBool TChineseCalendar::ValidDate(const TChineseDate &aDate) const |
|
342 { |
|
343 //do some trivial checks to ensure that the date is in the range of the lookup table |
|
344 if (aDate.iYear==0 || aDate.iYear>KNoOfYearsInCycle) |
|
345 return EFalse; |
|
346 |
|
347 if (aDate.iCycle < KFirstCycle) |
|
348 return EFalse; |
|
349 |
|
350 if (aDate.iCycle==KFirstCycle && aDate.iYear < KFirstYear) |
|
351 return EFalse; |
|
352 |
|
353 if (aDate.iCycle > KLastCycle) |
|
354 return EFalse; |
|
355 |
|
356 if ( (aDate.iCycle==KLastCycle) && (aDate.iYear>KLastYear)) |
|
357 return EFalse; |
|
358 |
|
359 if (aDate.iDay==0 || aDate.iDay>30) |
|
360 return EFalse; |
|
361 |
|
362 return ETrue; |
|
363 } |
|
364 |
|
365 TReal TChineseCalendar::JulianDate() __SOFTFP |
|
366 { |
|
367 return iJulianDay; |
|
368 } |