pimappsupport/chinesecalendaralg/pluginsrc/chinesecalendar.cpp
branchRCL_3
changeset 12 38571fd2a704
equal deleted inserted replaced
5:42814f902fe6 12:38571fd2a704
       
     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 	}