pimappsupport/chinesecalendaralg/originalsrc/Chinese.cpp
branchRCL_3
changeset 12 38571fd2a704
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pimappsupport/chinesecalendaralg/originalsrc/Chinese.cpp	Fri Mar 12 15:42:35 2010 +0200
@@ -0,0 +1,626 @@
+// 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.
+// 
+//
+
+// User includes
+#include "calconv.h"
+
+// Constants
+const TInt KChinStartEpoch = 758325;
+const TInt KFifteenth = 15;
+const TInt KDegreesPerMonth = 30;
+const TInt KMonthsInYear = 12;
+const TInt KFirstChinYear = -2636;
+const TInt KYearsInChinCycle = 60;
+const TInt KCycleOffset = 1;
+
+
+//
+// Construction/Destruction
+//
+
+//------------------------------------------------------
+// Class:       TChineseCalendar
+// Function:    TChineseCalendar
+// Arguments:   None
+//
+// Comments:    Constructer
+//
+// Return:      None
+//------------------------------------------------------
+EXPORT_C TChineseCalendar::TChineseCalendar()
+	{
+	iStartEpoch = KChinStartEpoch;
+	}
+
+//------------------------------------------------------
+// Class:       TChineseCalendar
+// Function:    CurrentMajorSolarTerm
+// Arguments:   TReal
+//
+// Comments:    Returns the index of the last major solar term
+//
+// Return:      see comment
+//------------------------------------------------------
+TReal TChineseCalendar::CurrentMajorSolarTerm(TReal& aJulianDay) const
+	{
+	TReal sigma;
+	TInt sigmaI;
+
+	AdjustJDToNoon(aJulianDay);
+
+	sigma = ChineseTimeZone(aJulianDay);
+	sigma = UniversalFromLocal(aJulianDay,sigma);
+	SolarLongitude(sigma,sigma);
+	sigma /= 30.0;
+	Floor(sigmaI,sigma);
+	sigmaI += 2;
+	Amod(sigma,sigmaI,12.0);
+	Round(sigmaI,sigma);
+	return sigmaI;
+	}
+
+//------------------------------------------------------
+// Class:       TChineseCalendar
+// Function:    ChineseTimeZone
+// Arguments:   TReal
+//
+// Comments:    Determines which time zone to use
+//
+// Return:      TReal - time zone
+//------------------------------------------------------
+TReal TChineseCalendar::ChineseTimeZone(const TReal& aJulianDay) const
+	{
+	TReal result;
+	TGregorianCalendar greg(aJulianDay);
+	TArithmeticalDate date;
+
+	greg.GetDate(date);
+
+	if(date.iYear < 1929)
+		{
+		result = 465.0 + (40.0 / 60.0);
+		}
+	else
+		{
+		result = 480.0;
+		}
+	return result;
+	}
+
+//------------------------------------------------------
+// Class:       TChineseCalendar
+// Function:    ChineseDateNextSolarLongitudeL
+// Arguments:   TReal , TReal
+//
+// Comments:    calculates the first date on or after the given
+//				julian day when the solar longitude will be a 
+//				multiple of aDegrees degrees. 
+//
+// Return:      TInt - see comment
+//------------------------------------------------------
+TInt TChineseCalendar::ChineseDateNextSolarLongitude(TReal& aJulianDay, const TReal& aDegrees) const
+	{
+	TReal chTimeZone;
+	TReal chDateNxtSlrLong;
+	TInt rtn;
+
+	AdjustJDToNoon(aJulianDay);
+	chTimeZone = ChineseTimeZone(aJulianDay);
+
+	chDateNxtSlrLong = UniversalFromLocal(aJulianDay,chTimeZone);
+	chDateNxtSlrLong = DateNextSolarLongitude(chDateNxtSlrLong,aDegrees);
+	chDateNxtSlrLong = LocalFromUniversal(chDateNxtSlrLong,chTimeZone);
+
+	AdjustJDFromNoon(chDateNxtSlrLong);
+	Floor(rtn,chDateNxtSlrLong);
+
+	return rtn;
+	}
+
+
+//------------------------------------------------------
+// Class:       TChineseCalendar
+// Function:    MajorSolarTermOnOrAfter
+// Arguments:   TReal
+//
+// Comments:    Determines the major solar term on or after 
+//				the given julian day.
+//
+// Return:      TReal - see comment
+//------------------------------------------------------
+TReal TChineseCalendar::MajorSolarTermOnOrAfter(TReal& aJulianDay) const
+	{
+	TReal majorSolarTerm;
+	majorSolarTerm = ChineseDateNextSolarLongitude(aJulianDay,KDegreesPerMonth);
+	return majorSolarTerm;
+	}
+
+//------------------------------------------------------
+// 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
+//------------------------------------------------------
+EXPORT_C void TChineseCalendar::GetDate(TChineseDate &aDate)
+	{
+	ChineseFromFixed(aDate,iJulianDay);
+	}
+
+
+//------------------------------------------------------
+// Class:       TChineseCalendar
+// Function:    ChineseNewMoonBefore
+// Arguments:   TReal
+//
+// Comments:    corrects for chinese month starting at noon
+//				in Beijing
+//
+// Return:      TInt - new moon
+//------------------------------------------------------
+TInt TChineseCalendar::ChineseNewMoonBefore(TReal aJulianDay) const
+	{
+	TReal newMoon;
+	TReal timeZone;
+	TInt rtn;
+
+	AdjustJDToNoon(aJulianDay);
+
+	timeZone = ChineseTimeZone(aJulianDay);
+	newMoon = UniversalFromLocal(aJulianDay,timeZone);
+	newMoon = NewMoonBefore(newMoon);
+	newMoon = LocalFromUniversal(newMoon,timeZone);
+
+	AdjustJDFromNoon(newMoon);
+	Floor(rtn,newMoon);
+
+	return rtn;
+	}
+
+//------------------------------------------------------
+// Class:       TChineseCalendar
+// Function:    ChineseNewMoonOnOrAfter
+// Arguments:   TReal
+//
+// Comments:    corrects for chinese month starting at noon
+//				in Beijing
+//
+// Return:      TInt - new moon
+//------------------------------------------------------
+TInt TChineseCalendar::ChineseNewMoonOnOrAfter(TReal aJulianDay) const
+	{
+	TReal newMoon;
+	TReal timeZone;
+	TInt rtn;
+
+	AdjustJDToNoon(aJulianDay);
+
+	timeZone = ChineseTimeZone(aJulianDay);
+	newMoon = UniversalFromLocal(aJulianDay,timeZone);
+	newMoon = NewMoonAtOrAfter(newMoon);
+	newMoon = LocalFromUniversal(newMoon,timeZone);
+
+	AdjustJDFromNoon(newMoon);
+	Floor(rtn,newMoon);
+
+	return rtn;
+	}
+
+//------------------------------------------------------
+// Class:       TChineseCalendar
+// Function:    NoMajorSolarTerm
+// Arguments:   TReal
+//
+// Comments:    Determines whether a given month lacks a 
+//				major solar term.  The first month without
+//				a major solar term is a leap month.
+//
+// Return:      TBool - ETrue if month has no major solar term
+//------------------------------------------------------
+TBool TChineseCalendar::NoMajorSolarTerm(TReal aJulianDay) const
+	{
+	TReal chinNewMoon;
+	TReal currentMajSolTrm1;
+	TReal currentMajSolTrm2;
+
+	chinNewMoon = ChineseNewMoonOnOrAfter(aJulianDay + KCalConvDayOffsetByOne);
+	currentMajSolTrm1 = CurrentMajorSolarTerm(chinNewMoon);
+	currentMajSolTrm2 = CurrentMajorSolarTerm(aJulianDay);
+	
+	return(currentMajSolTrm1 == currentMajSolTrm2);
+	}
+
+//------------------------------------------------------
+// Class:       TChineseCalendar
+// Function:    PriorLeapMonth
+// Arguments:   TReal , TReal
+//
+// Comments:    this function is used in conjunction with
+//				NoMajorSolarTerm() to ensure that only the 
+//				first month missing a major solar term is 
+//				a leap month
+//
+// Return:      TBool - 
+//------------------------------------------------------
+TBool TChineseCalendar::PriorLeapMonth(TReal& aMnthprime, TReal aMnth) const
+	{
+	TBool rtn,majorSolarTerm;
+	TReal newMoonBefore;
+
+	majorSolarTerm = NoMajorSolarTerm(aMnth);
+	newMoonBefore = ChineseNewMoonBefore(aMnth);
+
+	if((aMnth >= aMnthprime) && 
+		(PriorLeapMonth(aMnthprime,newMoonBefore) || majorSolarTerm))
+		{
+		rtn = ETrue;
+		}
+	else
+		{
+		rtn = EFalse;
+		}
+	return rtn;
+	}
+
+//------------------------------------------------------
+// Class:       TChineseCalendar
+// Function:    ChineseNewYear
+// Arguments:   TInt
+//
+// Comments:    Determines the chinese new year
+//
+// Return:      TReal - Julian day of the start of the given year
+//------------------------------------------------------
+TReal TChineseCalendar::ChineseNewYear(TInt aYear) const
+	{
+	TGregorianCalendar greg(iJulianDay);
+	TArithmeticalDate date;
+	TReal solarTerm1;
+	TReal solarTerm2;
+	TReal newMoon1;
+	TReal newMoon2;
+	TReal newMoon3;
+	TReal rtn;
+	TBool majorSolarTerm1;
+	TBool majorSolarTerm2;
+	TReal tempReal;
+	TInt tempInt;
+
+	// get solar term 1
+	date.iDay = KFifteenth;
+	date.iMonth = EDecember + KCalConvMonthOffsetByOne;
+	date.iYear = aYear - KCalConvYearOffsetByOne;
+	solarTerm1 = greg.GregToJulianDay(date);
+	solarTerm1 = MajorSolarTermOnOrAfter(solarTerm1);
+
+	// get solar term 2
+	date.iDay = KFifteenth;
+	date.iMonth = EDecember + KCalConvMonthOffsetByOne;
+	date.iYear = aYear;
+	solarTerm2 = greg.GregToJulianDay(date);
+	solarTerm2 = MajorSolarTermOnOrAfter(solarTerm2);
+
+	// get new moon 1
+	newMoon1 = ChineseNewMoonOnOrAfter(solarTerm1 + KCalConvDayOffsetByOne);
+
+	// get new moon 2
+	newMoon2 = ChineseNewMoonOnOrAfter(newMoon1 + KCalConvDayOffsetByOne);
+
+	// get new moon 3
+	newMoon3 = ChineseNewMoonBefore(solarTerm2 + KCalConvDayOffsetByOne);
+
+	// perform chinese new year calculation
+	tempReal = (newMoon3 - newMoon1) / KMeanSynodicMonth;
+	Round(tempInt,tempReal);
+	majorSolarTerm1 = NoMajorSolarTerm(newMoon1);
+	majorSolarTerm2 = NoMajorSolarTerm(newMoon2);
+	if((tempInt == KMonthsInYear) && (majorSolarTerm1 || majorSolarTerm2))
+		{
+		rtn = ChineseNewMoonOnOrAfter(newMoon2 + KCalConvDayOffsetByOne);
+		}
+	else
+		{
+		rtn = newMoon2;
+		}
+	return rtn;
+	}
+
+//------------------------------------------------------
+// Class:       TChineseCalendar
+// Function:    SetDate
+// Arguments:   TChineseDate&
+//
+// Comments:    this function sets the julian day value
+//				in the base class from the given 
+//				TChineseDate
+//
+// Return:      None
+//------------------------------------------------------
+EXPORT_C TInt TChineseCalendar::SetDate(const TChineseDate &aDate)
+	{
+	TReal jD;
+	TChineseDate ChinDate = aDate;
+	if(ValidDate(ChinDate)==EFalse)
+		{
+		return KCalConInvalidDate;
+		}
+		
+	ChineseToFixed(aDate,jD);
+	iJulianDay = jD;
+	return KErrNone;
+	}
+
+//------------------------------------------------------
+// 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
+//------------------------------------------------------
+void TChineseCalendar::ChineseFromFixed(TChineseDate &aDate, const TReal& aJulianDay) const
+	{
+	TGregorianCalendar greg(aJulianDay);
+	TArithmeticalDate date;
+	TReal solarTerm1;
+	TReal solarTerm2;
+	TReal lunarTerm1;
+	TReal lunarTerm2;
+	TReal lunarTerm3;
+	TInt leapYear;
+	TInt year;
+	TInt elapsedYears;
+	TBool majorSolarTerm;
+	TReal tempReal;
+	TInt tempInt;
+
+	// get the Gregorian date
+	greg.GetDate(date);
+	year = date.iYear;
+
+	// get solar term 1
+	date.iDay = KFifteenth;
+	date.iMonth = EDecember + KCalConvMonthOffsetByOne;
+	date.iYear = year - KCalConvYearOffsetByOne;
+	solarTerm1 = greg.GregToJulianDay(date);
+	solarTerm1 = MajorSolarTermOnOrAfter(solarTerm1);
+
+	// get solar term 2
+	date.iDay = KFifteenth;
+	date.iMonth = EDecember + KCalConvMonthOffsetByOne;
+	date.iYear = year;
+	solarTerm2 = greg.GregToJulianDay(date);
+	solarTerm2 = MajorSolarTermOnOrAfter(solarTerm2);
+
+	// get lunar term 1
+	if((solarTerm1 <= aJulianDay) && (aJulianDay < solarTerm2))
+		{
+		lunarTerm1 = solarTerm1 + KCalConvDayOffsetByOne;
+		}
+	else
+		{
+		lunarTerm1 = solarTerm2 + KCalConvDayOffsetByOne;
+		}
+	lunarTerm1 = ChineseNewMoonOnOrAfter(lunarTerm1);
+
+	// get lunar term 2
+	if((solarTerm1 <= aJulianDay) && (aJulianDay < solarTerm2))
+		{
+		lunarTerm2 = solarTerm2 + KCalConvDayOffsetByOne;
+		}
+	else
+		{
+		date.iDay = KFifteenth;
+		date.iMonth = EDecember + KCalConvMonthOffsetByOne;
+		date.iYear = year + KCalConvYearOffsetByOne;
+		lunarTerm2 = greg.GregToJulianDay(date);
+		lunarTerm2 = MajorSolarTermOnOrAfter(lunarTerm2) + KCalConvDayOffsetByOne;
+		}
+	lunarTerm2 = ChineseNewMoonBefore(lunarTerm2);
+
+	// get Lunar term 3
+	lunarTerm3 = aJulianDay + KCalConvDayOffsetByOne;
+	lunarTerm3 = ChineseNewMoonBefore(lunarTerm3);
+
+	// get leap year
+	tempReal = ((lunarTerm2 - lunarTerm1) / KMeanSynodicMonth);
+	Round(tempInt,tempReal);
+	if(tempInt == KMonthsInYear)
+		{
+		leapYear = ETrue;
+		}
+	else
+		{
+		leapYear = EFalse;
+		}
+
+	// get month
+	tempReal = ((lunarTerm3 - lunarTerm1) / KMeanSynodicMonth);
+	Round(tempInt,tempReal);
+	if(leapYear && PriorLeapMonth(lunarTerm1,lunarTerm3))
+		{
+		tempInt--;
+		}
+	Amod(tempReal,tempInt,KMonthsInYear);
+	Round(aDate.iMonth,tempReal);
+
+	// get leap month
+	majorSolarTerm = NoMajorSolarTerm(lunarTerm3);
+	if((leapYear) && majorSolarTerm && (!PriorLeapMonth(lunarTerm1,ChineseNewMoonBefore(lunarTerm3))))
+		{
+		aDate.iLeapMonth = ETrue;
+		}
+	else
+		{
+		aDate.iLeapMonth = EFalse;
+		}
+
+	// get elapsed years
+	elapsedYears = year - KFirstChinYear;
+
+	date.iDay = KCalConvFirstDay;
+	date.iMonth = EJuly + KCalConvMonthOffsetByOne;
+	date.iYear = year;
+	tempReal = greg.GregToJulianDay(date);
+	if((aDate.iMonth < (ENovember + KCalConvMonthOffsetByOne)) || (aJulianDay > tempReal))
+		{
+		elapsedYears++;
+		}
+
+	// get cycle
+	tempReal = (elapsedYears - KCalConvYearOffsetByOne) / KYearsInChinCycle;
+	Floor(aDate.iCycle,tempReal);
+	aDate.iCycle++;
+
+	// get year
+	Amod(tempReal,elapsedYears,KYearsInChinCycle);
+	Round(aDate.iYear,tempReal);
+
+	// get day
+	Floor(tempInt,aJulianDay);
+	aDate.iDay = tempInt;
+	Floor(tempInt,lunarTerm3);
+	aDate.iDay -= tempInt;
+	aDate.iDay += KCalConvDayOffsetByOne;
+	}
+
+//------------------------------------------------------
+// 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
+	{
+	TReal jD;
+	TChineseDate chinDate;
+
+	ChineseToFixed(aDate,jD);
+	ChineseFromFixed(chinDate,jD);
+
+	if(aDate.operator==(chinDate))
+		return ETrue;
+	else
+		return EFalse;
+	}
+
+//------------------------------------------------------
+// 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
+//------------------------------------------------------
+EXPORT_C void TChineseCalendar::ChineseToDateTime(TDateTime &aDT)
+	{
+	TArithmeticalDate gregDate;
+	TGregorianCalendar greg(iJulianDay);
+
+	greg.GregFromJulianDay(gregDate,iJulianDay);
+
+	aDT.SetMicroSecond(0);
+	aDT.SetSecond(0);
+	aDT.SetMinute(0);
+	aDT.SetHour(0);
+	aDT.SetMonth((TMonth)(gregDate.iMonth - KCalConvMonthOffsetByOne));
+	aDT.SetDay(gregDate.iDay - 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
+//------------------------------------------------------
+EXPORT_C 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:    ChineseToFixed
+// Arguments:   TChineseDate , TReal &
+//
+// Comments:    This function converts a chinese date to 
+//				to a julian day value.
+//
+// Return:      void
+//------------------------------------------------------
+void TChineseCalendar::ChineseToFixed(const TChineseDate& aDate, TReal &aJulianDay) const
+	{
+	TInt year;
+	TReal newYear;
+	TReal pi;
+	TReal priorNewMoon;
+	TReal yearReal;
+	TChineseDate chinDate;
+
+	// get year
+	yearReal = (aDate.iCycle - KCycleOffset) * KYearsInChinCycle;
+	Floor(year,yearReal);
+	year += aDate.iYear - KCalConvYearOffsetByOne;
+	year += KFirstChinYear;
+
+	// get new year
+	newYear = ChineseNewYear(year);
+
+	// get papa
+	pi = ChineseNewMoonOnOrAfter(newYear + ((aDate.iMonth - KCalConvMonthOffsetByOne) * 29));
+
+	// get delta
+	ChineseFromFixed(chinDate,pi);
+
+	// get priorNewMoon
+	if((aDate.iMonth == chinDate.iMonth) && (aDate.iLeapMonth == chinDate.iLeapMonth))
+		{
+		priorNewMoon = pi;
+		}
+	else
+		{
+		priorNewMoon = ChineseNewMoonOnOrAfter(pi + KCalConvDayOffsetByOne);
+		}
+
+	aJulianDay = priorNewMoon + aDate.iDay - KCalConvDayOffsetByOne;
+	}