tzservices/tzserver/Client/Source/vtzrules.cpp
changeset 0 2e3d3ce01487
child 81 676b6116ca93
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tzservices/tzserver/Client/Source/vtzrules.cpp	Tue Feb 02 10:12:00 2010 +0200
@@ -0,0 +1,1546 @@
+// Copyright (c) 2005-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:
+//
+
+#include <s32buf.h>
+#include <vtzrules.h>
+#include <tz.h>
+
+#include "tzrules.h"
+
+const TInt KDaysInTheWeek = 7;
+const TInt KTzRulesGranularity = 4;
+
+//
+// TVTzRule
+//
+
+/**
+Constructor for a time zone rule.
+
+@publishedAll
+@released
+
+@param aFrom The first date at which the rule applies.
+@param aTo The last date at which the rule applies.
+@param aOldOffset The UTC offset in minutes which applies before the DST change.
+@param aNewOffset The UTC offset in minutes which applies after the DST change.
+@param aMonth The month in which the DST change occurs.
+@param aDayRule The rule defining on which day the DST change takes place.
+@param aDayOfMonth The number of the day within the month, offset from zero.  Used in conjunction with 
+       aDayRule to define the day when DST changes.
+@param aDayOfWeek The number of the day within the week, the numerical equivalent of a TDay value.  
+       Used in conjunction with aDayRule to define the day where DST changes.
+@param aTimeReference Defines whether aTimeOfChange is a local (wall-clock) time or a UTC time.
+@param aTimeOfChange The time of the DST change in minutes from midnight.
+*/
+EXPORT_C TTzRule::TTzRule(TTimeWithReference aFrom, TTimeWithReference aTo, TInt16 aOldOffset, TInt16 aNewOffset, TMonth aMonth, TTzRuleDay aDayRule,
+				TUint8 aDayOfMonth, TUint8 aDayOfWeek, TTzTimeReference aTimeReference, TUint16 aTimeOfChange) :
+ 	iFrom(aFrom),
+	iTo(aTo),
+	iOldLocalTimeOffset(aOldOffset),
+	iNewLocalTimeOffset(aNewOffset),
+	iMonth(aMonth),
+	iDayRule(aDayRule),
+	iDayOfMonth(aDayOfMonth),
+	iDayOfWeek(aDayOfWeek),
+	iTimeReference(aTimeReference),
+	iTimeOfChange(aTimeOfChange)
+	{
+	}
+
+/**
+Constructor for a time zone rule.
+
+@publishedAll
+@released
+
+@param aFromYear The first year in which the rule applies.
+@param aToYear The last year in which the rule applies.
+@param aOldOffset The UTC offset in minutes which applies before the DST change.
+@param aNewOffset The UTC offset in minutes which applies after the DST change.
+@param aMonth The month in which the DST change occurs.
+@param aDayRule The rule defining on which day the DST change takes place.
+@param aDayOfMonth The number of the day within the month, offset from zero.  Used in conjunction with 
+       aDayRule to define the day where DST changes.  
+@param aDayOfWeek The number of the day within the week, the numerical equivalent of a TDay value.  
+       Used in conjunction with aDayRule to define the day where DST changes.
+@param aTimeReference Defines whether aTimeOfChange is a local (wall-clock) time or a UTC time.
+@param aTimeOfChange The time of the DST change in minutes from midnight.
+*/
+EXPORT_C TTzRule::TTzRule(TInt16 aFromYear, TInt16 aToYear, TInt16 aOldOffset, TInt16 aNewOffset, TMonth aMonth, TTzRuleDay aDayRule,
+				TUint8 aDayOfMonth, TUint8 aDayOfWeek, TTzTimeReference aTimeReference, TUint16 aTimeOfChange) :
+ 	iFrom(TTimeWithReference(TDateTime(aFromYear,EJanuary,0,0,0,0,0))),
+	iTo(TTimeWithReference(TDateTime(aToYear,EDecember,30,23,59,59,0))),
+	iOldLocalTimeOffset(aOldOffset),
+	iNewLocalTimeOffset(aNewOffset),
+	iMonth(aMonth),
+	iDayRule(aDayRule),
+	iDayOfMonth(aDayOfMonth),
+	iDayOfWeek(aDayOfWeek),
+	iTimeReference(aTimeReference),
+	iTimeOfChange(aTimeOfChange)
+	{
+	}
+
+/**
+Default constructor for a time zone rule.
+
+All member variables are set to zero values.
+
+@publishedAll
+@released
+*/
+EXPORT_C TTzRule::TTzRule() :
+	iOldLocalTimeOffset(0),
+	iNewLocalTimeOffset(0),
+	iMonth(EJanuary),
+	iDayRule(ETzFixedDate),
+	iDayOfMonth(0),
+	iDayOfWeek(0),
+	iTimeReference(ETzWallTimeReference),
+	iTimeOfChange(0)
+	{
+	}
+
+/**
+Copy constructor for a time zone rule.
+
+@publishedAll
+@released
+*/
+EXPORT_C TTzRule::TTzRule(const TTzRule& aRule) :
+ 	iFrom(aRule.iFrom),
+	iTo(aRule.iTo),
+	iOldLocalTimeOffset(aRule.iOldLocalTimeOffset),
+	iNewLocalTimeOffset(aRule.iNewLocalTimeOffset),
+	iMonth(aRule.iMonth),
+	iDayRule(aRule.iDayRule),
+	iDayOfMonth(aRule.iDayOfMonth),
+	iDayOfWeek(aRule.iDayOfWeek),
+	iTimeReference(aRule.iTimeReference),
+	iTimeOfChange(aRule.iTimeOfChange)
+	{
+	}
+
+/** 
+Externalises a time zone rule to a write stream.
+
+@param aStream Stream to which the object should be externalised. 
+@internalComponent
+@released
+*/ 
+void TTzRule::ExternalizeL(RWriteStream& aStream) const
+	{
+	aStream << iFrom.iTime.Int64();
+	aStream << static_cast<TInt32>(iFrom.iTimeReference);
+	aStream << iTo.iTime.Int64();
+	aStream << static_cast<TInt32>(iTo.iTimeReference);
+	aStream << iOldLocalTimeOffset;
+	aStream << iNewLocalTimeOffset;
+	aStream << static_cast<TInt32>(iMonth);
+	aStream << static_cast<TInt32>(iDayRule);
+	aStream << iDayOfMonth;
+	aStream << iDayOfWeek;
+	aStream << static_cast<TInt32>(iTimeReference);
+	aStream << iTimeOfChange;
+	}
+
+/** 
+Internalizes a time zone rule from a read stream.
+
+@param aStream Stream from which the object should be internalised. 
+@internalComponent
+@released
+*/ 
+void TTzRule::InternalizeL(RReadStream& aStream)
+	{
+	TInt64 time;
+	aStream >> time;	
+	iFrom.iTime = TTime(time);
+	iFrom.iTimeReference = static_cast<TTzTimeReference>(aStream.ReadInt32L());
+	aStream >> time;	
+	iTo.iTime = TTime(time);
+	iTo.iTimeReference = static_cast<TTzTimeReference>(aStream.ReadInt32L());
+	aStream >> iOldLocalTimeOffset;
+	aStream >> iNewLocalTimeOffset;
+	iMonth = static_cast<TMonth>(aStream.ReadInt32L());
+	iDayRule = static_cast<TTzRuleDay>(aStream.ReadInt32L());
+	aStream >> iDayOfMonth;
+	aStream >> iDayOfWeek;
+	iTimeReference = static_cast<TTzTimeReference>(aStream.ReadInt32L());
+	aStream >> iTimeOfChange;
+	}
+
+
+/** 
+Check if a time zone rule is applicable during a time range.
+
+@return ETrue if the rule applies during the supplied time range, EFalse otherwise.
+@param aStart Start of time range, inclusively.  ie. For a rule to be applicable, this time
+       can be equal to or earlier than the rule's end time.  This time should use the same 
+       time reference used when TTzRule is constructed.
+@param aEnd End of time range, exclusively.  ie. In order for a rule to be applicable, this 
+       time must be later than the rule's start time.  This time should use the same 
+       time reference used when TTzRule is constructed.
+@internalComponent
+@released
+*/ 
+TBool TTzRule::RuleApplies(const TTime& aStart, const TTime& aEnd) const
+ 	{
+	// If the end of the rule is in the time range or the beginning of the rule is in the time range
+	return ( (iTo.iTime >= aStart) && (iFrom.iTime < aEnd) );
+ 	}
+
+/**
+Resolves the date rule to the precise date and time for the given year, and
+returns it in a TVTzActualisedRule
+
+For day rules ETzDayAfterDate & ETzDayBeforeDate, the reference date entered 
+is inclusive in the calculation.  ie. If the reference date fits the criteria,
+the reference date will be returned.   
+
+eg. Actualise(Friday, ETzDayAfterDate, Fri Jun 22, 2007) returns Jun 22, 2007.
+
+Deprecated.  Use TVTzActualisedRule TTzRule::ActualiseL instead.
+
+@return The time zone rule with the precise date and time for the given year.
+@param aYear Year to actualise time rules
+@publishedAll
+@deprecated 
+@see TVTzActualisedRule TTzRule::ActualiseL(TInt aYear) const
+*/
+EXPORT_C TVTzActualisedRule TTzRule::Actualise(TInt aYear) const
+    {
+    TVTzActualisedRule rule;
+    TRAP_IGNORE(rule = ActualiseL(aYear));        
+    return rule;
+    }
+
+/**
+Resolves the date rule to the precise date and time for the given year, and
+returns it in a TVTzActualisedRule
+
+For day rules ETzDayAfterDate & ETzDayBeforeDate, the reference date entered 
+is inclusive in the calculation.  ie. If the reference date fits the criteria,
+the reference date will be returned.   
+
+eg. Actualise(Friday, ETzDayAfterDate, Fri Jun 22, 2007) returns Jun 22, 2007.
+
+@return The time zone rule with the precise date and time for the given year.
+@param aYear Year to actualise time rules
+@leave KErrCorrupt if the current day rule is not one of the defined values in TTzRuleDay
+@publishedAll
+@released
+*/
+EXPORT_C TVTzActualisedRule TTzRule::ActualiseL(TInt aYear) const
+	{
+	TInt dayOfMonth = iDayOfMonth;
+	TInt daysDifference = 0;
+	TDay dayOfWeek(EMonday);
+
+	TDateTime actualDateTime(aYear,
+						(TMonth)iMonth,
+						dayOfMonth,
+						(iTimeOfChange / 60),
+						(iTimeOfChange % 60),
+						0,
+						0);
+	TTime actualTime(actualDateTime);
+	switch(iDayRule)
+		{
+		case ETzFixedDate:
+			// do nothing
+			break;
+
+		case ETzDayAfterDate:
+			// e.g. "Sunday after the 15th"
+
+			// find day in week for given date
+			dayOfWeek = actualTime.DayNoInWeek();
+
+			// find difference in days to the rule date
+			daysDifference = iDayOfWeek - dayOfWeek;
+			// make positive difference
+			if (daysDifference < 0)
+				{
+				daysDifference += KDaysInTheWeek;	// sunday is last day of month
+				}
+
+			// set actual day
+			dayOfMonth += daysDifference;
+			actualDateTime.SetDay(dayOfMonth);
+			break;
+
+		case ETzDayBeforeDate:
+			// e.g. "Sunday before the 15th"
+
+			// find day in week for given date
+			dayOfWeek = actualTime.DayNoInWeek();
+
+			// find difference in days to the rule date
+			daysDifference = dayOfWeek - iDayOfWeek;
+			// make positive difference
+			if (daysDifference < 0)
+				{
+				daysDifference += KDaysInTheWeek;	// sunday is last day of month
+				}
+
+			// set actual day
+			dayOfMonth -= daysDifference;
+			actualDateTime.SetDay(dayOfMonth);
+			break;
+
+		case ETzDayInLastWeekOfMonth:
+			// e.g. "last Sunday in the month"
+
+			// initialise the day to the last day in the month,
+			dayOfMonth = actualTime.DaysInMonth() - 1; // days offset from 0
+			actualDateTime.SetDay(dayOfMonth);
+
+			// find day in week for given date
+			actualTime = actualDateTime;
+			dayOfWeek = actualTime.DayNoInWeek();
+
+			// find difference in days to the rule date
+			daysDifference = dayOfWeek - iDayOfWeek;
+			// make positive difference
+			if (daysDifference < 0)
+				{
+				daysDifference += KDaysInTheWeek;	// sunday is last day of month
+				}
+
+			// set actual day
+			dayOfMonth -= daysDifference;
+			actualDateTime.SetDay(dayOfMonth);
+			break;
+
+		default:
+			User::Leave(KErrCorrupt);  // If data is corrupt method leaves
+			break;
+		}
+
+	actualTime = actualDateTime;
+
+	TVTzActualisedRule tActRule(actualTime, 
+		iNewLocalTimeOffset, 
+		static_cast<TTzTimeReference>(iTimeReference));
+	return tActRule;
+	}
+
+//
+// CTzRules
+//
+
+/**
+Creates a new time zone rules object.
+@return Pointer to the time zone rules.
+@publishedAll
+@released
+*/
+EXPORT_C CTzRules* CTzRules::NewL()
+	{
+	CTzRules* self = new(ELeave) CTzRules();
+	return self;
+	}
+
+/**
+Creates a new time zone rules object.
+@param aStartYear The first year in which these time zone rules apply.
+@param aEndYear The last year in which these time zone rules apply.
+@return Pointer to the time zone rules.
+@publishedAll
+@released
+*/
+EXPORT_C CTzRules* CTzRules::NewL(TInt aStartYear, TInt aEndYear)
+	{
+	CTzRules* self = new(ELeave) CTzRules(aStartYear,aEndYear);
+	return self;
+	}
+
+/**
+Creates a new time zone rules object from a stream.
+@return Pointer to the time zone rules.
+@param aStream Stream with the time zone rules to be used to create a CTzRules object.
+@publishedAll
+@released
+*/
+EXPORT_C CTzRules* CTzRules::NewL(RReadStream& aStream)
+	{
+	CTzRules* self = new(ELeave) CTzRules();
+	CleanupStack::PushL(self);
+	self->InternalizeL(aStream);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CTzRules::CTzRules(TInt aStartYear, TInt aEndYear) :
+	iStartYear((TInt16)aStartYear),
+	iEndYear((TInt16)aEndYear),
+	iRules(KTzRulesGranularity)
+	{
+	}
+
+CTzRules::CTzRules() :
+	iRules(KTzRulesGranularity)
+	{
+	}
+
+/**
+Destructor.
+@publishedAll
+@released
+*/
+EXPORT_C CTzRules::~CTzRules()
+	{
+	delete iActualisedRulesCache;
+	iRules.Reset();
+	}
+
+/**
+Get the object size when it is internalize and externalised.
+
+@return the size of thisobject 
+@internalComponent
+@released
+*/
+EXPORT_C TInt CTzRules::SizeOfObject() const
+	{
+	return iRules.Count() * sizeof (TTzRule) + 4*sizeof (TInt16);
+	//As to 4 size of TInt16, they are for iStartYear, iEndYear, iInitialStdTimeOffset and the count of array of TTzRule
+	}
+/**
+Internalizes time zone rules from a read stream.
+
+@param aStream Stream from which the object should be internalised. 
+@publishedAll
+@released
+*/
+EXPORT_C void CTzRules::InternalizeL(RReadStream& aStream)
+	{
+	iRules.Reset();
+
+	// read start and end year covered by rules
+	iStartYear = aStream.ReadInt16L();
+	iEndYear = aStream.ReadInt16L();
+
+	// read initial std time offset
+	iInitialStdTimeOffset = aStream.ReadInt16L();
+	
+	// read number of rules
+	const TInt16 KCount = aStream.ReadInt16L();
+
+	// read rules
+	TTzRule rule;
+	for (TInt i = 0; i < KCount; ++i)
+		{
+		rule.InternalizeL(aStream);
+		User::LeaveIfError(iRules.Append(rule));
+		}
+	
+	// The cache has been invalidated so clear it
+	delete iActualisedRulesCache;
+	iActualisedRulesCache = NULL;
+	}
+
+/** 
+Externalises time zone rules to a write stream.
+
+@param aStream Stream to which the object should be externalised. 
+@leave KErrArgument if the output stream size is invalid
+@publishedAll
+@released
+*/
+EXPORT_C void CTzRules::ExternalizeL(RWriteStream& aStream) const
+	{
+	// Ensure the size of the stream is valid.
+	TInt size = aStream.Sink()->SizeL();
+	const TInt KMaxSize = KMaxTInt / 2;
+	if (size < 0 || size >= KMaxSize)
+	    {
+	    User::Leave(KErrArgument);
+	    }
+
+	// write range of years covered by rules
+	aStream.WriteInt16L(iStartYear);
+	aStream.WriteInt16L(iEndYear);
+	
+	// write initial std time offset
+	aStream.WriteInt16L(iInitialStdTimeOffset);
+	
+	// write number of rules
+	const TInt16 KCount = (TInt16)iRules.Count();
+	aStream.WriteInt16L(KCount);
+
+	// write rules
+	for (TInt i = 0; i < KCount; i++)
+		{
+		iRules[i].ExternalizeL(aStream);
+		}
+	}
+
+/**
+Gets the first year in which the time zone rules apply.
+@return The year.
+@publishedAll
+@released
+*/
+EXPORT_C TInt CTzRules::StartYear() const
+	{
+	return iStartYear;
+	}
+
+/**
+Gets the last year in which the time zone rules apply.
+@return The year.
+@publishedAll
+@released
+*/
+EXPORT_C TInt CTzRules::EndYear() const
+	{
+	return iEndYear;
+	}
+
+/**
+Sets the first year in which the time zone rules apply.
+@param aYear The year.
+@publishedAll
+@released
+*/
+EXPORT_C void CTzRules::SetStartYear(TInt aYear)
+	{
+	iStartYear = (TInt16)aYear;
+	}
+
+/**
+Sets the last year in which the time zone rules apply.
+@param aYear The year.
+@publishedAll
+@released
+*/
+EXPORT_C void CTzRules::SetEndYear(TInt aYear)
+	{
+	iEndYear = (TInt16)aYear;
+	}
+
+/**
+Gets the number of time zone rules (TTzRules) in this set.
+@return The number of rules.
+@publishedAll
+@released
+*/
+EXPORT_C TInt CTzRules::Count() const
+	{
+	return iRules.Count();
+	}
+
+/**
+Gets the initial UTC offset for this set of time zone rules.
+@return The offset in minutes.
+@publishedAll
+@released
+*/
+EXPORT_C TInt CTzRules::InitialStdTimeOffset() const
+	{
+	return iInitialStdTimeOffset;
+	}
+	
+/**
+Sets the initial UTC offset for this set of time zone rules.
+@param aOffset The offset in minutes.
+@publishedAll
+@released
+*/
+EXPORT_C void CTzRules::SetInitialStdTimeOffset(TInt aOffset)
+	{
+	// The cache has been invalidated so clear it
+	delete iActualisedRulesCache;
+	iActualisedRulesCache = NULL;
+	
+	iInitialStdTimeOffset = aOffset;
+	}
+	
+/**
+Adds a time zone rule to this set.
+@param aTRule The rule to be added.
+@publishedAll
+@released
+*/
+EXPORT_C void CTzRules::AddRuleL(TTzRule aTRule)
+	{
+	// the cache has been invalidated so clear it
+	delete iActualisedRulesCache;
+	iActualisedRulesCache = NULL;
+	
+	TInt result = iRules.Append(aTRule);
+	User::LeaveIfError(result);
+	}
+
+/**
+Removes a time zone rule from this set.
+@param aIndex The index of the rule to be removed.
+@publishedAll
+@released
+*/
+EXPORT_C void CTzRules::RemoveRule(TInt aIndex)
+	{
+	// the cache has been invalidated so clear it
+	delete iActualisedRulesCache;
+	iActualisedRulesCache = NULL;
+		
+	iRules.Remove(aIndex);
+	}
+
+/**
+Gets a time zone rule from this set.
+@param aIndex The index of the rule to be fetched.
+@return Reference to the time zone rule.
+@publishedAll
+@released
+*/
+EXPORT_C TTzRule& CTzRules::operator[](TInt aIndex)
+	{
+	// prevent array bounds error
+	__ASSERT_ALWAYS( (aIndex < iRules.Count() && aIndex >= 0), RTz::Panic(RTz::EPanicRulesIndexOutofRange));
+	
+	return iRules[aIndex];
+	}
+
+/**
+Queries the time zone rule set to see if they apply to a specified time.
+@param aTime The time to be checked, using the same time reference used when constructing 
+       CTzRules.
+@return ETrue if the time zone rules apply to the specified time. EFalse if not.
+@publishedAll
+@released
+*/
+ EXPORT_C TBool CTzRules::RulesApply(const TTime& aTime) const
+ 	{
+	const TTime KStart(TDateTime(iStartYear, EJanuary, 0, 0, 0, 0, 0));
+	const TTime KEnd(TDateTime(iEndYear + 1, EJanuary, 0, 0, 0, 0, 0));
+	return ((aTime >= KStart) && (aTime < KEnd));
+ 	}
+
+
+/**
+
+Compares two times with time references (TTzTimeReference).
+TTzTimeReference is either UTC, or STD, or ETzWallTimeReference.
+
+Comparison is done at some point in time when aStdOffset applies to item(s) with ETzStdTimeReference, 
+and aWallOffset applies to item(s) with ETzWallTimeReference.
+
+If time references for both aTimeA and aTimeB are the same, then straight comparison is done to 
+aTimeA and aTimeB. Otherwise, STD or wall-clock time is converted to UTC using either aStdOffset, 
+or aWallOffset correspondingly.
+
+Thus, aStdOffset parameter is never used if none of aTimeA and aTimeB is ETzStdTimeReference;
+and, similarly, aWallOffset is never used if none of aTimeA and aTimeB is ETzWallTimeReference.
+
+@param	aTimeA		- first time with reference;
+@param	aTimeB		- second time with reference, to compare to aTimeA;
+@param	aStdOffset	- an offset (in minutes) to be used for a time with ETzStdTimeReference;
+@param	aWallOffset	- an offset (in minutes) to be used for a time with ETzWallTimeReference;
+@param	aMinutesDifference	-on return, the time difference between aTimeA and aTimeB in minutes;
+
+@return TInt		-1 if aTimeA is < aTimeB;
+					 0 if aTimeA is equal to aTimeB;
+					 1 if aTimeA is > aTimeB.	 
+Example: 
+	compare 20050403T020200 local with 20050403T020100Z UTC in PST time zone (-0800):
+			CompareTimesWithRef(20050403T020200, wall, 20050403T020100, utc, 0(not used), -8(PST))  gives -1;
+	while 	CompareTimesWithRef(20050403T020200, wall, 20050403T020100, utc, 0(not used), 0(GMT))  gives 1.
+
+@internalComponent
+@released
+ */ 
+TInt CTzRules::CompareTimesWithRef(TTime aTimeA, TTzTimeReference aTimeARef,
+								   TTime aTimeB, TTzTimeReference aTimeBRef,
+								   TInt aStdOffset, TInt aWallOffset, TTimeIntervalMinutes* aMinutesDifference) const
+	{
+	TTime timeA(aTimeA), timeB(aTimeB);
+	if (aTimeARef != aTimeBRef)
+		{
+		if (aTimeARef == ETzStdTimeReference)
+			{
+			timeA -= TTimeIntervalMinutes(aStdOffset);	
+			}
+		if (aTimeARef == ETzWallTimeReference)
+			{
+			timeA -= TTimeIntervalMinutes(aWallOffset);	
+			}
+		if (aTimeBRef == ETzStdTimeReference)
+			{
+			timeB -= TTimeIntervalMinutes(aStdOffset);	
+			}
+		if (aTimeBRef == ETzWallTimeReference)
+			{
+			timeB -= TTimeIntervalMinutes(aWallOffset);	
+			}
+		}
+
+	if (aMinutesDifference)
+		{
+		timeA.MinutesFrom(timeB, *aMinutesDifference);
+		}
+
+	return (timeA<timeB) ? -1 : ((timeA>timeB) ? 1 : 0);
+	}
+
+/**
+Based on the rules in the object calculates actualised rules for particular year and adds them
+to the specified array of actualised rules (CVTzActualisedRules).
+
+@param	aActRules	- an array of actualised rules where new actualised rules are added;
+@param	aYear		- a year for which actualised rules are added.
+
+@internalComponent
+@released
+*/
+void CTzRules::AddActualisedRulesL(CVTzActualisedRules& aActRules, TInt aYear) const
+   	{
+   	const TInt count=iRules.Count();
+   	const TTzRule* trule = NULL;
+
+	const TTime KYearBegin(TDateTime(aYear, EJanuary, 0, 0, 0, 0, 0));
+	const TTime KYearEnd(TDateTime(aYear + 1, EJanuary, 0, 0, 0, 0, 0));
+
+   	for (TInt i = 0; i < count; i++)
+   		{
+   		trule = &(iRules[i]);
+   		if ( trule->RuleApplies(KYearBegin, KYearEnd))
+   			{
+   			TVTzActualisedRule tactRule = trule->Actualise(aYear);
+   
+   			// ETzStdTimeReference is not useful for VTIMEZONE or for conversions
+   			if(trule->iTimeReference == ETzStdTimeReference)
+   				{
+				//# Time: Time for the DST switch. Important: sometimes the time is followed by a letter. The meaning of this letter is:
+				//no letter or w: wall clock time, actual local time.
+				//s: local standard time (winter time)
+				//u or g or z: UTC time.
+				//So, if a 'DST on' time is given as '0:00s', this means a switch on 0:00 local time.
+   				//If a 'DST off' time is given as '0:00s', this means a switch on 1:00 local time (assuming a DST offset of 1 hour).
+   				
+   				//DST off time is always the lowest among the two.
+				//We do not want to use the oldlocaltimeoffset for DST Off conditions.
+   				TInt standardOffset = trule->iOldLocalTimeOffset;
+   				if(trule->iNewLocalTimeOffset < trule->iOldLocalTimeOffset)
+   					{
+   					standardOffset = trule->iNewLocalTimeOffset;
+   					}
+   				tactRule.iTimeOfChange -= TTimeIntervalMinutes(standardOffset);
+   				tactRule.iTimeReference = ETzUtcTimeReference;
+   				}
+   				
+  			if ( 0 >= CompareTimesWithRef(tactRule.iTimeOfChange, tactRule.iTimeReference,
+  											trule->iTo.iTime, trule->iTo.iTimeReference,
+  											0, trule->iOldLocalTimeOffset, NULL) )
+  				{
+  				// tactRule.iTimeOfChange w/ref is less or equal to trule->iTo
+
+  				/*Fix for INC117764:
+				Before adding make sure that rule does not occur before the rules which have already been added.
+				For Ex-"Europe\Tirane" 
+				1) Rule Starts at 1/4/1984, Rule Ends at 30/6/1984, Old offset = 60, New Offset = 120 (Summer rule)
+				2) Rule Starts at 1/7/1984, Rule Ends at 1/7/1984, Old offset = 60, New Offset = 120 (Summer rule contd.)
+				3) Rule Starts at 1/9/1984, Rule Ends at 31/12/1995, Old offset = 60, New Offset = 60(winter rule) 
+				4) Rule Starts at 1/3/1984, Rule Ends at 31/12/9998, Old offset = 60, New Offset = 120 (Summer Rule)
+				The 4th rule should follow from 7/7/1984 onwards, otherwise if 4th rule is actualised for year 1984
+				it would look like --Rule Starts at 1/3/1984, NewOffset = 120, this will cause issues when converting time in March since summer
+				time won't start until April 1984.
+				*/
+  				TBool ruleAdded = ETrue;
+				for(TInt loop = aActRules.Count()-1; loop >=0; --loop)
+					{
+					TVTzActualisedRule prevActRule = aActRules[loop];
+					TDateTime prevRdt = prevActRule.iTimeOfChange.DateTime();
+					TDateTime actRdt = tactRule.iTimeOfChange.DateTime();	
+					if(actRdt.Year() > prevRdt.Year())
+						{
+						//no covering rule for this year in previously added rules
+						//no need of looking into other year rules
+						break;						
+						}
+					if(actRdt.Year() == prevRdt.Year() &&
+					   actRdt.Month() < prevRdt.Month() &&
+					   tactRule.iNewOffset == prevActRule.iNewOffset)
+						{
+						//covering rule already exists so dont add this one
+						ruleAdded = EFalse;
+						break;
+						}	
+					}
+				if(ruleAdded)
+					{
+					aActRules.AddRuleL(tactRule);	
+					}
+  				}
+			}
+   		}
+   	}
+
+/**
+Get actualised rules for time zone rules.
+@param aActRules Actualised rules for time zone rules.
+@publishedAll
+@released
+*/
+EXPORT_C void CTzRules::GetActualisedRulesL(CVTzActualisedRules& aActRules) const
+	{
+	// Always add the initial offset because there may not have been
+	// any rules to actualise before the actualised rules range specified
+	TVTzActualisedRule tDefRule(TDateTime(iStartYear, EJanuary, 0, 0, 0, 0, 0), iInitialStdTimeOffset, ETzWallTimeReference);
+	aActRules.AddRuleL(tDefRule);
+	
+	if (iRules.Count() == 0)
+		{
+		// do nothing
+		}
+	if (iRules.Count() == 1)
+		{
+		// There is only one rule, perhaps this is an unknown timezone
+		// or a timezone that has never had DST, so just add that one rule
+		
+		TVTzActualisedRule tDefRule(TDateTime(aActRules.StartYear(), EJanuary, 0, 0, 0, 0, 0), iRules[0].iNewLocalTimeOffset, ETzWallTimeReference);
+		aActRules.AddRuleL(tDefRule);
+		}
+	else
+		{
+		// Add actualised rules for the year range spcified in aActRules
+		// also make sure that a year before this range is actualised
+		// so that the initial offset for the actualised rules range is correct
+		
+		TInt32 year(0);
+		for (year = aActRules.EndYear() ; year >= aActRules.StartYear() ; --year) 
+			{
+			AddActualisedRulesL(aActRules, year);
+			}
+		
+		// try to add an actualised rule for the previous year
+		// so that the start of the range will be correct
+		const TInt KActRulesCount(aActRules.Count());
+		AddActualisedRulesL(aActRules, year);
+		
+		if (aActRules.Count() == KActRulesCount)
+			{
+			// No rules were added for the year before the range being actualised
+			// so find the first rule that applies before this year
+			
+			TTime timeSoFar(TDateTime(iStartYear, EJanuary, 0, 0, 0, 0, 0));	
+			TTime endTime(TDateTime(year, EJanuary, 0, 0, 0, 0, 0));
+			
+			TBool found(EFalse);
+			
+			for (TInt i(iRules.Count() - 1) ; i >= 0 ; --i)
+				{
+				if (iRules[i].iTo.iTime > timeSoFar && iRules[i].iTo.iTime < endTime)
+					{
+					timeSoFar = iRules[i].iTo.iTime;
+					found = ETrue;
+					}
+				}
+			
+			if (found)
+				{
+				AddActualisedRulesL(aActRules, timeSoFar.DateTime().Year());
+				}
+			}
+		}
+	}
+
+/**
+Converts the received local time to UTC time.
+@param aTime The time to convert. On return, this contains the converted time.
+@publishedAll
+@released
+*/ 
+EXPORT_C void CTzRules::ConvertToUtcL(TTime& aTime) const
+	{
+	// This check would not be necessary if we can ensure this function
+	// is never called with a null TTime
+	if (aTime == Time::NullTTime())
+		{
+		return;
+		}
+	
+	TInt offset = GetOffsetL(aTime, ETzWallTimeReference);
+	aTime -= (TTimeIntervalMinutes)(offset);	
+	}
+
+/**
+Converts the received UTC time to local time.
+@param aTime The time to convert. On return, this contains the converted time.
+@publishedAll
+@released
+*/
+EXPORT_C void CTzRules::ConvertToLocalL(TTime& aTime) const
+	{
+	// This check would not be necessary if we can ensure this function
+	// is never called with a null TTime	
+	if (aTime == Time::NullTTime())
+		{
+		return;
+		}
+	
+	TInt offset = GetOffsetL(aTime, ETzUtcTimeReference);
+	aTime += (TTimeIntervalMinutes)(offset);	
+	}
+	
+/**
+Calculate the local time offset at the supplied time.
+
+@return local time offset
+@internalComponent
+@released
+*/
+EXPORT_C TInt CTzRules::GetOffsetL(const TTime& aTime, TTzTimeReference aTimeRef) const
+	{
+	if (iActualisedRulesCache)
+		{
+		TTime startTime(TDateTime(iActualisedRulesCache->StartYear(), EJanuary, 0, 0, 0, 0, 0));	
+		TTime endTime(TDateTime(iActualisedRulesCache->EndYear() + 1, EJanuary, 0, 0, 0, 0, 0));
+		
+		if (aTime >= startTime && aTime <= endTime)
+			{
+			return iActualisedRulesCache->GetOffsetFromRuleL(aTime, aTimeRef);
+			}
+		}
+
+	TInt year(aTime.DateTime().Year());
+			
+	// actualise rules
+	delete iActualisedRulesCache;
+	iActualisedRulesCache = NULL;
+	iActualisedRulesCache = CVTzActualisedRules::NewL(year, year);
+	TRAPD(leaveCode,GetActualisedRulesL(*iActualisedRulesCache));
+	if(leaveCode != KErrNone)
+		{
+		delete iActualisedRulesCache;
+		iActualisedRulesCache = NULL;
+		User::LeaveIfError(leaveCode);		
+		}
+	
+	return iActualisedRulesCache->GetOffsetFromRuleL(aTime, aTimeRef);;
+	}
+
+/**
+Creates a copy of these timezone rules.
+
+@capability None
+@return A pointer to the CTzRules copy.
+@publishedAll
+@released
+*/
+EXPORT_C CTzRules* CTzRules::CloneL() const
+	{
+	CTzRules* newRules = CTzRules::NewL();
+	CleanupStack::PushL(newRules);
+	
+	newRules->SetStartYear(iStartYear);
+	newRules->SetEndYear(iEndYear);
+	newRules->SetInitialStdTimeOffset(iInitialStdTimeOffset);
+	
+	TInt numRules = Count();
+	for (TInt i = 0; i < numRules; i++)
+		{
+		newRules->AddRuleL(iRules[i]);
+		}
+	
+	CleanupStack::Pop(newRules);
+	return newRules;
+	}
+
+/** Copy a time zone rule to this time zone rule.
+
+@capability None
+@param aTzRule A rule to copy from.
+@internalAll
+@released
+*/
+EXPORT_C void CTzRules::CopyL(const CTzRules& aTzRule)
+	{
+	SetStartYear(aTzRule.iStartYear);
+	SetEndYear(aTzRule.iEndYear);
+	SetInitialStdTimeOffset(aTzRule.iInitialStdTimeOffset);
+	iRules.Reset();	
+	const TInt numRules = aTzRule.Count();
+	for (TInt i = 0; i < numRules; i++)
+		{
+		AddRuleL(aTzRule.iRules[i]);
+		}
+	}
+/**
+Compares two sets of timezone rules.
+
+@capability None
+@param aRules The timezone rules to compare with.
+@return ETrue if the rules are identical. EFalse if not.
+@publishedAll
+@released
+*/
+EXPORT_C TBool CTzRules::IsEqualTo(const CTzRules& aRules) const
+	{
+	if (iStartYear != aRules.StartYear() ||
+		iEndYear != aRules.EndYear() ||
+		iInitialStdTimeOffset != aRules.InitialStdTimeOffset() ||
+		Count() != aRules.Count())
+		{
+		return EFalse;
+		}
+
+	const TInt KRuleCount(Count());
+	for (TInt i = 0; i < KRuleCount; i++)
+		{
+		TTzRule rule1 = const_cast<CTzRules&>(*this)[i];
+		TTzRule rule2 = const_cast<CTzRules&>(aRules)[i];
+		
+		if (rule1.iFrom != rule2.iFrom ||
+			rule1.iTo != rule2.iTo ||
+			rule1.iOldLocalTimeOffset != rule2.iOldLocalTimeOffset ||
+			rule1.iNewLocalTimeOffset != rule2.iNewLocalTimeOffset ||
+			rule1.iMonth != rule2.iMonth ||
+			rule1.iDayRule != rule2.iDayRule ||
+			rule1.iDayOfMonth != rule2.iDayOfMonth ||
+			rule1.iDayOfWeek != rule2.iDayOfWeek ||
+			rule1.iTimeReference != rule2.iTimeReference ||
+			rule1.iTimeOfChange != rule2.iTimeOfChange )
+			{
+			return EFalse;
+			}
+		}
+	return ETrue;
+	}
+	
+/**
+Converts between local (wall-clock) and UTC times.
+
+@return KErrNone if successful, otherwise KErrNotSupported or KErrNotFound
+@param aRules The actualised rules to use.
+@param aTime The time to convert, specified by aTimerRef if the time is in UTC or local time. On return, 
+       it will contain the converted time from UTC to local time or vice versa, depending on aTimerRef's value. 
+@param aTimerRef What aTime is expressed in.
+@publishedAll
+@released
+*/
+EXPORT_C TInt CTzRules::ConvertTime(CVTzActualisedRules& aRules, TTime& aTime, TTzTimeReference aTimeRef) const
+	{
+	TInt results = KErrNone;
+	TInt offset = 0;
+
+#ifdef _DEBUG
+	TDateTime aDateTime = aTime.DateTime();
+#endif
+	
+	TRAP( results, offset = aRules.GetOffsetFromRuleL(aTime, aTimeRef));
+	
+	if (results == KErrNone)
+		{
+		switch (aTimeRef)
+			{
+			case ETzUtcTimeReference:
+				aTime += TTimeIntervalMinutes(offset);
+				break;
+			case ETzWallTimeReference:
+				aTime -= TTimeIntervalMinutes(offset);
+				break;
+			default:
+				results = KErrNotSupported;
+				break;
+			}
+		}
+
+	return (results);
+	}
+
+//
+// TVTzActualisedRule
+//
+
+/** 
+Constructor for an actualised rule (local time change).
+
+@param aTimeOfChange Time of local time change
+@param aNewOffset New UTC offset in minutes 
+@param aTimeReference Time reference
+@publishedAll
+@released
+*/
+EXPORT_C TVTzActualisedRule::TVTzActualisedRule(TTime aTimeOfChange, TInt aNewOffset, TTzTimeReference aTimeReference) :
+	iTimeOfChange(aTimeOfChange),
+	iNewOffset(aNewOffset),
+	iTimeReference(aTimeReference)
+	{
+	}
+
+
+/** 
+Default constructor for an actualised rule (local time change).
+@publishedAll
+@released
+*/
+EXPORT_C TVTzActualisedRule::TVTzActualisedRule() :
+	iTimeOfChange(0),
+	iNewOffset(0),
+	iTimeReference(ETzUtcTimeReference)
+	{
+	}
+
+/** 
+Assignment operator for an actualised rule.
+@param aRule Actualised rule
+@publishedAll
+@released
+*/
+EXPORT_C void TVTzActualisedRule::operator=(TVTzActualisedRule aRule)
+	{
+	iTimeOfChange = aRule.iTimeOfChange;
+	iNewOffset = aRule.iNewOffset;
+	iTimeReference = aRule.iTimeReference;
+	}
+
+/**
+Order actualised rules by time of local time change.
+@internalComponent
+@released
+*/
+TInt TVTzActualisedRule::Order(const TVTzActualisedRule& aLeft, const TVTzActualisedRule& aRight)
+	{
+	if (aLeft.iTimeOfChange < aRight.iTimeOfChange)
+		{
+		return -1;
+		}
+	if (aLeft.iTimeOfChange == aRight.iTimeOfChange)
+		{
+		return 0;
+		}
+	return 1;
+	}
+
+
+//
+// CVTzActualisedRules
+//
+
+/**
+Factory method for CVTzActualisedRules objects.
+Creates a new instance of CVTzActualizedRules - an array of actualised rules (TVTzActualisedRule).
+
+The array of rules can be populated later by invoking CTzRules::GetActualisedRulesL() method.
+
+Rules in the array are sorted ascending by rule's start time (TVTzActualisedRule.iTimeOfChange);
+The very first rule in the array, if present, defines "default standard rule" for the time zone 
+indicating the STD time offset from UTC, in effect from the start of the first year (aStartYear).
+
+@param aStartYear, aEndYear	- specify range of years for to which actualised rules apply.
+@return 	A pointer to the newly created rules.
+@panic RTz 10 if aStartYear is larger than aEndYear.
+@publishedAll
+@released
+*/
+EXPORT_C CVTzActualisedRules* CVTzActualisedRules::NewL(TInt aStartYear, TInt aEndYear)
+	{
+	__ASSERT_ALWAYS(aStartYear <= aEndYear, RTz::Panic(RTz::EPanicInvalidArgument));  
+
+	CVTzActualisedRules* self = new (ELeave) CVTzActualisedRules(aStartYear, aEndYear);
+	return self;
+	}
+
+/**
+Constructor.
+@internalComponent
+@released
+*/
+CVTzActualisedRules::CVTzActualisedRules(TInt aStartYear, TInt aEndYear) :
+	iStartYear(aStartYear),
+	iEndYear(aEndYear),
+	iRules(KVTzRulesGranularity)
+	{
+	}
+
+/**
+Default constructor.
+@internalComponent
+@released
+*/
+CVTzActualisedRules::CVTzActualisedRules() :
+	iRules(KVTzRulesGranularity)
+	{
+	}
+
+/**
+Destructor.
+@publishedAll
+@released
+*/
+EXPORT_C CVTzActualisedRules::~CVTzActualisedRules()
+	{
+	iRules.Reset();
+	}
+
+/**
+Returns specified TVTzActualisedRule.
+
+@param aIndex Index of a rule
+@return A reference to TVTzActualised rule at index aIndex.
+@panic RTz 4 if aIndex is out of bounds.
+@publishedAll
+@released
+*/
+EXPORT_C TVTzActualisedRule& CVTzActualisedRules::operator[](TInt aIndex) const
+	{
+	// prevent array bounds error
+	__ASSERT_ALWAYS( (aIndex < iRules.Count() && aIndex >= 0), RTz::Panic(RTz::EPanicRulesIndexOutofRange));
+	
+	return const_cast<TVTzActualisedRule&>(iRules[aIndex]);
+	}
+
+/** 
+Add an actualised rule to the collection.
+
+@param aRule An actualised rule to be added into the collection.
+@publishedAll
+@released
+*/
+EXPORT_C void CVTzActualisedRules::AddRuleL(const TVTzActualisedRule& aRule)
+	{
+	TLinearOrder<TVTzActualisedRule> order(TVTzActualisedRule::Order);
+	
+	User::LeaveIfError(iRules.InsertInOrderAllowRepeats(aRule, order));
+	}
+
+/**
+Returns number of rules currently held in array of rules.
+
+@return Number of rules.
+@publishedAll
+@released
+*/
+EXPORT_C TInt CVTzActualisedRules::Count() const
+	{
+	return iRules.Count();
+	}
+
+/**
+Returns min year of the year range the CVTzActualisedRules object describes the rules for.
+It is guaranteed that the array of rules does not contain any rules for years before that min year.
+
+@return 	Start year (e.g. 1998).
+@publishedAll
+@released
+*/
+EXPORT_C TInt CVTzActualisedRules::StartYear() const
+	{
+	return iStartYear;
+	}
+
+/**
+Returns max year of the year range the CVTzActualisedRules object describes the rules for.
+
+@return 	End year (e.g. 2005).
+@publishedAll
+@released
+*/
+EXPORT_C TInt CVTzActualisedRules::EndYear() const
+	{
+	return iEndYear;
+	}
+
+/**
+Tells if Daylight Savings Applies for the current time zone at the current time
+@return EFalse if Daylight Savings does not apply (winter time) and ETrue if Daylight Savings does apply
+@param aTime The time of interest given in UTC.
+@panic RTz 5 if aTime is not covered by the current set of time zone rules.
+@panic RTz 7 if one of the time zone rules uses standard time reference.
+@publishedAll
+@released
+*/
+EXPORT_C TBool CVTzActualisedRules::IsDaylightSavingOn(TTime& aTime) const
+	{
+	const TInt count = iRules.Count();
+
+	// ensure that there are rules
+	__ASSERT_ALWAYS((count > 0), RTz::Panic(RTz::EPanicTimeNotCoveredByRules));
+
+	// initialisation separated from declaration to avoid arm4 'unused variable warning'
+	TDateTime dateTime;
+	dateTime = aTime.DateTime();
+
+	// ensure that there are rules defined for the time in question
+	__ASSERT_ALWAYS(dateTime.Year() >= StartYear() && dateTime.Year() <= EndYear(), 
+					RTz::Panic(RTz::EPanicTimeNotCoveredByRules));
+	
+	// the illustration below is for a location in the northern hemisphere
+	// the opposite applies to southern hemisphere locations
+	//
+	//          --------|--------|---------
+	// season:  winter    summer    winter
+	// rule:           [1]      [2]   
+	//
+	// the rules are sorted by iTimeOfChange.
+	// we start searching for the applicable rule with time 0.
+	//
+	// general dst example from southern hemisphere:
+	//	America/Sao_Paulo
+	//	UTC offset (dst off): -180min (-3h)	
+	//	UTC offset (dst on):  -120min (-2h)		
+	//	starting dst (Nov) 4/11/2007 at 00:00:00
+	//	utc time:  local time:   expected dst status:
+	//	02:00       23:00        off (-180)
+	//	02:58       23:58        off (-180)
+	//	02:59       23:59        off (-180)
+	//	n/a         (00:00)      n/a
+	//	03:00       01:00        on (-120)
+	//	03:01       01:01        on (-120)
+	//	04:00       02:00        on (-120)
+	//	05:00       03:00        on (-120)	
+	//
+	//	ending dst (Feb) 24/02/2008: 00:00:00
+	//	utc time:  local time:   expected dst status:
+	//	01:00       23:00        on (-120)
+	//	01:58       23:58        on (-120)
+	//	01:59       23:59        on (-120)
+	//	n/a	        (00:00)      n/a
+	//	02:00       23:00        off (-180)
+	//	02:58       23:58        off (-180)
+	//	02:59       23:59        off (-180)
+	//	03:00       00:00        off (-180)
+	//	04:00       01:00        off (-180)
+	//	05:00       02:00        off (-180)
+	//   
+	TBool dstOn(EFalse);
+	TTime lastTimeOfChange(0);
+    TInt lowestOffset = 0;
+    TBool firstMatchFound = EFalse;
+    
+    // Retrieve lowest applicable time offset.
+	// This is used to determine if DST is on.
+	for (TInt i = 0; i < count; ++i)
+		{
+		const TVTzActualisedRule& rule = iRules[i];
+		
+		// Only check for the same year as requested (aTime)
+		if (rule.iTimeOfChange.DateTime().Year() == dateTime.Year())
+   		    {
+   		    if (!firstMatchFound)
+	   		    {
+	   		    lowestOffset = rule.iNewOffset;
+	   		    firstMatchFound = ETrue;	
+	   		    }
+   		    
+			if (rule.iNewOffset < lowestOffset)
+				{
+				lowestOffset = rule.iNewOffset;
+				}	
+			}	
+		}
+	
+	if (firstMatchFound) // lowest offset has been found in year of interest
+	    {
+	    // there are only a few actualised rules
+	    // so simple sequential search will suffice
+	    // Times may be expressed in utc, or local
+	    // so we need to compare like for like
+		for (TInt i = 0; i < count; ++i)
+			{
+			const TVTzActualisedRule& rule = iRules[i];
+			TInt oldOffset = (i>0) ?  iRules[i-1].iNewOffset : rule.iNewOffset;
+ 			
+			__ASSERT_ALWAYS(rule.iTimeReference!=ETzStdTimeReference, RTz::Panic(RTz::EPanicUnsupportedTimeReference));
+		
+			TTime timeOfChange(rule.iTimeOfChange);
+			
+			// convert to utc
+		    if (rule.iTimeReference == ETzWallTimeReference)
+				{
+				timeOfChange -= (TTimeIntervalMinutes)oldOffset;				
+				}
+
+		#if defined(_DEBUG)
+			// initialisation separated from declaration to avoid arm4 'unused variable warning'
+			TDateTime dateTimeofChange;
+			dateTimeofChange = timeOfChange.DateTime();
+		#endif
+
+			if (aTime >= timeOfChange) // continue until finding the rule which applies to the current time
+				{
+				if (timeOfChange > lastTimeOfChange) // a double check that rules are in order
+					{
+					// Check to see if the lowest offset is greater than the current
+					// offset. If it is, then this implies DST is on.
+					if (rule.iNewOffset > lowestOffset)
+						{
+						dstOn = ETrue;  // daylight savings is on
+						}
+					else
+						{
+						dstOn = EFalse; // daylight savings is off
+						}
+					
+					lastTimeOfChange = timeOfChange;
+					}
+				}
+			else
+				{
+				// found the matching rule on previous run through loop
+				break;
+				}
+			}
+	    }
+	return(dstOn);
+	}
+	
+/**
+Receives a time. Finds out which of these rules applies at the received time
+and returns the offset in effect at the specified time.
+
+Leaves with KErrNotFound, if it doesn't find the rule 
+(i.e. aTime is earlier than the very first time in CVTzActualisedRules).
+
+@param	aUserTime		- time of interest
+@param	aUserTimeRef	- time reference for the aUserTime (UTC or wall-time)
+					note: ETzStdTimeReference for aTimeRef is not supported, will 
+					panic with RTz::EPanicUnsupportedTimeReference.
+
+@return	TInt		  - offset from UTC (in minutes).
+ */
+EXPORT_C TInt CVTzActualisedRules::GetOffsetFromRuleL(const TTime& aUserTime, TTzTimeReference aUserTimeRef) const
+	{
+	// The first rule with iTimeOfChange <= aUserTime that is found going backwards in the array is the one that
+	// applies at the requested aUserTime.
+	__ASSERT_ALWAYS(aUserTimeRef!=ETzStdTimeReference, RTz::Panic(RTz::EPanicUnsupportedTimeReference));
+
+	// we traverse the array of rules, starting from the last one, until we find the
+	// rule that has a start time just before aTime
+	TBool ruleFound = EFalse;
+	TInt resultOffset = 0;
+	
+	TLinearOrder<TVTzActualisedRule> linearOrder(TVTzActualisedRule::Order);
+	TVTzActualisedRule findActualisedRule(aUserTime, 0, aUserTimeRef);
+	TInt position;
+	TInt error = iRules.FindInOrder(findActualisedRule, position, linearOrder);
+	
+	for (TInt i(Min(position, iRules.Count()-1)); i >= 0; i--)
+		{
+		const TVTzActualisedRule& actRule = iRules[i];
+		TInt oldOffset = (i>0) ? iRules[i-1].iNewOffset : actRule.iNewOffset;
+
+		TTime rolloverTime = actRule.iTimeOfChange;
+		TTzTimeReference rolloverTimeRef = actRule.iTimeReference;
+
+    #if defined(_DEBUG)
+		TDateTime dtRolloverTime = rolloverTime.DateTime();
+		TDateTime dtUserTime     = aUserTime.DateTime();
+    #endif
+		
+		TTimeIntervalMinutes diffMinutes;
+		// Find out if rolloverTime is earlier than aUserTime
+		if (CompareTimesWithRef(rolloverTime, rolloverTimeRef, aUserTime, aUserTimeRef, oldOffset, diffMinutes) <= 0)
+			{// rolloverTime is now earlier than aUserTime, so we are done iterating backwards
+			//  and aUserTime is now between this iteration and the last iterated rule.
+			//  This means we need to use the current iNewOffset for the correct offset to give aUserTime on return.
+			resultOffset = actRule.iNewOffset;			
+			
+            // If diffMinutes is less than difference between iNewOffset and oldOffset,              
+            // then we are potentially in the "missing" hour, which should return the  
+            // oldOffset instead of iNewOffset. 			
+    		if (aUserTimeRef == ETzWallTimeReference &&
+    		    oldOffset < actRule.iNewOffset &&
+    		    diffMinutes.Int() < (actRule.iNewOffset-oldOffset))
+				{
+				// the missing hour - use oldOffset instead.
+				// see general dst example in CVTzActualisedRules::IsDaylightSavingOn
+				// why this is necessary.
+				resultOffset = oldOffset;
+				}
+			
+			ruleFound = ETrue;
+			break;
+			}
+		}
+
+	if (!ruleFound)
+		{
+		User::Leave(KErrNotFound);
+		}
+		
+	return resultOffset;
+	}
+	
+/**	
+
+Compares two times with time references (TTzTimeReference).
+TTzTimeReference is either ETzUtcTimeReference or ETzWallTimeReference.
+
+If time references for both aRolloverTime and aUserTime are the same, 
+then straight comparison is done. Otherwise aRolloverTime is converted to match
+the time reference of aUserTime.
+
+@param	aRolloverTime	 - the time of change from/to Daylight Savings Time (DST)
+@param  aTimeRefRollover - the time reference used in aRolloverTime
+@param	aUserTime		 - the time provided by the user to compare with 
+@param  aTimeRefUser     - the time reference used for the user time
+@param  aOldWallOffset   - the offset that is active before aRolloverTime happens
+
+@return TInt		-1 if aRolloverTime is earlier than aUserTime;
+					 0 if aRolloverTime is equal to aUserTime;
+					 1 if aRolloverTime is later than aUserTime.	 
+ */ 
+TInt CVTzActualisedRules::CompareTimesWithRef(	
+		TTime aRolloverTime, TTzTimeReference aTimeRefRollover, 
+		TTime aUserTime,     TTzTimeReference aTimeRefUser,
+		TInt aOldWallOffset, TTimeIntervalMinutes& aDiffMinutes) const
+	{
+	TInt result = 0;		
+
+	// Always convert the Rollover time if it has not 
+	// the same reference type as user time
+	if ( aTimeRefRollover != aTimeRefUser)
+		{
+		// As they are different; if RolloverTime is of
+		// wall time type, we need to convert it to Utc
+		// and vice versa, to match aTimeRefUser
+		if ( aTimeRefRollover == ETzWallTimeReference)
+			{
+			// Convert to utc time reference
+			aRolloverTime -= TTimeIntervalMinutes (aOldWallOffset);
+			}
+		else // aTimeRefRollover is ETzUtcTimeReference
+			{
+			// Convert to wall time reference
+			aRolloverTime += TTimeIntervalMinutes (aOldWallOffset);
+ 			}
+		}
+
+	#if defined(_DEBUG)
+		TDateTime dtRollover = aRolloverTime.DateTime ();
+		TDateTime dtUser     = aUserTime.DateTime ();
+	#endif
+		
+	TInt err = aUserTime.MinutesFrom(aRolloverTime, aDiffMinutes);
+	
+	if (aRolloverTime < aUserTime)
+		{
+		result = -1;
+ 		}
+	else if (aRolloverTime > aUserTime)
+		{
+		result = 1;
+		}
+
+	return result;
+	}
+
+
+