diff -r 42814f902fe6 -r 38571fd2a704 pimappsupport/chinesecalendaralg/pluginsrc/chinesecalendar.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pimappsupport/chinesecalendaralg/pluginsrc/chinesecalendar.cpp Fri Mar 12 15:42:35 2010 +0200 @@ -0,0 +1,368 @@ +// Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// Implementation of the TChineseCalendar class. +// + +#include "chinesecalendar.h" +#include "arithmeticaldate.h" +#include "gregoriancalendar.h" + +#if defined(_DEBUG) +_LIT(KCalconPanic,"Calcon"); +#endif + +const TUint KMonthInvalid=0; +const TUint K29DayMonth=1; +const TUint K30DayMonth=2; +const TUint K29DayLeapMonth=3; +const TUint K30DayLeapMonth=4; + +const TUint KMonthMask=1<<15; +const TUint KLeapMonthShift=28; + +const TInt KNoOfYearsInCycle = 60; + +enum TCalconPanic + { + ECalconChineseFromFixedMonthInvalid=0, + ECalconChineseToFixedLeapYearInvalid, + ECalconGetDataYearOutOfRange, + ECalconGetDataMonthOutOfRange, + ECalconGetNewYearYearOutOfRange + }; + +TUint TCalconData::GetData(TInt aCycle, TInt aYear, TInt aMonth) const + { + __ASSERT_DEBUG((aYear>=0 && aYear<=59), User::Panic(_L("Calcon"), ECalconGetDataYearOutOfRange)); //year range is 0..59 + __ASSERT_DEBUG((aMonth>=0 && aMonth<=12), User::Panic(_L("Calcon"), ECalconGetDataMonthOutOfRange));//month range is 0..12 + + TInt y=(aCycle*KNoOfYearsInCycle)+aYear; + y-=(KFirstYear-1); //there are KFirstYear-1 entries missing from the head of the table + TUint16 x=iCalConDataMonth[y]; + + TUint mask=KMonthMask>>aMonth; + + TInt flag=K29DayMonth; + if (x & mask) + flag=K30DayMonth; + + TUint leapMonth=iCalConDataYear[y]>>KLeapMonthShift; + leapMonth--; + + if ((TUint)aMonth==leapMonth) + flag+=2; //--> K29/30DayLeapMonth + + if ((aMonth==12) && (leapMonth==0)) + flag=KMonthInvalid;//month doesn't exist + + return flag; + } + +TUint TCalconData::GetNewYear(TInt aCycle, TInt aYear) const + { + __ASSERT_DEBUG((aYear>=0 && aYear<=59), User::Panic(_L("Calcon"), ECalconGetNewYearYearOutOfRange)); + TInt y=(aCycle*KNoOfYearsInCycle)+aYear; + y-=(KFirstYear-1); + return (iCalConDataYear[y] & 0x0fffffff); + } + +//------------------------------------------------------ +// Class: TChineseCalendar +// Function: ChineseToDateTime +// Arguments: TDateTime & +// +// Comments: This function converts the date held within +// the TChineseCalendar class to a TDateTime format and +// places it in the TDateTime class provided. +// +// Return: void +//------------------------------------------------------ +void TChineseCalendar::ChineseToDateTime(TDateTime &aDT) + { + TArithmeticalDate gregDate; + TGregorianCalendar greg(iJulianDay); + + greg.GregFromJulianDay(gregDate,iJulianDay); + aDT.Set(0,EJanuary,0,0,0,0,0); + + aDT.SetDay(gregDate.iDay - KCalConvMonthOffsetByOne); + aDT.SetMonth((TMonth)(gregDate.iMonth - KCalConvMonthOffsetByOne)); + aDT.SetYear(gregDate.iYear); + } + +//------------------------------------------------------ +// Class: TChineseCalendar +// Function: DateTimeToChinese +// Arguments: TDateTime & +// +// Comments: Sets the date held in the given TDateTime +// class to the TChineseCalendar class +// +// Return: void +//------------------------------------------------------ +void TChineseCalendar::DateTimeToChinese(const TDateTime &aDT) + { + TArithmeticalDate gregDate; + TGregorianCalendar greg; + + gregDate.iDay = aDT.Day() + KCalConvMonthOffsetByOne; + gregDate.iMonth = (TInt)aDT.Month() + KCalConvMonthOffsetByOne; + gregDate.iYear = aDT.Year(); + + iJulianDay = greg.GregToJulianDay(gregDate); + } + +//------------------------------------------------------ +// Class: TChineseCalendar +// Function: SetDate +// Arguments: TChineseDate& +// +// Comments: this function sets the julian day value +// in the base class from the given +// TChineseDate +// +// Return: None +//------------------------------------------------------ +TInt TChineseCalendar::SetDate(const TChineseDate &aDate) + { + TReal jD; + TChineseDate ChinDate = aDate; + + if(!ValidDate(ChinDate)) + return KErrArgument; + + if (!ChineseToFixed(aDate,jD)) + return KErrArgument; + + if (jDKLastJulianDate) + return KErrArgument; + + iJulianDay = (TInt)jD; + return KErrNone; + } +//------------------------------------------------------ +// Class: TChineseCalendar +// Function: GetDate +// Arguments: TChineseDate & +// +// Comments: This function Determines the chinese date and +// places it in the TChineseDate class provided +// for the julian day value held internally in the +// Chinese class. +// +// Return: None +//------------------------------------------------------ +TInt TChineseCalendar::GetDate(TChineseDate &aDate) + { + return ChineseFromFixed(aDate,iJulianDay); + } + +//------------------------------------------------------ +// Class: TChineseCalendar +// Function: ChineseToFixed +// Arguments: TChineseDate , TReal & +// TChineseDate members start at 1 (not zero) +// +// Comments: This function converts a chinese date to +// to a julian day value. +// +// Return: TBool ETrue if date valid, else EFalse +//------------------------------------------------------ +TBool TChineseCalendar::ChineseToFixed(const TChineseDate& aDate, TReal &aJulianDay) const + { + TInt cycle=aDate.iCycle-KFirstCycle; //cycle starts from zero + TInt year=aDate.iYear-1; //year is 0..59 + + TInt days=0; + + TInt targetMonth=aDate.iMonth; //targetMonth is 1..12 + TBool leap=aDate.iLeapMonth; + if (leap) + { + targetMonth++; + if (iData.GetData(cycle, year, targetMonth-1)<3) + return EFalse; //not a leap month + } + + TInt month=1; + while (month<=targetMonth) + { + TInt daysFlag=iData.GetData(cycle, year, month-1); + +//We need to handle case where targetMonth is a leap month +//Eg if Chinese month==6 targetMonth will be 6 +//Eg but if Chinese month 5 is a leap month, month 6 will be 5(leap) so we need to take it into account +//BUT Eg if Chinese momth== 7(leap) we've already taken this into account. + if (month==targetMonth) + if ((leap) || (daysFlag<3)) + break; + + switch (daysFlag) + { + case KMonthInvalid: + return EFalse; + case K29DayMonth: + days+=29; + break; + case K30DayMonth: + days+=30; + break; + case K29DayLeapMonth: + __ASSERT_DEBUG(!leap, User::Panic(KCalconPanic,ECalconChineseToFixedLeapYearInvalid)); + leap=ETrue; + targetMonth++; + days+=29; + break; + case K30DayLeapMonth: + __ASSERT_DEBUG(!leap, User::Panic(KCalconPanic,ECalconChineseToFixedLeapYearInvalid)); + leap=ETrue; + targetMonth++; + days+=30; + break; + } + month++; + } + +//Check that if days==30, the requested month actually has 30 days + TInt checkMonth = aDate.iMonth; + if (leap) + checkMonth++; //this is the month requested by the user + TUint daysFlag=iData.GetData(cycle, year, checkMonth-1); + + if ((aDate.iDay==30) && ((daysFlag==K29DayMonth) || (daysFlag==K29DayLeapMonth))) + return EFalse; + + days+=aDate.iDay-1; + + days+=iData.GetNewYear(cycle, year);//add the New Year + aJulianDay=days; + return ETrue; + } + +//------------------------------------------------------ +// Class: TChineseCalendar +// Function: ChineseFromFixed +// Arguments: TChineseDate &, TReal +// +// Comments: this function converts a julian day value to +// a chinese date in the form TChineseDate +// +// Return: None +//------------------------------------------------------ +TInt TChineseCalendar::ChineseFromFixed(TChineseDate &aDate, const TReal& aJulianDay) const + { + if ((aJulianDayKLastJulianDate)) + return KErrArgument; + + TInt cycleIndex=0; + + while ((cycleIndex < KLastCycle-KFirstCycle) + && (aJulianDay >= iData.GetNewYear(cycleIndex+1,0))) + cycleIndex++; + + aDate.iCycle=cycleIndex + KFirstCycle; + TInt chineseNewYear; + TInt yearCount=0; + if (cycleIndex==0) + yearCount=KFirstYear-1; + + while (yearCount<60 && aJulianDay >= iData.GetNewYear(cycleIndex,yearCount)) + yearCount++; + + aDate.iYear=yearCount; + chineseNewYear = iData.GetNewYear(cycleIndex,--yearCount); + + TInt addedNumberOfDays = 0; + TInt previousAddedNumberOfDays = 0; + TInt monthCount = 1; + aDate.iMonth = 0; + + TInt monthNumber; // 0=No month exists, 1 = 29 day month, 2 = 30 day month, 3 = 29 day leap month, 4 = 30 day leap month + + while (aJulianDay >= (chineseNewYear + addedNumberOfDays)) + { + previousAddedNumberOfDays = addedNumberOfDays; + monthNumber = iData.GetData(cycleIndex,yearCount,monthCount-1); + + switch (monthNumber) + { + case KMonthInvalid: + __ASSERT_DEBUG(0, User::Panic(_L("Calcon"),ECalconChineseFromFixedMonthInvalid)); + break; + case K29DayMonth: + addedNumberOfDays += 29; + aDate.iMonth++; + aDate.iLeapMonth = EFalse; + break; + case K30DayMonth: + addedNumberOfDays += 30; + aDate.iMonth++; + aDate.iLeapMonth = EFalse; + break; + case K29DayLeapMonth: + addedNumberOfDays += 29; + aDate.iLeapMonth = ETrue; + break; + case K30DayLeapMonth: + addedNumberOfDays += 30; + aDate.iLeapMonth = ETrue; + break; + } + monthCount++; + } + + aDate.iDay = (TInt)aJulianDay - chineseNewYear-previousAddedNumberOfDays; + aDate.iDay++; + return KErrNone; + } + +//------------------------------------------------------ +// Class: TChineseCalendar +// Function: ValidDate +// Arguments: TChineseDate & +// +// Comments: This function Determines whether the given +// date is a valid chinese date +// +// Return: TBool - ETrue if date is valid, else EFalse +//------------------------------------------------------ +TBool TChineseCalendar::ValidDate(const TChineseDate &aDate) const + { + //do some trivial checks to ensure that the date is in the range of the lookup table + if (aDate.iYear==0 || aDate.iYear>KNoOfYearsInCycle) + return EFalse; + + if (aDate.iCycle < KFirstCycle) + return EFalse; + + if (aDate.iCycle==KFirstCycle && aDate.iYear < KFirstYear) + return EFalse; + + if (aDate.iCycle > KLastCycle) + return EFalse; + + if ( (aDate.iCycle==KLastCycle) && (aDate.iYear>KLastYear)) + return EFalse; + + if (aDate.iDay==0 || aDate.iDay>30) + return EFalse; + + return ETrue; + } + +TReal TChineseCalendar::JulianDate() __SOFTFP + { + return iJulianDay; + }