tzservices/tzserver/Server/Source/tzdbentities.cpp
changeset 0 2e3d3ce01487
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 // Copyright (c) 2004-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 //
       
    15 
       
    16 #include "tzdbentities.h"
       
    17 #include "ReadOnlyTzDb.h"
       
    18 #include <vtzrules.h>
       
    19 
       
    20 /**
       
    21 This const must match the last TTzRuleDay enumeration in tzdefines.h.
       
    22 @internalComponent
       
    23 */
       
    24 const TInt KValidatedLastDayRule = ETzDayInLastWeekOfMonth;
       
    25 
       
    26 /**
       
    27 This const must match the last TTzTimeReference enumeration in tzdefines.h.
       
    28 @internalComponent
       
    29 */
       
    30 const TInt KValidatedLastTimeReference = ETzWallTimeReference;
       
    31 
       
    32 //=============================================================================
       
    33 
       
    34 CTzDbStringsTable* CTzDbStringsTable::NewL(const TTzStringsTable& aRegionsTable)
       
    35 	{
       
    36 	CTzDbStringsTable* self = new(ELeave) CTzDbStringsTable(aRegionsTable);
       
    37 	return self;
       
    38 	}
       
    39 
       
    40 CTzDbStringsTable::CTzDbStringsTable(const TTzStringsTable& aRegionsTable)
       
    41 	: iPersistedEntity(aRegionsTable)
       
    42 	{
       
    43 	}
       
    44 
       
    45 TPtrC8 CTzDbStringsTable::GetStringL(TUint aReferenceToString)
       
    46 	{
       
    47 	const TInt KStringsBaseAddress = (TInt)&iPersistedEntity;
       
    48 	const TInt KLengthAddress = KStringsBaseAddress + aReferenceToString;
       
    49 	const TInt KStringAddress = KLengthAddress + 1; // length occupies 1 byte
       
    50 	TUint8 length = *(reinterpret_cast<TUint8*>(KLengthAddress));
       
    51 	TPtrC8 theString(reinterpret_cast<TUint8*>(KStringAddress),length);
       
    52 	return theString;
       
    53 	}
       
    54 
       
    55 //=============================================================================
       
    56 
       
    57 CTzDbRegionsTable* CTzDbRegionsTable::NewL(CReadOnlyTzDb& aReadOnlyTzDb, const TTzRegionsTable& aRegionsTable)
       
    58 	{
       
    59 	CTzDbRegionsTable* self = new(ELeave) CTzDbRegionsTable(aReadOnlyTzDb, aRegionsTable);
       
    60 	return self;
       
    61 	}
       
    62 
       
    63 CTzDbRegionsTable::CTzDbRegionsTable(CReadOnlyTzDb& aReadOnlyTzDb, const TTzRegionsTable& aRegionsTable)
       
    64 :	iReadOnlyTzDb(aReadOnlyTzDb), 
       
    65 	iPersistedEntity(aRegionsTable)
       
    66 	{
       
    67 	}
       
    68 
       
    69 //
       
    70 // Looks for a region given its name.
       
    71 // Returns the region wrapped in a CTzDbRegion object.
       
    72 // Returns NULL if region is not found
       
    73 //
       
    74 CTzDbRegion* CTzDbRegionsTable::FindRegionL(const TDesC8& aRegionName)
       
    75 	{
       
    76 	const TInt KRegionCount = iPersistedEntity.iNumberOfRegions;
       
    77 	TTzRegion* region(NULL);
       
    78 	TPtrC8 name;
       
    79 	TInt regionAddress = reinterpret_cast<TInt>(&iPersistedEntity) + sizeof(iPersistedEntity.iNumberOfRegions);
       
    80 	for (TInt i = 0; i < KRegionCount; i++, regionAddress += sizeof(TTzRegion))
       
    81 		{
       
    82 		region = reinterpret_cast<TTzRegion*>(regionAddress);
       
    83 		name.Set(iReadOnlyTzDb.GetStringL(region->iOffsetToRegionName));
       
    84 
       
    85 		// compare both strings
       
    86 		if (aRegionName.Compare(name) == 0) // found our region
       
    87 			{
       
    88 			return CTzDbRegion::NewL(iReadOnlyTzDb,*region);
       
    89 			}
       
    90 		}
       
    91 
       
    92 	// if it gets here, it means that the region has not been found
       
    93 	return NULL;
       
    94 	}
       
    95 
       
    96 //=============================================================================
       
    97 
       
    98 CTzDbRegionalZonesTable* CTzDbRegionalZonesTable::NewL(CReadOnlyTzDb& aReadOnlyTzDb, const TTzRegionalZonesTable& aRegionalZonesTable)
       
    99 	{
       
   100 	CTzDbRegionalZonesTable* self = new(ELeave) CTzDbRegionalZonesTable(aReadOnlyTzDb, aRegionalZonesTable);
       
   101 	return self;
       
   102 	}
       
   103 
       
   104 CTzDbRegionalZonesTable::CTzDbRegionalZonesTable(CReadOnlyTzDb& aReadOnlyTzDb, const TTzRegionalZonesTable& aRegionalZonesTable)
       
   105 :	iReadOnlyTzDb(aReadOnlyTzDb), 
       
   106 	iPersistedEntity(aRegionalZonesTable)
       
   107 	{
       
   108 	}
       
   109 
       
   110 const TTzRegionalZoneIndex& CTzDbRegionalZonesTable::GetTRegionalZoneIndex(TUint aReference)
       
   111 	{
       
   112 	return * reinterpret_cast<TTzRegionalZoneIndex*> (aReference + reinterpret_cast<TInt>(&iPersistedEntity));
       
   113 	}
       
   114 
       
   115 //=============================================================================
       
   116 
       
   117 CTzDbZonesTable* CTzDbZonesTable::NewL(CReadOnlyTzDb& aReadOnlyTzDb, const TTzZonesTable& aZonesTable, TInt aZonesDataBaseAddress)
       
   118 	{
       
   119 	CTzDbZonesTable* self = new(ELeave) CTzDbZonesTable(aReadOnlyTzDb, aZonesTable, aZonesDataBaseAddress);
       
   120 	return self;
       
   121 	}
       
   122 
       
   123 CTzDbZonesTable::CTzDbZonesTable(CReadOnlyTzDb& aReadOnlyTzDb, const TTzZonesTable& aZonesTable, TInt aZonesDataBaseAddress)
       
   124 :	iReadOnlyTzDb(aReadOnlyTzDb), 
       
   125 	iPersistedEntity(aZonesTable),
       
   126 	iZonesDataBaseAddress(aZonesDataBaseAddress)
       
   127 	{
       
   128 	}
       
   129 
       
   130 CTzDbZone* CTzDbZonesTable::GetZoneL(TUint aReference)
       
   131 	{
       
   132 	return CTzDbZone::NewL(iReadOnlyTzDb, GetTZone(aReference));
       
   133 	}
       
   134 
       
   135 TTzZone& CTzDbZonesTable::GetTZone(TUint aReference)
       
   136 	{
       
   137 	return *reinterpret_cast<TTzZone*>(aReference + iZonesDataBaseAddress);
       
   138 	}
       
   139 
       
   140 //
       
   141 // Performs a binary search in the zones table, looking for the zone with the
       
   142 // supplied numeric ID.
       
   143 //
       
   144 // IMPORTANT: Assumes zones are sorted by LocationId in zones table.
       
   145 //
       
   146 CTzDbZone* CTzDbZonesTable::GetZoneByIdL(TUint aNumericId)
       
   147 	{
       
   148 	TTzZone* tzone(NULL);
       
   149 	const TInt KZoneCount = iPersistedEntity.iNumberOfZones;
       
   150 	TInt start = 0;
       
   151 	TInt end = KZoneCount - 1;
       
   152 	TInt mid;
       
   153 	TBool found = EFalse;
       
   154 	while(start <= end)
       
   155 		{
       
   156 		mid = (end + start) / 2;
       
   157 		tzone = &GetTZone(iPersistedEntity.iOffsetsToZones[mid]);
       
   158 		if (aNumericId < tzone->iLocationId)
       
   159 			{
       
   160 			end = mid - 1;
       
   161 			}
       
   162 		else if (aNumericId == tzone->iLocationId)
       
   163 			{ 
       
   164 			// found our zone
       
   165 			found = ETrue;
       
   166 			break;
       
   167 			}
       
   168 		else
       
   169 			{
       
   170 			start = mid + 1;
       
   171 			}
       
   172 		}
       
   173 
       
   174 	if (found)
       
   175 		{
       
   176 		return CTzDbZone::NewL(iReadOnlyTzDb, *tzone);
       
   177 		}
       
   178 	else
       
   179 		{
       
   180 		return NULL;	
       
   181 		}
       
   182 	}
       
   183 
       
   184 //=============================================================================
       
   185 
       
   186 CTzDbLinksTable* CTzDbLinksTable::NewL(CReadOnlyTzDb& aReadOnlyTzDb, const TTzLinksTable& aLinksTable)
       
   187 	{
       
   188 	CTzDbLinksTable* self = new(ELeave) CTzDbLinksTable(aReadOnlyTzDb, aLinksTable);
       
   189 	return self;
       
   190 	}
       
   191 
       
   192 CTzDbLinksTable::CTzDbLinksTable(CReadOnlyTzDb& aReadOnlyTzDb, const TTzLinksTable& aLinksTable)
       
   193 :	iReadOnlyTzDb(aReadOnlyTzDb), 
       
   194 	iPersistedEntity(aLinksTable)
       
   195 	{
       
   196 	}
       
   197 
       
   198 CTzDbZone* CTzDbLinksTable::FindZoneL(const TDesC8& aLinkName)
       
   199 	{
       
   200 	const TInt KLinkCount = iPersistedEntity.iNumberOfLinks;
       
   201 	TPtrC8 name;
       
   202 	TTzLink* link(NULL);
       
   203 	TInt linkAddress = reinterpret_cast<TInt>(&iPersistedEntity) + sizeof(iPersistedEntity.iNumberOfLinks);
       
   204 	for (TInt i = 0; i < KLinkCount; i++, linkAddress += sizeof(TTzLink))
       
   205 		{
       
   206 		link = reinterpret_cast<TTzLink*>(linkAddress);
       
   207 		name.Set(iReadOnlyTzDb.GetStringL(link->iOffsetToLinkName));
       
   208 		if (!name.CompareC(aLinkName))
       
   209 			{ // we found our link
       
   210 			return iReadOnlyTzDb.GetZoneL(link->iOffsetToZone);
       
   211 			}
       
   212 		}
       
   213 
       
   214 	// if it gets here, it means that the zone has not been found
       
   215 	return NULL;
       
   216 	}
       
   217 
       
   218 //=============================================================================
       
   219 
       
   220 CTzDbStdTimeAlignmentsTable* CTzDbStdTimeAlignmentsTable::NewL(const TTzStdTimeAlignmentsTable& aStdTimeAlignmentsTable)
       
   221 	{
       
   222 	CTzDbStdTimeAlignmentsTable* self = new(ELeave) CTzDbStdTimeAlignmentsTable(aStdTimeAlignmentsTable);
       
   223 	return self;
       
   224 	}
       
   225 
       
   226 CTzDbStdTimeAlignmentsTable::CTzDbStdTimeAlignmentsTable(const TTzStdTimeAlignmentsTable& aStdTimeAlignmentsTable)
       
   227 	: iPersistedEntity(aStdTimeAlignmentsTable)
       
   228 	{
       
   229 	}
       
   230 
       
   231 TTzStdTimeAlignment& CTzDbStdTimeAlignmentsTable::GetTStdTimeAlignment(TUint aReference)
       
   232 	{
       
   233 	return *reinterpret_cast<TTzStdTimeAlignment*>(aReference + (TInt)&iPersistedEntity);
       
   234 	}
       
   235 
       
   236 //=============================================================================
       
   237 
       
   238 CTzDbRuleSetsTable* CTzDbRuleSetsTable::NewL(CReadOnlyTzDb& aReadOnlyTzDb, const TTzRuleSetsTable& aRuleSetsTable)
       
   239 	{
       
   240 	CTzDbRuleSetsTable* self = new(ELeave) CTzDbRuleSetsTable(aReadOnlyTzDb, aRuleSetsTable);
       
   241 	return self;
       
   242 	}
       
   243 
       
   244 CTzDbRuleSetsTable::CTzDbRuleSetsTable(CReadOnlyTzDb& aReadOnlyTzDb, const TTzRuleSetsTable& aRuleSetsTable)
       
   245 	: iReadOnlyTzDb(aReadOnlyTzDb), iPersistedEntity(aRuleSetsTable)
       
   246 	{
       
   247 	}
       
   248 
       
   249 CTzDbRuleSet* CTzDbRuleSetsTable::GetRuleSetL(TUint aReference)
       
   250 	{
       
   251 	return CTzDbRuleSet::NewL(iReadOnlyTzDb, GetTRuleSet(aReference));
       
   252 	}
       
   253 
       
   254 TTzRuleSet& CTzDbRuleSetsTable::GetTRuleSet(TUint aReference)
       
   255 	{
       
   256 	return * reinterpret_cast<TTzRuleSet*>(aReference + (TInt)&iPersistedEntity);
       
   257 	}
       
   258 
       
   259 //=============================================================================
       
   260 
       
   261 CTzDbRuleUsesTable* CTzDbRuleUsesTable::NewL(const TTzRuleUsesTable& aRuleUsesTable)
       
   262 	{
       
   263 	CTzDbRuleUsesTable* self = new(ELeave) CTzDbRuleUsesTable(aRuleUsesTable);
       
   264 	return self;
       
   265 	}
       
   266 
       
   267 CTzDbRuleUsesTable::CTzDbRuleUsesTable(const TTzRuleUsesTable& aRuleUsesTable)
       
   268 	: iPersistedEntity(aRuleUsesTable)
       
   269 	{
       
   270 	}
       
   271 
       
   272 TTzRuleUse& CTzDbRuleUsesTable::GetTRuleUse(TUint aReference)
       
   273 	{
       
   274 	return * reinterpret_cast<TTzRuleUse*> (aReference + (TInt)&iPersistedEntity);
       
   275 	}
       
   276 
       
   277 //=============================================================================
       
   278 
       
   279 CTzDbRuleDefinitionsTable* CTzDbRuleDefinitionsTable::NewL(const TTzRuleDefinitionsTable& aRuleDefinitionsTable)
       
   280 	{
       
   281 	CTzDbRuleDefinitionsTable* self = new(ELeave) CTzDbRuleDefinitionsTable(aRuleDefinitionsTable);
       
   282 	return self;
       
   283 	}
       
   284 
       
   285 CTzDbRuleDefinitionsTable::CTzDbRuleDefinitionsTable(const TTzRuleDefinitionsTable& aRuleDefinitionsTable)
       
   286 	: iPersistedEntity(aRuleDefinitionsTable)
       
   287 	{
       
   288 	}
       
   289 
       
   290 const TTzRuleDefinition& CTzDbRuleDefinitionsTable::GetRuleDefinition(TUint aReference)
       
   291 	{
       
   292 	return * reinterpret_cast<TTzRuleDefinition*>(aReference + (TInt)&iPersistedEntity);
       
   293 	}
       
   294 
       
   295 //=============================================================================
       
   296 
       
   297 CTzDbRegion* CTzDbRegion::NewL(CReadOnlyTzDb& aReadOnlyTzDb, const TTzRegion& aRegion)
       
   298 	{
       
   299 	CTzDbRegion* self = new(ELeave) CTzDbRegion(aReadOnlyTzDb,aRegion);
       
   300 	return self;
       
   301 	}
       
   302 
       
   303 CTzDbRegion::CTzDbRegion(CReadOnlyTzDb& aReadOnlyTzDb, const TTzRegion& aRegion)
       
   304 :	iReadOnlyTzDb(aReadOnlyTzDb),
       
   305 	iPersistedEntity(aRegion)
       
   306 	{
       
   307 	}
       
   308 
       
   309 CTzDbZone* CTzDbRegion::FindZoneL(TUint aCityNameReference)
       
   310 	{
       
   311 	TTzRegionalZoneIndex* zoneIndex = const_cast<TTzRegionalZoneIndex*>(&iReadOnlyTzDb.GetTRegionalZoneIndex(iPersistedEntity.iOffsetToRegionalZoneIndex));
       
   312 	const TInt KZoneCount = zoneIndex->iNumberOfZones;
       
   313 	TTzZone* tzone(NULL);
       
   314 	for (TInt i = 0; i < KZoneCount; i++)
       
   315 		{
       
   316 		tzone = const_cast<TTzZone*>(&iReadOnlyTzDb.GetTZone(zoneIndex->iOffsetsToZones[i]));
       
   317 		if (tzone->iOffsetToZoneName == aCityNameReference)
       
   318 			{ // found our zone
       
   319 			return CTzDbZone::NewL(iReadOnlyTzDb,*tzone);
       
   320 			}
       
   321 		}
       
   322 
       
   323 	// if it gets here, it means that the zone has not been found
       
   324 	return NULL;
       
   325 	}
       
   326 
       
   327 CTzDbZone* CTzDbRegion::FindZoneL(const TDesC8& aCityName)
       
   328 	{
       
   329 	TTzZone* tzone(NULL);
       
   330 	TTzRegionalZoneIndex* zoneIndex = const_cast<TTzRegionalZoneIndex*>(&iReadOnlyTzDb.GetTRegionalZoneIndex(iPersistedEntity.iOffsetToRegionalZoneIndex));
       
   331 	const TInt KZoneCount = zoneIndex->iNumberOfZones;
       
   332 	TPtrC8 name;
       
   333 
       
   334 	TBool found = EFalse;
       
   335 	TInt start = 0;
       
   336 	TInt end = KZoneCount - 1;
       
   337 	TInt mid;
       
   338 
       
   339 	// perform a binary search for aCityName among the zones listed in the zone index. This assumes
       
   340 	// that zones are sorted alphabetically in the zone index.
       
   341 	while (start <= end)
       
   342 		{
       
   343 		mid = (end + start) / 2;
       
   344 		tzone = const_cast<TTzZone*>(&iReadOnlyTzDb.GetTZone(zoneIndex->iOffsetsToZones[mid]));
       
   345 		
       
   346 		// compare this zone's name with the name we've been given as a parameter
       
   347 		// use strict comparison method Compare, as CompareC may cause the search to fail:
       
   348 		// for example, Stanley will come BEFORE St_Helens using the standard collation method in Symbian OS,
       
   349 		// but it will have been placed AFTER St_Helens by std::sort in he TZ Compiler. This would result
       
   350 		// in this binary search to fail.
       
   351 		name.Set(iReadOnlyTzDb.GetStringL(tzone->iOffsetToZoneName));
       
   352 		if (aCityName.Compare(name) < 0)
       
   353 			{
       
   354 			end = mid - 1;
       
   355 			}
       
   356 		else if (aCityName.Compare(name) == 0) 
       
   357 			{ // found our zone
       
   358 			found = ETrue;
       
   359 			break;
       
   360 			}
       
   361 		else if (aCityName.Compare(name) > 0)
       
   362 			{
       
   363 			start = mid + 1;
       
   364 			}
       
   365 		}
       
   366 
       
   367 	if (found)
       
   368 		{
       
   369 		return CTzDbZone::NewL(iReadOnlyTzDb,*tzone);
       
   370 		}
       
   371 	else
       
   372 		{
       
   373 		return NULL;
       
   374 		}
       
   375 	}
       
   376 
       
   377 //=============================================================================
       
   378 
       
   379 CTzDbZone* CTzDbZone::NewL(CReadOnlyTzDb& aReadOnlyTzDb, const TTzZone& aZone)
       
   380 	{
       
   381 	CTzDbZone* self = new(ELeave) CTzDbZone(aReadOnlyTzDb,aZone);
       
   382 	return self;
       
   383 	}
       
   384 
       
   385 CTzDbZone::CTzDbZone(CReadOnlyTzDb& aReadOnlyTzDb, const TTzZone& aZone)
       
   386 :	iReadOnlyTzDb(aReadOnlyTzDb),
       
   387 	iPersistedEntity(aZone)
       
   388 	{
       
   389 	}
       
   390 
       
   391 void CTzDbZone::GetRulesL(CTzRules& aRules)
       
   392 	{	
       
   393 	// start and end years of interest
       
   394 	TInt firstYearOfInterest = aRules.StartYear();
       
   395 	TInt lastYearOfInterest = aRules.EndYear();
       
   396 
       
   397 	// record last instant of end year, in order to see if we need to get another time alignment
       
   398 	TDateTime endDateTimeOfInterest(lastYearOfInterest,EDecember,30,23,59,59,0);
       
   399 	TTime endTimeOfInterest(endDateTimeOfInterest);
       
   400 
       
   401 	// initialise start time to beginning of startYear (UTC)
       
   402 	TDateTime startDateTime(firstYearOfInterest,EJanuary,0,0,0,0,0);
       
   403 	TTime startTime(startDateTime);
       
   404 	TTime staEndTime;
       
   405 	TDateTime staEndDateTime;
       
   406 	TTzTimeReference staTimeReference(ETzUtcTimeReference);
       
   407 
       
   408 	// the following variables are used to iterate through the list of standard time alignments for this location
       
   409 	TInt taCount = iPersistedEntity.iNumberOfStdTimeAlignments;
       
   410 	TInt tmpOffset;
       
   411 	TTzStdTimeAlignment* ta(NULL);
       
   412 	TTzStdTimeAlignment* prevTa(NULL);
       
   413 	CTzDbStdTimeAlignment* sta = NULL;
       
   414 
       
   415 	// the standard time offset at the beginning of the period of interest has to be set in aTzRules
       
   416 	TBool initialOffsetHasBeenSet = EFalse;
       
   417 	
       
   418 	// Iterate through std time alignments until we find the one that contains our date of interest.
       
   419 	// Get the rules for this time alignment, up to the end of the time alignment or the end of our 
       
   420 	// period of interest (whichever comes first).
       
   421 	// If the period of interest is covered by only one time alignment, finish and return.
       
   422 	// If the period of interest is covered by more than one time alignment, repeat procedure with 
       
   423 	// next time alignment(s) until we reach the end of the period of interest
       
   424 	for (TInt i = 0; (i < taCount) && (startTime < endTimeOfInterest ); i++)
       
   425 		{
       
   426 		// get a standard time alignment
       
   427 
       
   428 		prevTa = ta; // this will be needed to eventually wrap the time alignment in a CTzDbStdTimeAlignment object
       
   429 		tmpOffset = iPersistedEntity.iOffsetsToTimeAlignments[i];
       
   430 		ta = const_cast<TTzStdTimeAlignment*>(&iReadOnlyTzDb.GetTStdTimeAlignment(tmpOffset));
       
   431 
       
   432 		// check if our time of interest is within this time alignment
       
   433 		if (IsTimeInStdTimeAlignment(*ta,	startDateTime.Year(),
       
   434 											startDateTime.Month(),
       
   435 											startDateTime.Day(),
       
   436 											startDateTime.Hour(),
       
   437 											startDateTime.Minute(),
       
   438 											staTimeReference) )
       
   439 			{
       
   440 			// wrap the time alignment in a CTzDbStdTimeAlignment object
       
   441 			sta = CTzDbStdTimeAlignment::NewL(iReadOnlyTzDb,*ta,prevTa);
       
   442 			if (sta)
       
   443 				{
       
   444 				CleanupStack::PushL(sta); // push #1 - sta
       
   445 				
       
   446 				if (initialOffsetHasBeenSet == EFalse)
       
   447 					{
       
   448 					aRules.SetInitialStdTimeOffset(ta->iUtcOffset);
       
   449 					initialOffsetHasBeenSet = ETrue;
       
   450 					}
       
   451 					
       
   452 				// staStartDateTime, staEndTime are passed by reference and their values
       
   453 				// are updated in GetRulesL
       
   454 				sta->GetRulesL(aRules,startDateTime,staEndDateTime);
       
   455 
       
   456 				// The time reference to calculate the start of the next time alignment is the time reference
       
   457 				// in which the end time of this time alignment is expressed 
       
   458 				staTimeReference = static_cast<TTzTimeReference>(sta->UntilTimeReference());
       
   459 				CleanupStack::PopAndDestroy(sta); // pop #1 - sta
       
   460 
       
   461 				staEndTime = staEndDateTime;
       
   462 				if (staEndTime == Time::MaxTTime())
       
   463 					{
       
   464 					startTime = staEndTime; // this will cause loop to finish
       
   465 					}
       
   466 				else
       
   467 					{
       
   468 					// move just after end of time alignment
       
   469 					startTime = staEndTime + static_cast<TTimeIntervalSeconds>(1);
       
   470 					startDateTime = startTime.DateTime();
       
   471 					}
       
   472 				}
       
   473 			} // if IsTimeInStdTimeAlignment(...)
       
   474 		} // for
       
   475 			
       
   476 	}
       
   477 	
       
   478 TBool CTzDbZone::IsTimeInStdTimeAlignment(const TTzStdTimeAlignment& aStdTa, TInt aYear, TInt aMonth, TInt aDay, TInt aHour, TInt aMinute, TTzTimeReference aTimeRef)
       
   479 	{
       
   480 	TInt found = EFalse;
       
   481 
       
   482 	if (aYear > (TInt)KMaxTUint16)
       
   483 		{
       
   484 		aYear = KMaxTUint16; // KMaxTUint16 (0xFFFF) is the value given to year when the end of a time alignment is unknown
       
   485 		}
       
   486 
       
   487 	if (aStdTa.iUntilYear > aYear)
       
   488 		{
       
   489 		found = ETrue;
       
   490 		}
       
   491 	else if (aStdTa.iUntilYear == aYear)
       
   492 		{
       
   493 		if ( (aStdTa.iUntilMonth > aMonth) || (aStdTa.iUntilMonth == KMaxTUint8) )
       
   494 			{
       
   495 			found = ETrue;
       
   496 			}
       
   497 		else if (aStdTa.iUntilMonth == aMonth)
       
   498 			{
       
   499 			// evaluate the day and time the time alignment ends 
       
   500 			// and see if the received time falls in or out of the t.a.
       
   501 			TTime ourTime;
       
   502 
       
   503 			if (aYear >= (TInt)KMaxTUint16)
       
   504 				{
       
   505 				ourTime = Time::MaxTTime();
       
   506 				}
       
   507 			else
       
   508 				{
       
   509 				TDateTime ourDateTime(aYear,
       
   510 									(TMonth)aMonth,
       
   511 									aDay,
       
   512 									aHour,
       
   513 									aMinute,
       
   514 									0,
       
   515 									0);
       
   516 
       
   517 				ourTime = ourDateTime;
       
   518 
       
   519 				// convert ourTime to UTC
       
   520 				if (aTimeRef == ETzStdTimeReference)
       
   521 					{
       
   522 					ourTime -= static_cast<TTimeIntervalMinutes>(aStdTa.iUtcOffset);
       
   523 					}
       
   524 				}
       
   525 
       
   526 			TTime endTime;
       
   527 			if (aStdTa.iUntilYear == KMaxTUint16)
       
   528 				{
       
   529 				endTime = Time::MaxTTime();
       
   530 				}
       
   531 			else
       
   532 				{
       
   533 				TDateTime endDateTime(aStdTa.iUntilYear,
       
   534 									(TMonth)aStdTa.iUntilMonth,
       
   535 									aStdTa.iUntilDayOfMonth,
       
   536 									(aStdTa.iUntilTimeInMinutes / 60),
       
   537 									(aStdTa.iUntilTimeInMinutes % 60),
       
   538 									0,
       
   539 									0);
       
   540 
       
   541 				endTime = endDateTime;
       
   542 
       
   543 				// convert endTime to UTC
       
   544 				if (aTimeRef == ETzStdTimeReference)
       
   545 					{
       
   546 					endTime -= static_cast<TTimeIntervalMinutes>(aStdTa.iUtcOffset);
       
   547 					}
       
   548 				}
       
   549 			
       
   550 			// and finally compare both times
       
   551 			if (endTime >= ourTime)
       
   552 				{
       
   553 				found = ETrue;
       
   554 				}
       
   555 			}
       
   556 		} // else if (aStdTa->iUntilYear == aYear)
       
   557 
       
   558 	return found;
       
   559 	}
       
   560 //
       
   561 // Traverses the collection of Std Time Alignments for the current zone, looking for the one that 
       
   562 // matches the given time.
       
   563 // Returns a CTzDbStdTimeAlignment object.
       
   564 //
       
   565 CTzDbStdTimeAlignment* CTzDbZone::FindStdTimeAlignmentL(TInt aYear, TInt aMonth, TInt aDay, TInt aHour, TInt aMinute, const TTzTimeReference aTimeRef)
       
   566 	{
       
   567 	TTzStdTimeAlignment* ta(NULL);
       
   568 	TTzStdTimeAlignment* prevTa(NULL);
       
   569 	TInt taCount = iPersistedEntity.iNumberOfStdTimeAlignments;
       
   570 	TBool found = EFalse;
       
   571 	TInt tmpOffset = 0;
       
   572 	for (TInt i = 0; (i < taCount) && (!found); i++)
       
   573 		{
       
   574 		prevTa = ta;
       
   575 		tmpOffset = iPersistedEntity.iOffsetsToTimeAlignments[i];
       
   576 		ta = const_cast<TTzStdTimeAlignment*>(&iReadOnlyTzDb.GetTStdTimeAlignment(tmpOffset));
       
   577 		
       
   578 		found = IsTimeInStdTimeAlignment(*ta,aYear,aMonth,aDay,aHour,aMinute,aTimeRef);
       
   579 		}
       
   580 		
       
   581 	if (found)
       
   582 		{
       
   583 		return CTzDbStdTimeAlignment::NewL(iReadOnlyTzDb, *ta, prevTa);
       
   584 		}
       
   585 	else
       
   586 		{
       
   587 		return NULL;
       
   588 		}
       
   589 	}
       
   590 
       
   591 HBufC8* CTzDbZone::GetFullZoneNameLC()
       
   592 	{
       
   593 	HBufC8* fullName = HBufC8::NewL(KMaxTimeZoneIdSize);
       
   594 	CleanupStack::PushL(fullName);
       
   595 	TPtr8 fullNamePtr(fullName->Des() );
       
   596 	fullNamePtr.Append(iReadOnlyTzDb.GetStringL(iPersistedEntity.iOffsetToRegionName));
       
   597 	if (fullNamePtr.Length() > 0)
       
   598 		{
       
   599 		// if the region name is empty (e.g. zone "CET"), don't add the slash
       
   600 		fullNamePtr.Append('/');
       
   601 		}
       
   602 	fullNamePtr.Append(iReadOnlyTzDb.GetStringL(iPersistedEntity.iOffsetToZoneName));
       
   603 
       
   604 	return fullName;
       
   605 	}
       
   606 
       
   607 //========================================================================
       
   608 
       
   609 CTzDbStdTimeAlignment* CTzDbStdTimeAlignment::NewL(CReadOnlyTzDb& aReadOnlyTzDb, const TTzStdTimeAlignment& aTimeAlignment, TTzStdTimeAlignment* aPrevTimeAlignment)
       
   610 	{
       
   611 	CTzDbStdTimeAlignment* self = new(ELeave) CTzDbStdTimeAlignment(aReadOnlyTzDb,aTimeAlignment,aPrevTimeAlignment);
       
   612 	return self;		
       
   613 	}
       
   614 
       
   615 CTzDbStdTimeAlignment::CTzDbStdTimeAlignment(CReadOnlyTzDb& aReadOnlyTzDb, 
       
   616 							const TTzStdTimeAlignment& aTimeAlignment, TTzStdTimeAlignment* aPrevTimeAlignment)
       
   617 	: iReadOnlyTzDb(aReadOnlyTzDb)
       
   618 	{
       
   619 	iPersistedEntity = aTimeAlignment;
       
   620 	iPrevTimeAlignment = aPrevTimeAlignment;
       
   621 	}
       
   622 
       
   623 CTzDbStdTimeAlignment::~CTzDbStdTimeAlignment()
       
   624 	{
       
   625 	}
       
   626 
       
   627 void CTzDbStdTimeAlignment::GetRulesL(CTzRules& aRules, const TDateTime& aStartDateTime, TDateTime& aEndDateTime)
       
   628 	{
       
   629 	// get the ruleSet for this time alignment
       
   630 	CTzDbRuleSet* ruleSet = iReadOnlyTzDb.GetRuleSetL(iPersistedEntity.iOffsetToRuleSet);
       
   631 	if (ruleSet)
       
   632 		{
       
   633 		CleanupStack::PushL(ruleSet); // PUSH #1 - RULESET
       
   634 
       
   635 		// get end time of time alignment
       
   636 		TTime endTime;
       
   637 		CalculateEndTime(endTime);
       
   638 		if (endTime == Time::MaxTTime())
       
   639 			{
       
   640 			aEndDateTime.SetYear(KMaxTUint16);
       
   641 			}
       
   642 		else
       
   643 			{
       
   644 			aEndDateTime = endTime.DateTime();
       
   645 			}
       
   646 	
       
   647 		TInt firstYearOfInterest = (aRules.StartYear() >= aStartDateTime.Year()) ? aRules.StartYear() : aStartDateTime.Year();
       
   648 		TInt lastYearOfInterest  = (aRules.EndYear() <= aEndDateTime.Year()) ? aRules.EndYear() : aEndDateTime.Year();
       
   649 		CTzRules* newRules = CTzRules::NewL(firstYearOfInterest, lastYearOfInterest);
       
   650 		CleanupStack::PushL(newRules); // PUSH #2 - NEWRULES
       
   651 		
       
   652 		ruleSet->GetRulesL(*newRules,iPersistedEntity.iUtcOffset,aStartDateTime,aEndDateTime);
       
   653 		
       
   654 		// the new rules obtained for the current std time alignment must be merged into 
       
   655 		// the global rule collection
       
   656 		AddRulesToCollectionL(aRules,*newRules);
       
   657 	
       
   658 		CleanupStack::PopAndDestroy(2, ruleSet); // POP #2,#1 - NEWRULES, RULESET
       
   659 		}
       
   660 	}
       
   661 
       
   662 void CTzDbStdTimeAlignment::AddRulesToCollectionL(CTzRules& aRuleCollection, CTzRules& aNewRules)
       
   663 	{
       
   664 	TTzRule* tRule(NULL);
       
   665 	TVTzActualisedRule tActRule;
       
   666 	TInt count = aNewRules.Count();
       
   667 	for (TInt i = 0; i < count; i++)
       
   668 		{
       
   669 		TBool ruleAdded = EFalse;
       
   670 		tRule = &(aNewRules[i]);
       
   671 		TInt basicRuleFromYear = tRule->iFrom.iTime.DateTime().Year();
       
   672 		TInt basicRuleToYear = tRule->iTo.iTime.DateTime().Year();
       
   673 		
       
   674 		if ( (iPrevTimeAlignment != NULL) 
       
   675 			&& (basicRuleFromYear <= iPrevTimeAlignment->iUntilYear)
       
   676 			&& (basicRuleToYear >= iPrevTimeAlignment->iUntilYear) )
       
   677 			{ // the rule is in effect during the first year of the time alignment
       
   678 			// actualise rule for this year and remove it if it falls outside the time alignment
       
   679 			tActRule = tRule->Actualise(iPrevTimeAlignment->iUntilYear);
       
   680 			
       
   681 			// work out start time of time alignment (i.e. end time of the prev. alignment)
       
   682 				
       
   683 			TDateTime staStartDateTime(	iPrevTimeAlignment->iUntilYear,
       
   684 										(TMonth)iPrevTimeAlignment->iUntilMonth,
       
   685 										iPrevTimeAlignment->iUntilDayOfMonth,
       
   686 										iPrevTimeAlignment->iUntilTimeInMinutes/60, // hour
       
   687 										iPrevTimeAlignment->iUntilTimeInMinutes%60, // minute
       
   688 										0,0); // second, ms
       
   689 			
       
   690 			// make sure times are expressed in the same reference (UTC or Local)
       
   691 			if (tActRule.iTimeReference != iPrevTimeAlignment->iUntilTimeReference)
       
   692 				{			
       
   693 				if (iPrevTimeAlignment->iUntilTimeReference == ETzWallTimeReference)
       
   694 					{ // convert sta start time to UTC
       
   695 					TTime staTime(staStartDateTime);
       
   696 					staTime -= (TTimeIntervalMinutes)(iPrevTimeAlignment->iUtcOffset);
       
   697 					staStartDateTime = staTime.DateTime();
       
   698 					}
       
   699 				else if (iPrevTimeAlignment->iUntilTimeReference == ETzUtcTimeReference)
       
   700 					{ // convert time of change to UTC
       
   701 					tActRule.iTimeOfChange -= (TTimeIntervalMinutes)tRule->iOldLocalTimeOffset;
       
   702 					}
       
   703 				}
       
   704 			
       
   705 			// add rule to collection only if its time of change falls within the time alignment
       
   706 			if (tActRule.iTimeOfChange >= staStartDateTime)
       
   707 				{
       
   708 				aRuleCollection.AddRuleL(*tRule);
       
   709 				ruleAdded = ETrue;
       
   710 				}
       
   711 			else 
       
   712 				{
       
   713 				TDateTime tActRuleDt = tActRule.iTimeOfChange.DateTime();
       
   714 				/*
       
   715 				Fix for INC117764:
       
   716 				Update the rule's month and daytime information only if the rule starts and ends in the same year
       
   717 				otherwise just add them to the collection.
       
   718 				For example:
       
   719 				Iqaluit rules:
       
   720 				-6:00	Canada	C%sT	2000 Oct 29 2:00
       
   721 				-5:00	Canada	E%sT
       
   722 
       
   723 				Rule	Canada	1974	2006	-	Oct	lastSun	2:00	0	S
       
   724 				Rule	Canada	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
       
   725 				Rule	Canada	2007	max	-	Mar	Sun>=8	2:00	1:00	D
       
   726 				Rule	Canada	2007	max	-	Nov	Sun>=1	2:00	0	S
       
   727 				Before this fix, In such a case for all the rules between 2000 and 2006 would be overwritten with start month as 10 whereas they
       
   728 				should be alternating between October and April till 2006.
       
   729 				*/
       
   730 				if ((tActRuleDt.Year() == staStartDateTime.Year()) && (basicRuleFromYear == basicRuleToYear) )
       
   731 					{
       
   732 					tRule->iMonth = staStartDateTime.Month();
       
   733 					tRule->iDayOfMonth = staStartDateTime.Day();
       
   734 					tRule->iDayRule = ETzFixedDate;
       
   735 					aRuleCollection.AddRuleL(*tRule);
       
   736 					ruleAdded = ETrue;
       
   737 					}
       
   738 				else if (tActRuleDt.Year() == staStartDateTime.Year())
       
   739 					{
       
   740 					aRuleCollection.AddRuleL(*tRule);
       
   741 					ruleAdded = ETrue;	
       
   742 					}
       
   743 				}
       
   744 			}
       
   745 		else if (  
       
   746 					(tRule->iFrom.iTime.DateTime().Year() <= iPersistedEntity.iUntilYear)
       
   747 				 	&&(tRule->iTo.iTime.DateTime().Year() >= iPersistedEntity.iUntilYear) 
       
   748 				 )
       
   749 			{ 
       
   750 			// the rule is in effect during the last year of the time alignment
       
   751 			tActRule = tRule->Actualise(iPersistedEntity.iUntilYear);
       
   752 			
       
   753 			TDateTime staEndDateTime(iPersistedEntity.iUntilYear, (TMonth)iPersistedEntity.iUntilMonth, 
       
   754 									 iPersistedEntity.iUntilDayOfMonth, 
       
   755 									 iPersistedEntity.iUntilTimeInMinutes / 60, // hour
       
   756 									 iPersistedEntity.iUntilTimeInMinutes % 60, // minute
       
   757 									 0,0); // second, ms
       
   758 									 
       
   759 			if (tActRule.iTimeReference != iPersistedEntity.iUntilTimeReference)
       
   760 				{
       
   761 				if (iPersistedEntity.iUntilTimeReference == ETzWallTimeReference)
       
   762 					{
       
   763 					TTime staTime(staEndDateTime);
       
   764 					staTime -= (TTimeIntervalMinutes)iPersistedEntity.iUtcOffset;
       
   765 					staEndDateTime = staTime.DateTime();
       
   766 					}
       
   767 				else if (iPersistedEntity.iUntilTimeReference == ETzUtcTimeReference)
       
   768 					{
       
   769 					tActRule.iTimeOfChange -= (TTimeIntervalMinutes)tRule->iOldLocalTimeOffset;
       
   770 					}
       
   771 				}
       
   772 				
       
   773 			// add rule to collection only if its time of change falls withing the time alignment
       
   774 			if (tActRule.iTimeOfChange < staEndDateTime)
       
   775 				{
       
   776 				aRuleCollection.AddRuleL(*tRule);
       
   777 				ruleAdded = ETrue;
       
   778 				}
       
   779 			}
       
   780 		else
       
   781 			{
       
   782 			// no doubt that the rule falls within the time alignment
       
   783 			aRuleCollection.AddRuleL(*tRule);
       
   784 			ruleAdded = ETrue;
       
   785 			}
       
   786 		/*
       
   787 		Fix for INC117764:
       
   788 		Updating the default rule for a year if any new rule overlaps with the default rule.(Default rules start and end at same time)
       
   789 		The offsets are updated if default rule and newly added rule start during same time and newly added rule month occurs before
       
   790 		the default rule month.
       
   791 		*/
       
   792 		if( ruleAdded )
       
   793 			{
       
   794 			if(basicRuleFromYear != basicRuleToYear)
       
   795 				{
       
   796 				TInt ruleCount = aRuleCollection.Count() - 2;								
       
   797 				for(TInt loop = ruleCount;loop >= 0; --loop)
       
   798 					{
       
   799 					TTzRule prevAddedRule = aRuleCollection[loop];
       
   800 					//check that we do not update a winter rule using a summer rule and vice versa					
       
   801 					//Summer rules start before July and winter rules after
       
   802 					if(tRule->iMonth < EJuly && prevAddedRule.iMonth > EJuly)
       
   803 						{
       
   804 						continue;	
       
   805 						}
       
   806 					if(tRule->iMonth > EJuly && prevAddedRule.iMonth < EJuly)
       
   807 						{
       
   808 						continue;	
       
   809 						}
       
   810 					if(basicRuleFromYear > prevAddedRule.iFrom.iTime.DateTime().Year())
       
   811 						{
       
   812 						//no need to check beyond the newly added rules start year.
       
   813 						break;	
       
   814 						}					
       
   815 					if((tRule->iFrom == prevAddedRule.iFrom) &&
       
   816 					 (prevAddedRule.iFrom == prevAddedRule.iTo) && 
       
   817 					 (tRule->iMonth < prevAddedRule.iMonth))
       
   818 						{
       
   819 						prevAddedRule.iOldLocalTimeOffset = tRule->iOldLocalTimeOffset;
       
   820 						prevAddedRule.iNewLocalTimeOffset = tRule->iNewLocalTimeOffset;
       
   821 						aRuleCollection.RemoveRule(loop);
       
   822 						aRuleCollection.AddRuleL(prevAddedRule);
       
   823 						}
       
   824 					}	
       
   825 				}		
       
   826 			}
       
   827 		} // for
       
   828 	}
       
   829 
       
   830 TInt CTzDbStdTimeAlignment::UtcOffset()
       
   831 	{
       
   832 	return iPersistedEntity.iUtcOffset;	
       
   833 	}
       
   834 
       
   835 TUint CTzDbStdTimeAlignment::RuleSetReference()	
       
   836 	{
       
   837 	return iPersistedEntity.iOffsetToRuleSet;	
       
   838 	}
       
   839 
       
   840 TInt CTzDbStdTimeAlignment::UntilYear()			
       
   841 	{
       
   842 	return iPersistedEntity.iUntilYear;		
       
   843 	}
       
   844 
       
   845 TInt CTzDbStdTimeAlignment::UntilMonth()			
       
   846 	{
       
   847 	return iPersistedEntity.iUntilMonth;		
       
   848 	}
       
   849 
       
   850 TInt CTzDbStdTimeAlignment::UntilDay()	
       
   851 	{
       
   852 	return iPersistedEntity.iUntilDayOfMonth;		
       
   853 	}
       
   854 
       
   855 TInt CTzDbStdTimeAlignment::UntilTimeInMinutes()	
       
   856 	{
       
   857 	return iPersistedEntity.iUntilTimeInMinutes;
       
   858 	}
       
   859 
       
   860 TInt CTzDbStdTimeAlignment::UntilTimeReference()
       
   861 	{
       
   862 	return iPersistedEntity.iUntilTimeReference;
       
   863 	}	
       
   864 	
       
   865 //
       
   866 // Calculate End Time of TimeAlignment (UTC)
       
   867 //
       
   868 void CTzDbStdTimeAlignment::CalculateEndTime(TTime& aEndTime)
       
   869 	{
       
   870 	TInt endYear;
       
   871 	TInt endMonth;
       
   872 	TInt endDay;
       
   873 	TInt endHour;
       
   874 	TInt endMinute;
       
   875 	TInt endSecond = 0;
       
   876 	TInt endMicrosecond = 0;
       
   877 	
       
   878 	if (iPersistedEntity.iUntilYear == KMaxTUint16)
       
   879 		{
       
   880 		aEndTime = Time::MaxTTime();
       
   881 		}
       
   882 	else
       
   883 		{
       
   884 		
       
   885 		endYear = iPersistedEntity.iUntilYear;
       
   886 		endMonth = iPersistedEntity.iUntilMonth; if (endMonth > EDecember) endMonth = EJanuary;
       
   887 		endDay = iPersistedEntity.iUntilDayOfMonth; if (endDay > 31) endDay = 0;
       
   888 		if (iPersistedEntity.iUntilTimeInMinutes == KMaxTUint16)
       
   889 			{
       
   890 			endHour = endMinute = 0;
       
   891 			}
       
   892 		else
       
   893 			{
       
   894 			endHour = iPersistedEntity.iUntilTimeInMinutes / 60;
       
   895 			endMinute = iPersistedEntity.iUntilTimeInMinutes % 60;
       
   896 			}
       
   897 
       
   898 		TDateTime endDateTime(endYear,(TMonth)endMonth,endDay,endHour,endMinute,endSecond,endMicrosecond);
       
   899 		aEndTime = endDateTime;
       
   900 
       
   901 		// convert time to UTC
       
   902 		TTzTimeReference taTimeReference(static_cast<TTzTimeReference>(iPersistedEntity.iUntilTimeReference) );
       
   903 		if (taTimeReference == ETzStdTimeReference)
       
   904 			{
       
   905 			aEndTime -= static_cast<TTimeIntervalMinutes>(iPersistedEntity.iUtcOffset);
       
   906 			}		
       
   907 
       
   908 		// aEndTime is, at this point, the beginning of the the next Std Time Alignment
       
   909 		aEndTime -= static_cast<TTimeIntervalSeconds>(1);
       
   910 		}	
       
   911 	}
       
   912 
       
   913 //
       
   914 // Calculate Start Time of TimeAlignment (UTC)
       
   915 //
       
   916 void CTzDbStdTimeAlignment::CalculateStartTime(TTime& aStartTime)
       
   917   	{
       
   918   	TInt startYear;
       
   919   	TInt startMonth;
       
   920   	TInt startDay;
       
   921   	TInt startHour;
       
   922   	TInt startMinute;
       
   923   	TInt startSecond = 0;
       
   924   	TInt startMicrosecond = 0;
       
   925   	
       
   926   	if (iPrevTimeAlignment == NULL)
       
   927   		{
       
   928   		aStartTime = 0;
       
   929   		}
       
   930   	else
       
   931   		{
       
   932   		startYear = iPrevTimeAlignment->iUntilYear;
       
   933   		startMonth = iPrevTimeAlignment->iUntilMonth; if (startMonth == (TInt)KMaxTUint8) startMonth = EJanuary;
       
   934   		startDay = iPrevTimeAlignment->iUntilDayOfMonth; if (startDay == (TInt)KMaxTUint8) startDay = 0;
       
   935   		if (iPrevTimeAlignment->iUntilTimeInMinutes == KMaxTUint16)
       
   936   			{
       
   937   			startHour = startMinute = 0;
       
   938   			}
       
   939   		else
       
   940   			{
       
   941   			startHour = iPrevTimeAlignment->iUntilTimeInMinutes / 60;
       
   942   			startMinute = iPrevTimeAlignment->iUntilTimeInMinutes % 60;
       
   943   			}
       
   944   
       
   945   		TDateTime startDateTime(startYear,(TMonth)startMonth,startDay,startHour,startMinute,startSecond,startMicrosecond);
       
   946   		aStartTime = startDateTime;
       
   947 		// convert time to UTC
       
   948 		TTzTimeReference taTimeReference(static_cast<TTzTimeReference>(iPersistedEntity.iUntilTimeReference) );
       
   949 		if (taTimeReference == ETzStdTimeReference)
       
   950 			{
       
   951 			aStartTime -= static_cast<TTimeIntervalMinutes>(iPersistedEntity.iUtcOffset);
       
   952 			}		
       
   953   		}		
       
   954   	}
       
   955 	
       
   956 //========================================================================
       
   957 
       
   958 CTzDbRuleSet* CTzDbRuleSet::NewL(CReadOnlyTzDb& aReadOnlyTzDb, const TTzRuleSet& aRuleSet)
       
   959 	{
       
   960 	CTzDbRuleSet* self = new(ELeave) CTzDbRuleSet(aReadOnlyTzDb,aRuleSet);
       
   961 	return self;	
       
   962 	}
       
   963 
       
   964 
       
   965 CTzDbRuleSet::CTzDbRuleSet(CReadOnlyTzDb& aReadOnlyTzDb, const TTzRuleSet& aRuleSet)
       
   966 	: iReadOnlyTzDb(aReadOnlyTzDb),
       
   967 	iPersistedEntity(aRuleSet)
       
   968 	{
       
   969 	}
       
   970 
       
   971 //
       
   972 // Gets the encoded rules for the current standard time alignment, between aStartDateTime and aEndDateTime
       
   973 //
       
   974 void CTzDbRuleSet::GetRulesL(CTzRules& aTzRules, TInt aUtcOffset, const TDateTime& aStartDateTime, const TDateTime& aEndDateTime) const
       
   975 	{	
       
   976 	TInt startYear = aStartDateTime.Year();
       
   977 	// the last year we are interested in is the earliest of the following:
       
   978 	// 		1) the last year of the CTzRules
       
   979 	//		2) the year of aEndDateTime (the end of the invoking std time alignment)
       
   980 	
       
   981 	TInt endYear = (aEndDateTime.Year() < aTzRules.EndYear()) 
       
   982 		? aEndDateTime.Year() : aTzRules.EndYear();
       
   983 	const TDateTime rulesEndDateTime(aTzRules.EndYear(), EDecember, 30, 0,0,0,0);
       
   984 	const TDateTime& endDateTime = (aEndDateTime.Year() <= aTzRules.EndYear())
       
   985 		? aEndDateTime : rulesEndDateTime;
       
   986 	
       
   987 	RArray<TTzRuleDefinition*> ruleDefs;
       
   988 	CleanupClosePushL(ruleDefs); // PUSH #1
       
   989 	RArray<TTzRuleUse*> ruleUses;
       
   990 	CleanupClosePushL(ruleUses); // PUSH #2
       
   991 	
       
   992 	FetchRuleDefinitionsL(ruleDefs,ruleUses,startYear,endYear);
       
   993 
       
   994 	// fetch rules for previous year (these will be needed to work out the "Old Offset" field of 
       
   995 	// the first rule in aStartYear	
       
   996 	TInt initialLocalTimeOffset = GetLocalTimeOffsetAtEndOfYearL(startYear-1,aUtcOffset);
       
   997 		
       
   998 	// convert rule definitions (together with rule uses) to TTzRules and add them to aTzRules
       
   999 	
       
  1000 	CompleteRulesAndAddToCollectionL(aTzRules,ruleDefs,ruleUses,aUtcOffset,initialLocalTimeOffset,aStartDateTime,endDateTime);
       
  1001 	
       
  1002 	CleanupStack::PopAndDestroy(2,&ruleDefs); // POP #2,#1 - ruleUses, ruleDefs
       
  1003 	}
       
  1004 
       
  1005 TInt CTzDbRuleSet::GetLocalTimeOffsetAtEndOfYearL(TInt aYear, TInt aUtcOffset) const
       
  1006 	{
       
  1007 	RArray<TTzRuleDefinition*> ruleDefs;
       
  1008 	CleanupClosePushL(ruleDefs);
       
  1009 	RArray<TTzRuleUse*> ruleUses;
       
  1010 	CleanupClosePushL(ruleUses);
       
  1011 	
       
  1012 	TDateTime startDateTime(aYear,EJanuary,0,0,0,0,0);
       
  1013 	TDateTime endDateTime(aYear,EDecember,30,23,59,59,0);
       
  1014 	
       
  1015 	FetchRuleDefinitionsL(ruleDefs,ruleUses,aYear,aYear);
       
  1016 	
       
  1017 	CVTzActualisedRules* actRules = CVTzActualisedRules::NewL(aYear,aYear);
       
  1018 	CleanupStack::PushL(actRules);
       
  1019 	TVTzActualisedRule tDefaultRule(startDateTime,aUtcOffset,ETzUtcTimeReference);
       
  1020 	ActualiseRuleDefinitionsL(*actRules,ruleDefs,ruleUses,aUtcOffset,startDateTime,endDateTime,tDefaultRule);
       
  1021 
       
  1022 	TInt count = actRules->Count();
       
  1023 	TInt finalOffset = (*actRules)[count-1].iNewOffset;
       
  1024 		
       
  1025 	CleanupStack::PopAndDestroy(3,&ruleDefs);
       
  1026 	return finalOffset;
       
  1027 	}
       
  1028 
       
  1029 
       
  1030 void CTzDbRuleSet::CompleteRulesAndAddToCollectionL(
       
  1031 					CTzRules& aTzRules, 
       
  1032 					const RArray<TTzRuleDefinition*>& aRuleDefs, 
       
  1033 					const RArray<TTzRuleUse*>& aRuleUses, 
       
  1034 					TInt aUtcOffset, TInt aInitialLocalTimeOffset,
       
  1035 					TDateTime aStart, TDateTime aEnd) const
       
  1036 	{
       
  1037 	TInt count = aRuleDefs.Count();
       
  1038 	if (count != aRuleUses.Count())
       
  1039 		{
       
  1040 		User::Leave(KErrCorrupt);
       
  1041 		}
       
  1042 	
       
  1043 	TTimeWithReference startOfAlignment(aStart,ETzUtcTimeReference);
       
  1044 	TTimeWithReference endOfAlignment(aEnd,ETzUtcTimeReference);
       
  1045 
       
  1046 	//Keep track of changes to UTC offset
       
  1047 	// even if there are no DST rules.
       
  1048 	TTzRule trule(	
       
  1049 				startOfAlignment, startOfAlignment,
       
  1050 				(TUint16)aInitialLocalTimeOffset, (TUint16)aInitialLocalTimeOffset, EJanuary, ETzFixedDate,
       
  1051 				0, 0, 
       
  1052 				ETzUtcTimeReference, 
       
  1053 				0);
       
  1054 	aTzRules.AddRuleL(trule);		
       
  1055 	//Calculate the new and old offsets for each rule.
       
  1056 	TInt prevOffset = 0;
       
  1057 	TInt maxOffset = 0;
       
  1058 	for (TInt i = 0; i < count; i++)
       
  1059 		{
       
  1060 		TInt oldOffset = aInitialLocalTimeOffset;
       
  1061 		TInt dstOffset = aRuleDefs[i]->iStdTimeOffset;
       
  1062 		TInt newOffset = aUtcOffset + dstOffset;
       
  1063 		//newoffset and oldoffset should always have a difference of dstoffset.
       
  1064 		if (newOffset <= oldOffset )
       
  1065 			{
       
  1066 			//there are cases when dstoffset in the set of rules is same for few continuous rules
       
  1067 			//in such cases, newoffset and oldoffset would have a difference of maxoffset.
       
  1068 			if(prevOffset == dstOffset)
       
  1069 				{
       
  1070 				oldOffset =	aUtcOffset + maxOffset;		
       
  1071 				}
       
  1072 			else
       
  1073 				{
       
  1074 				oldOffset =	aUtcOffset + prevOffset;		
       
  1075 				}				
       
  1076 			}
       
  1077 		else
       
  1078 			//newoffset is more than oldoffset so maintain the difference with dstoffset.
       
  1079 			{
       
  1080 			oldOffset =	newOffset - dstOffset;							
       
  1081 			}
       
  1082 		prevOffset = dstOffset;		
       
  1083 		//store maximum offset, to handle cases in which dstoffset in the set of rules
       
  1084 		//is same for few continuous rules
       
  1085 		if(dstOffset > maxOffset)
       
  1086 			{
       
  1087 			maxOffset = dstOffset;
       
  1088 			}
       
  1089 			
       
  1090 		TUint16 timeOfChange = aRuleDefs[i]->iTimeOfChange;
       
  1091 		TTzTimeReference timeReference = 
       
  1092 			static_cast<TTzTimeReference>(aRuleDefs[i]->iTimeReference);
       
  1093 
       
  1094 		//
       
  1095 
       
  1096 		// Find the intersection of the date ranges:
       
  1097 		//  use latest start year, earliest end year
       
  1098 		TDateTime start = aStart;
       
  1099 		TDateTime end = aEnd;
       
  1100 		if(aRuleUses[i]->iFromYear > start.Year())
       
  1101 			{
       
  1102 			start = TDateTime(aRuleUses[i]->iFromYear,EJanuary,0,0,0,0,0);
       
  1103 			}
       
  1104 			
       
  1105 		if(aEnd.Year() > aRuleUses[i]->iUntilYear)
       
  1106 			{
       
  1107 			end = TDateTime(aRuleUses[i]->iUntilYear,EDecember,30,23,59,59,0);
       
  1108 			}
       
  1109 			
       
  1110 		TTimeWithReference startOfRule(start,ETzUtcTimeReference);
       
  1111 		TTimeWithReference endOfRule(end,ETzUtcTimeReference);
       
  1112 		if(endOfRule.iTime >= startOfRule.iTime)
       
  1113 			{
       
  1114 			TTzRule trule(	
       
  1115 						startOfRule, endOfRule,
       
  1116 						(TUint16)oldOffset, (TUint16)newOffset, (TMonth)aRuleDefs[i]->iMonth, (TTzRuleDay)aRuleDefs[i]->iDayRule,
       
  1117 						aRuleDefs[i]->iDayOfMonth, aRuleDefs[i]->iDayOfWeek, 
       
  1118 						timeReference, timeOfChange);				 
       
  1119 
       
  1120 			aTzRules.AddRuleL(trule);
       
  1121 	
       
  1122 			}
       
  1123 		}	
       
  1124 	}
       
  1125 
       
  1126 void CTzDbRuleSet::FetchRuleDefinitionsL(RArray<TTzRuleDefinition*>& aTzRuleDefinitions, RArray<TTzRuleUse*>& aTzRuleUses, TInt aStartYear, TInt aEndYear) const
       
  1127 	{	
       
  1128 	TInt ruleUseCount = iPersistedEntity.iNumberOfRuleUses;
       
  1129 	TTzRuleUse* truleUse(NULL);
       
  1130 	TTzRuleDefinition* truleDef(NULL);	
       
  1131 	for (TInt i = 0; i < ruleUseCount; i++)
       
  1132 		{
       
  1133 		truleUse = const_cast<TTzRuleUse*>(&iReadOnlyTzDb.GetTRuleUse(iPersistedEntity.iOffsetsToRuleUses[i]));
       
  1134 		
       
  1135 		// intersect rule use with (startYear,endYear) period
       
  1136 		if ( (truleUse->iFromYear <= aEndYear) && (truleUse->iUntilYear >= aStartYear) )
       
  1137 			{
       
  1138 			// Found one rule use valid during the years of interest - fetch rule definition.
       
  1139 			// For every year, check if it occurs within (aStartTime,aEndTime)
       
  1140 			truleDef = const_cast<TTzRuleDefinition*>(&iReadOnlyTzDb.GetTRuleDefinition(truleUse->iOffsetToRuleDefinition));
       
  1141 			// check that the rule definition has valid data. leave if the data is not valid, as it would mean that the database is corrupt
       
  1142 			User::LeaveIfError(CTzHelpers::Validate((const TTzRuleDefinition&)*truleDef));
       
  1143 			
       
  1144 			// Add rule definition ptr to array
       
  1145 			aTzRuleDefinitions.Append(truleDef);
       
  1146 			// Add rule use ptr to array
       
  1147 			aTzRuleUses.Append(truleUse);
       
  1148 			}
       
  1149 		}
       
  1150 	}
       
  1151 
       
  1152 void CTzDbRuleSet::ActualiseRuleDefinitionsL(CVTzActualisedRules& aActualisedRules, const RArray<TTzRuleDefinition*>& aTzRuleDefinitions, const RArray<TTzRuleUse*>& aTzRuleUses, TInt aUtcOffset, const TDateTime& aStartDateTime, const TDateTime& aEndDateTime, const TVTzActualisedRule& aDefaultRule) const
       
  1153 	{
       
  1154 	TInt startYear = aStartDateTime.Year();
       
  1155 	TInt endYear = (aActualisedRules.EndYear() < (TUint)aEndDateTime.Year()) ? aActualisedRules.EndYear() : aEndDateTime.Year();	
       
  1156 	TInt rulesAddedSoFar = 0;
       
  1157 	TInt yearOfFirstRule = endYear;	
       
  1158 	TInt count = aTzRuleDefinitions.Count();
       
  1159 	
       
  1160 	TInt oldOffset = 0; // Arbitrarily set to zero. Required to create TTzRule.
       
  1161 	
       
  1162 	for (TInt i = 0; i < count; i++)
       
  1163 		{
       
  1164 		for (TInt year = (startYear > aTzRuleUses[i]->iFromYear) ? startYear : aTzRuleUses[i]->iFromYear ; (year <= endYear) && (year <= aTzRuleUses[i]->iUntilYear); year++)
       
  1165 			{
       
  1166 			TTzRule trule(	
       
  1167 					static_cast<TUint16>(startYear), static_cast<TUint16>(endYear),
       
  1168 					static_cast<TUint16>(oldOffset), static_cast<TUint16>(aUtcOffset + aTzRuleDefinitions[i]->iStdTimeOffset),static_cast<TMonth>(aTzRuleDefinitions[i]->iMonth), static_cast<TTzRuleDay>(aTzRuleDefinitions[i]->iDayRule),
       
  1169 					static_cast<TUint8>(aTzRuleDefinitions[i]->iDayOfMonth), static_cast<TUint8>(aTzRuleDefinitions[i]->iDayOfWeek), 
       
  1170 					static_cast<TTzTimeReference>(aTzRuleDefinitions[i]->iTimeReference), static_cast<TTzTimeReference>(aTzRuleDefinitions[i]->iTimeOfChange));
       
  1171 			
       
  1172 			TVTzActualisedRule tActRule = trule.Actualise(year);
       
  1173 			if ( (tActRule.iTimeOfChange < aEndDateTime) && (tActRule.iTimeOfChange >= aStartDateTime) )
       
  1174 				{
       
  1175 				aActualisedRules.AddRuleL(tActRule);
       
  1176 				// record the year of the first rule added
       
  1177 				if (rulesAddedSoFar == 0)
       
  1178 					{
       
  1179 					yearOfFirstRule = year;
       
  1180 					}
       
  1181 				rulesAddedSoFar++;			
       
  1182 				}
       
  1183 			}
       
  1184 		}
       
  1185 		
       
  1186 	// In some cases we need to add a "default rule" to aRules. ("Default rule" 
       
  1187 	// means a rule with zero as DST offset and the start-time of the time-alignment 
       
  1188 	// as time-of-change). This default rule will be added if no rule exists for the
       
  1189 	// first year of the time alignment.
       
  1190 	if ( (rulesAddedSoFar == 0) || (yearOfFirstRule > startYear) )
       
  1191 		{
       
  1192 		aActualisedRules.AddRuleL(aDefaultRule);
       
  1193 		}			
       
  1194 	}
       
  1195 	
       
  1196 //============================================================================================
       
  1197 
       
  1198 TInt CTzHelpers::Validate(const TTzRuleDefinition& aRuleDefinition)
       
  1199 	{
       
  1200 	if (aRuleDefinition.iStdTimeOffset > KMaxDstOffset)
       
  1201 		{
       
  1202 		return KErrCorrupt;
       
  1203 		}
       
  1204 
       
  1205 	if (aRuleDefinition.iMonth > EDecember)
       
  1206 		{
       
  1207 		return KErrCorrupt;
       
  1208 		}
       
  1209 
       
  1210 	if (aRuleDefinition.iDayRule > KValidatedLastDayRule) // last element of enum TTzRuleDay
       
  1211 		{
       
  1212 		return KErrCorrupt;
       
  1213 		}
       
  1214 
       
  1215 	if (aRuleDefinition.iDayOfMonth > KMaxDayOfMonth)
       
  1216 		{
       
  1217 		return KErrCorrupt;
       
  1218 		}
       
  1219 
       
  1220 	if (aRuleDefinition.iDayOfWeek > ESunday)
       
  1221 		{
       
  1222 		return KErrCorrupt;
       
  1223 		}
       
  1224 
       
  1225 	if (aRuleDefinition.iTimeReference > KValidatedLastTimeReference) // last element of enum TTzTimeReference
       
  1226 		{
       
  1227 		return KErrCorrupt;
       
  1228 		}
       
  1229 
       
  1230 	if (aRuleDefinition.iTimeOfChange >= KMinutesInOneDay)
       
  1231 		{
       
  1232 		return KErrCorrupt;
       
  1233 		}
       
  1234 
       
  1235 	return KErrNone;
       
  1236 	}