tzservices/tzserver/Client/Source/vtzrules.cpp
changeset 0 2e3d3ce01487
child 81 676b6116ca93
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 // Copyright (c) 2005-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 <s32buf.h>
       
    17 #include <vtzrules.h>
       
    18 #include <tz.h>
       
    19 
       
    20 #include "tzrules.h"
       
    21 
       
    22 const TInt KDaysInTheWeek = 7;
       
    23 const TInt KTzRulesGranularity = 4;
       
    24 
       
    25 //
       
    26 // TVTzRule
       
    27 //
       
    28 
       
    29 /**
       
    30 Constructor for a time zone rule.
       
    31 
       
    32 @publishedAll
       
    33 @released
       
    34 
       
    35 @param aFrom The first date at which the rule applies.
       
    36 @param aTo The last date at which the rule applies.
       
    37 @param aOldOffset The UTC offset in minutes which applies before the DST change.
       
    38 @param aNewOffset The UTC offset in minutes which applies after the DST change.
       
    39 @param aMonth The month in which the DST change occurs.
       
    40 @param aDayRule The rule defining on which day the DST change takes place.
       
    41 @param aDayOfMonth The number of the day within the month, offset from zero.  Used in conjunction with 
       
    42        aDayRule to define the day when DST changes.
       
    43 @param aDayOfWeek The number of the day within the week, the numerical equivalent of a TDay value.  
       
    44        Used in conjunction with aDayRule to define the day where DST changes.
       
    45 @param aTimeReference Defines whether aTimeOfChange is a local (wall-clock) time or a UTC time.
       
    46 @param aTimeOfChange The time of the DST change in minutes from midnight.
       
    47 */
       
    48 EXPORT_C TTzRule::TTzRule(TTimeWithReference aFrom, TTimeWithReference aTo, TInt16 aOldOffset, TInt16 aNewOffset, TMonth aMonth, TTzRuleDay aDayRule,
       
    49 				TUint8 aDayOfMonth, TUint8 aDayOfWeek, TTzTimeReference aTimeReference, TUint16 aTimeOfChange) :
       
    50  	iFrom(aFrom),
       
    51 	iTo(aTo),
       
    52 	iOldLocalTimeOffset(aOldOffset),
       
    53 	iNewLocalTimeOffset(aNewOffset),
       
    54 	iMonth(aMonth),
       
    55 	iDayRule(aDayRule),
       
    56 	iDayOfMonth(aDayOfMonth),
       
    57 	iDayOfWeek(aDayOfWeek),
       
    58 	iTimeReference(aTimeReference),
       
    59 	iTimeOfChange(aTimeOfChange)
       
    60 	{
       
    61 	}
       
    62 
       
    63 /**
       
    64 Constructor for a time zone rule.
       
    65 
       
    66 @publishedAll
       
    67 @released
       
    68 
       
    69 @param aFromYear The first year in which the rule applies.
       
    70 @param aToYear The last year in which the rule applies.
       
    71 @param aOldOffset The UTC offset in minutes which applies before the DST change.
       
    72 @param aNewOffset The UTC offset in minutes which applies after the DST change.
       
    73 @param aMonth The month in which the DST change occurs.
       
    74 @param aDayRule The rule defining on which day the DST change takes place.
       
    75 @param aDayOfMonth The number of the day within the month, offset from zero.  Used in conjunction with 
       
    76        aDayRule to define the day where DST changes.  
       
    77 @param aDayOfWeek The number of the day within the week, the numerical equivalent of a TDay value.  
       
    78        Used in conjunction with aDayRule to define the day where DST changes.
       
    79 @param aTimeReference Defines whether aTimeOfChange is a local (wall-clock) time or a UTC time.
       
    80 @param aTimeOfChange The time of the DST change in minutes from midnight.
       
    81 */
       
    82 EXPORT_C TTzRule::TTzRule(TInt16 aFromYear, TInt16 aToYear, TInt16 aOldOffset, TInt16 aNewOffset, TMonth aMonth, TTzRuleDay aDayRule,
       
    83 				TUint8 aDayOfMonth, TUint8 aDayOfWeek, TTzTimeReference aTimeReference, TUint16 aTimeOfChange) :
       
    84  	iFrom(TTimeWithReference(TDateTime(aFromYear,EJanuary,0,0,0,0,0))),
       
    85 	iTo(TTimeWithReference(TDateTime(aToYear,EDecember,30,23,59,59,0))),
       
    86 	iOldLocalTimeOffset(aOldOffset),
       
    87 	iNewLocalTimeOffset(aNewOffset),
       
    88 	iMonth(aMonth),
       
    89 	iDayRule(aDayRule),
       
    90 	iDayOfMonth(aDayOfMonth),
       
    91 	iDayOfWeek(aDayOfWeek),
       
    92 	iTimeReference(aTimeReference),
       
    93 	iTimeOfChange(aTimeOfChange)
       
    94 	{
       
    95 	}
       
    96 
       
    97 /**
       
    98 Default constructor for a time zone rule.
       
    99 
       
   100 All member variables are set to zero values.
       
   101 
       
   102 @publishedAll
       
   103 @released
       
   104 */
       
   105 EXPORT_C TTzRule::TTzRule() :
       
   106 	iOldLocalTimeOffset(0),
       
   107 	iNewLocalTimeOffset(0),
       
   108 	iMonth(EJanuary),
       
   109 	iDayRule(ETzFixedDate),
       
   110 	iDayOfMonth(0),
       
   111 	iDayOfWeek(0),
       
   112 	iTimeReference(ETzWallTimeReference),
       
   113 	iTimeOfChange(0)
       
   114 	{
       
   115 	}
       
   116 
       
   117 /**
       
   118 Copy constructor for a time zone rule.
       
   119 
       
   120 @publishedAll
       
   121 @released
       
   122 */
       
   123 EXPORT_C TTzRule::TTzRule(const TTzRule& aRule) :
       
   124  	iFrom(aRule.iFrom),
       
   125 	iTo(aRule.iTo),
       
   126 	iOldLocalTimeOffset(aRule.iOldLocalTimeOffset),
       
   127 	iNewLocalTimeOffset(aRule.iNewLocalTimeOffset),
       
   128 	iMonth(aRule.iMonth),
       
   129 	iDayRule(aRule.iDayRule),
       
   130 	iDayOfMonth(aRule.iDayOfMonth),
       
   131 	iDayOfWeek(aRule.iDayOfWeek),
       
   132 	iTimeReference(aRule.iTimeReference),
       
   133 	iTimeOfChange(aRule.iTimeOfChange)
       
   134 	{
       
   135 	}
       
   136 
       
   137 /** 
       
   138 Externalises a time zone rule to a write stream.
       
   139 
       
   140 @param aStream Stream to which the object should be externalised. 
       
   141 @internalComponent
       
   142 @released
       
   143 */ 
       
   144 void TTzRule::ExternalizeL(RWriteStream& aStream) const
       
   145 	{
       
   146 	aStream << iFrom.iTime.Int64();
       
   147 	aStream << static_cast<TInt32>(iFrom.iTimeReference);
       
   148 	aStream << iTo.iTime.Int64();
       
   149 	aStream << static_cast<TInt32>(iTo.iTimeReference);
       
   150 	aStream << iOldLocalTimeOffset;
       
   151 	aStream << iNewLocalTimeOffset;
       
   152 	aStream << static_cast<TInt32>(iMonth);
       
   153 	aStream << static_cast<TInt32>(iDayRule);
       
   154 	aStream << iDayOfMonth;
       
   155 	aStream << iDayOfWeek;
       
   156 	aStream << static_cast<TInt32>(iTimeReference);
       
   157 	aStream << iTimeOfChange;
       
   158 	}
       
   159 
       
   160 /** 
       
   161 Internalizes a time zone rule from a read stream.
       
   162 
       
   163 @param aStream Stream from which the object should be internalised. 
       
   164 @internalComponent
       
   165 @released
       
   166 */ 
       
   167 void TTzRule::InternalizeL(RReadStream& aStream)
       
   168 	{
       
   169 	TInt64 time;
       
   170 	aStream >> time;	
       
   171 	iFrom.iTime = TTime(time);
       
   172 	iFrom.iTimeReference = static_cast<TTzTimeReference>(aStream.ReadInt32L());
       
   173 	aStream >> time;	
       
   174 	iTo.iTime = TTime(time);
       
   175 	iTo.iTimeReference = static_cast<TTzTimeReference>(aStream.ReadInt32L());
       
   176 	aStream >> iOldLocalTimeOffset;
       
   177 	aStream >> iNewLocalTimeOffset;
       
   178 	iMonth = static_cast<TMonth>(aStream.ReadInt32L());
       
   179 	iDayRule = static_cast<TTzRuleDay>(aStream.ReadInt32L());
       
   180 	aStream >> iDayOfMonth;
       
   181 	aStream >> iDayOfWeek;
       
   182 	iTimeReference = static_cast<TTzTimeReference>(aStream.ReadInt32L());
       
   183 	aStream >> iTimeOfChange;
       
   184 	}
       
   185 
       
   186 
       
   187 /** 
       
   188 Check if a time zone rule is applicable during a time range.
       
   189 
       
   190 @return ETrue if the rule applies during the supplied time range, EFalse otherwise.
       
   191 @param aStart Start of time range, inclusively.  ie. For a rule to be applicable, this time
       
   192        can be equal to or earlier than the rule's end time.  This time should use the same 
       
   193        time reference used when TTzRule is constructed.
       
   194 @param aEnd End of time range, exclusively.  ie. In order for a rule to be applicable, this 
       
   195        time must be later than the rule's start time.  This time should use the same 
       
   196        time reference used when TTzRule is constructed.
       
   197 @internalComponent
       
   198 @released
       
   199 */ 
       
   200 TBool TTzRule::RuleApplies(const TTime& aStart, const TTime& aEnd) const
       
   201  	{
       
   202 	// If the end of the rule is in the time range or the beginning of the rule is in the time range
       
   203 	return ( (iTo.iTime >= aStart) && (iFrom.iTime < aEnd) );
       
   204  	}
       
   205 
       
   206 /**
       
   207 Resolves the date rule to the precise date and time for the given year, and
       
   208 returns it in a TVTzActualisedRule
       
   209 
       
   210 For day rules ETzDayAfterDate & ETzDayBeforeDate, the reference date entered 
       
   211 is inclusive in the calculation.  ie. If the reference date fits the criteria,
       
   212 the reference date will be returned.   
       
   213 
       
   214 eg. Actualise(Friday, ETzDayAfterDate, Fri Jun 22, 2007) returns Jun 22, 2007.
       
   215 
       
   216 Deprecated.  Use TVTzActualisedRule TTzRule::ActualiseL instead.
       
   217 
       
   218 @return The time zone rule with the precise date and time for the given year.
       
   219 @param aYear Year to actualise time rules
       
   220 @publishedAll
       
   221 @deprecated 
       
   222 @see TVTzActualisedRule TTzRule::ActualiseL(TInt aYear) const
       
   223 */
       
   224 EXPORT_C TVTzActualisedRule TTzRule::Actualise(TInt aYear) const
       
   225     {
       
   226     TVTzActualisedRule rule;
       
   227     TRAP_IGNORE(rule = ActualiseL(aYear));        
       
   228     return rule;
       
   229     }
       
   230 
       
   231 /**
       
   232 Resolves the date rule to the precise date and time for the given year, and
       
   233 returns it in a TVTzActualisedRule
       
   234 
       
   235 For day rules ETzDayAfterDate & ETzDayBeforeDate, the reference date entered 
       
   236 is inclusive in the calculation.  ie. If the reference date fits the criteria,
       
   237 the reference date will be returned.   
       
   238 
       
   239 eg. Actualise(Friday, ETzDayAfterDate, Fri Jun 22, 2007) returns Jun 22, 2007.
       
   240 
       
   241 @return The time zone rule with the precise date and time for the given year.
       
   242 @param aYear Year to actualise time rules
       
   243 @leave KErrCorrupt if the current day rule is not one of the defined values in TTzRuleDay
       
   244 @publishedAll
       
   245 @released
       
   246 */
       
   247 EXPORT_C TVTzActualisedRule TTzRule::ActualiseL(TInt aYear) const
       
   248 	{
       
   249 	TInt dayOfMonth = iDayOfMonth;
       
   250 	TInt daysDifference = 0;
       
   251 	TDay dayOfWeek(EMonday);
       
   252 
       
   253 	TDateTime actualDateTime(aYear,
       
   254 						(TMonth)iMonth,
       
   255 						dayOfMonth,
       
   256 						(iTimeOfChange / 60),
       
   257 						(iTimeOfChange % 60),
       
   258 						0,
       
   259 						0);
       
   260 	TTime actualTime(actualDateTime);
       
   261 	switch(iDayRule)
       
   262 		{
       
   263 		case ETzFixedDate:
       
   264 			// do nothing
       
   265 			break;
       
   266 
       
   267 		case ETzDayAfterDate:
       
   268 			// e.g. "Sunday after the 15th"
       
   269 
       
   270 			// find day in week for given date
       
   271 			dayOfWeek = actualTime.DayNoInWeek();
       
   272 
       
   273 			// find difference in days to the rule date
       
   274 			daysDifference = iDayOfWeek - dayOfWeek;
       
   275 			// make positive difference
       
   276 			if (daysDifference < 0)
       
   277 				{
       
   278 				daysDifference += KDaysInTheWeek;	// sunday is last day of month
       
   279 				}
       
   280 
       
   281 			// set actual day
       
   282 			dayOfMonth += daysDifference;
       
   283 			actualDateTime.SetDay(dayOfMonth);
       
   284 			break;
       
   285 
       
   286 		case ETzDayBeforeDate:
       
   287 			// e.g. "Sunday before the 15th"
       
   288 
       
   289 			// find day in week for given date
       
   290 			dayOfWeek = actualTime.DayNoInWeek();
       
   291 
       
   292 			// find difference in days to the rule date
       
   293 			daysDifference = dayOfWeek - iDayOfWeek;
       
   294 			// make positive difference
       
   295 			if (daysDifference < 0)
       
   296 				{
       
   297 				daysDifference += KDaysInTheWeek;	// sunday is last day of month
       
   298 				}
       
   299 
       
   300 			// set actual day
       
   301 			dayOfMonth -= daysDifference;
       
   302 			actualDateTime.SetDay(dayOfMonth);
       
   303 			break;
       
   304 
       
   305 		case ETzDayInLastWeekOfMonth:
       
   306 			// e.g. "last Sunday in the month"
       
   307 
       
   308 			// initialise the day to the last day in the month,
       
   309 			dayOfMonth = actualTime.DaysInMonth() - 1; // days offset from 0
       
   310 			actualDateTime.SetDay(dayOfMonth);
       
   311 
       
   312 			// find day in week for given date
       
   313 			actualTime = actualDateTime;
       
   314 			dayOfWeek = actualTime.DayNoInWeek();
       
   315 
       
   316 			// find difference in days to the rule date
       
   317 			daysDifference = dayOfWeek - iDayOfWeek;
       
   318 			// make positive difference
       
   319 			if (daysDifference < 0)
       
   320 				{
       
   321 				daysDifference += KDaysInTheWeek;	// sunday is last day of month
       
   322 				}
       
   323 
       
   324 			// set actual day
       
   325 			dayOfMonth -= daysDifference;
       
   326 			actualDateTime.SetDay(dayOfMonth);
       
   327 			break;
       
   328 
       
   329 		default:
       
   330 			User::Leave(KErrCorrupt);  // If data is corrupt method leaves
       
   331 			break;
       
   332 		}
       
   333 
       
   334 	actualTime = actualDateTime;
       
   335 
       
   336 	TVTzActualisedRule tActRule(actualTime, 
       
   337 		iNewLocalTimeOffset, 
       
   338 		static_cast<TTzTimeReference>(iTimeReference));
       
   339 	return tActRule;
       
   340 	}
       
   341 
       
   342 //
       
   343 // CTzRules
       
   344 //
       
   345 
       
   346 /**
       
   347 Creates a new time zone rules object.
       
   348 @return Pointer to the time zone rules.
       
   349 @publishedAll
       
   350 @released
       
   351 */
       
   352 EXPORT_C CTzRules* CTzRules::NewL()
       
   353 	{
       
   354 	CTzRules* self = new(ELeave) CTzRules();
       
   355 	return self;
       
   356 	}
       
   357 
       
   358 /**
       
   359 Creates a new time zone rules object.
       
   360 @param aStartYear The first year in which these time zone rules apply.
       
   361 @param aEndYear The last year in which these time zone rules apply.
       
   362 @return Pointer to the time zone rules.
       
   363 @publishedAll
       
   364 @released
       
   365 */
       
   366 EXPORT_C CTzRules* CTzRules::NewL(TInt aStartYear, TInt aEndYear)
       
   367 	{
       
   368 	CTzRules* self = new(ELeave) CTzRules(aStartYear,aEndYear);
       
   369 	return self;
       
   370 	}
       
   371 
       
   372 /**
       
   373 Creates a new time zone rules object from a stream.
       
   374 @return Pointer to the time zone rules.
       
   375 @param aStream Stream with the time zone rules to be used to create a CTzRules object.
       
   376 @publishedAll
       
   377 @released
       
   378 */
       
   379 EXPORT_C CTzRules* CTzRules::NewL(RReadStream& aStream)
       
   380 	{
       
   381 	CTzRules* self = new(ELeave) CTzRules();
       
   382 	CleanupStack::PushL(self);
       
   383 	self->InternalizeL(aStream);
       
   384 	CleanupStack::Pop(self);
       
   385 	return self;
       
   386 	}
       
   387 
       
   388 CTzRules::CTzRules(TInt aStartYear, TInt aEndYear) :
       
   389 	iStartYear((TInt16)aStartYear),
       
   390 	iEndYear((TInt16)aEndYear),
       
   391 	iRules(KTzRulesGranularity)
       
   392 	{
       
   393 	}
       
   394 
       
   395 CTzRules::CTzRules() :
       
   396 	iRules(KTzRulesGranularity)
       
   397 	{
       
   398 	}
       
   399 
       
   400 /**
       
   401 Destructor.
       
   402 @publishedAll
       
   403 @released
       
   404 */
       
   405 EXPORT_C CTzRules::~CTzRules()
       
   406 	{
       
   407 	delete iActualisedRulesCache;
       
   408 	iRules.Reset();
       
   409 	}
       
   410 
       
   411 /**
       
   412 Get the object size when it is internalize and externalised.
       
   413 
       
   414 @return the size of thisobject 
       
   415 @internalComponent
       
   416 @released
       
   417 */
       
   418 EXPORT_C TInt CTzRules::SizeOfObject() const
       
   419 	{
       
   420 	return iRules.Count() * sizeof (TTzRule) + 4*sizeof (TInt16);
       
   421 	//As to 4 size of TInt16, they are for iStartYear, iEndYear, iInitialStdTimeOffset and the count of array of TTzRule
       
   422 	}
       
   423 /**
       
   424 Internalizes time zone rules from a read stream.
       
   425 
       
   426 @param aStream Stream from which the object should be internalised. 
       
   427 @publishedAll
       
   428 @released
       
   429 */
       
   430 EXPORT_C void CTzRules::InternalizeL(RReadStream& aStream)
       
   431 	{
       
   432 	iRules.Reset();
       
   433 
       
   434 	// read start and end year covered by rules
       
   435 	iStartYear = aStream.ReadInt16L();
       
   436 	iEndYear = aStream.ReadInt16L();
       
   437 
       
   438 	// read initial std time offset
       
   439 	iInitialStdTimeOffset = aStream.ReadInt16L();
       
   440 	
       
   441 	// read number of rules
       
   442 	const TInt16 KCount = aStream.ReadInt16L();
       
   443 
       
   444 	// read rules
       
   445 	TTzRule rule;
       
   446 	for (TInt i = 0; i < KCount; ++i)
       
   447 		{
       
   448 		rule.InternalizeL(aStream);
       
   449 		User::LeaveIfError(iRules.Append(rule));
       
   450 		}
       
   451 	
       
   452 	// The cache has been invalidated so clear it
       
   453 	delete iActualisedRulesCache;
       
   454 	iActualisedRulesCache = NULL;
       
   455 	}
       
   456 
       
   457 /** 
       
   458 Externalises time zone rules to a write stream.
       
   459 
       
   460 @param aStream Stream to which the object should be externalised. 
       
   461 @leave KErrArgument if the output stream size is invalid
       
   462 @publishedAll
       
   463 @released
       
   464 */
       
   465 EXPORT_C void CTzRules::ExternalizeL(RWriteStream& aStream) const
       
   466 	{
       
   467 	// Ensure the size of the stream is valid.
       
   468 	TInt size = aStream.Sink()->SizeL();
       
   469 	const TInt KMaxSize = KMaxTInt / 2;
       
   470 	if (size < 0 || size >= KMaxSize)
       
   471 	    {
       
   472 	    User::Leave(KErrArgument);
       
   473 	    }
       
   474 
       
   475 	// write range of years covered by rules
       
   476 	aStream.WriteInt16L(iStartYear);
       
   477 	aStream.WriteInt16L(iEndYear);
       
   478 	
       
   479 	// write initial std time offset
       
   480 	aStream.WriteInt16L(iInitialStdTimeOffset);
       
   481 	
       
   482 	// write number of rules
       
   483 	const TInt16 KCount = (TInt16)iRules.Count();
       
   484 	aStream.WriteInt16L(KCount);
       
   485 
       
   486 	// write rules
       
   487 	for (TInt i = 0; i < KCount; i++)
       
   488 		{
       
   489 		iRules[i].ExternalizeL(aStream);
       
   490 		}
       
   491 	}
       
   492 
       
   493 /**
       
   494 Gets the first year in which the time zone rules apply.
       
   495 @return The year.
       
   496 @publishedAll
       
   497 @released
       
   498 */
       
   499 EXPORT_C TInt CTzRules::StartYear() const
       
   500 	{
       
   501 	return iStartYear;
       
   502 	}
       
   503 
       
   504 /**
       
   505 Gets the last year in which the time zone rules apply.
       
   506 @return The year.
       
   507 @publishedAll
       
   508 @released
       
   509 */
       
   510 EXPORT_C TInt CTzRules::EndYear() const
       
   511 	{
       
   512 	return iEndYear;
       
   513 	}
       
   514 
       
   515 /**
       
   516 Sets the first year in which the time zone rules apply.
       
   517 @param aYear The year.
       
   518 @publishedAll
       
   519 @released
       
   520 */
       
   521 EXPORT_C void CTzRules::SetStartYear(TInt aYear)
       
   522 	{
       
   523 	iStartYear = (TInt16)aYear;
       
   524 	}
       
   525 
       
   526 /**
       
   527 Sets the last year in which the time zone rules apply.
       
   528 @param aYear The year.
       
   529 @publishedAll
       
   530 @released
       
   531 */
       
   532 EXPORT_C void CTzRules::SetEndYear(TInt aYear)
       
   533 	{
       
   534 	iEndYear = (TInt16)aYear;
       
   535 	}
       
   536 
       
   537 /**
       
   538 Gets the number of time zone rules (TTzRules) in this set.
       
   539 @return The number of rules.
       
   540 @publishedAll
       
   541 @released
       
   542 */
       
   543 EXPORT_C TInt CTzRules::Count() const
       
   544 	{
       
   545 	return iRules.Count();
       
   546 	}
       
   547 
       
   548 /**
       
   549 Gets the initial UTC offset for this set of time zone rules.
       
   550 @return The offset in minutes.
       
   551 @publishedAll
       
   552 @released
       
   553 */
       
   554 EXPORT_C TInt CTzRules::InitialStdTimeOffset() const
       
   555 	{
       
   556 	return iInitialStdTimeOffset;
       
   557 	}
       
   558 	
       
   559 /**
       
   560 Sets the initial UTC offset for this set of time zone rules.
       
   561 @param aOffset The offset in minutes.
       
   562 @publishedAll
       
   563 @released
       
   564 */
       
   565 EXPORT_C void CTzRules::SetInitialStdTimeOffset(TInt aOffset)
       
   566 	{
       
   567 	// The cache has been invalidated so clear it
       
   568 	delete iActualisedRulesCache;
       
   569 	iActualisedRulesCache = NULL;
       
   570 	
       
   571 	iInitialStdTimeOffset = aOffset;
       
   572 	}
       
   573 	
       
   574 /**
       
   575 Adds a time zone rule to this set.
       
   576 @param aTRule The rule to be added.
       
   577 @publishedAll
       
   578 @released
       
   579 */
       
   580 EXPORT_C void CTzRules::AddRuleL(TTzRule aTRule)
       
   581 	{
       
   582 	// the cache has been invalidated so clear it
       
   583 	delete iActualisedRulesCache;
       
   584 	iActualisedRulesCache = NULL;
       
   585 	
       
   586 	TInt result = iRules.Append(aTRule);
       
   587 	User::LeaveIfError(result);
       
   588 	}
       
   589 
       
   590 /**
       
   591 Removes a time zone rule from this set.
       
   592 @param aIndex The index of the rule to be removed.
       
   593 @publishedAll
       
   594 @released
       
   595 */
       
   596 EXPORT_C void CTzRules::RemoveRule(TInt aIndex)
       
   597 	{
       
   598 	// the cache has been invalidated so clear it
       
   599 	delete iActualisedRulesCache;
       
   600 	iActualisedRulesCache = NULL;
       
   601 		
       
   602 	iRules.Remove(aIndex);
       
   603 	}
       
   604 
       
   605 /**
       
   606 Gets a time zone rule from this set.
       
   607 @param aIndex The index of the rule to be fetched.
       
   608 @return Reference to the time zone rule.
       
   609 @publishedAll
       
   610 @released
       
   611 */
       
   612 EXPORT_C TTzRule& CTzRules::operator[](TInt aIndex)
       
   613 	{
       
   614 	// prevent array bounds error
       
   615 	__ASSERT_ALWAYS( (aIndex < iRules.Count() && aIndex >= 0), RTz::Panic(RTz::EPanicRulesIndexOutofRange));
       
   616 	
       
   617 	return iRules[aIndex];
       
   618 	}
       
   619 
       
   620 /**
       
   621 Queries the time zone rule set to see if they apply to a specified time.
       
   622 @param aTime The time to be checked, using the same time reference used when constructing 
       
   623        CTzRules.
       
   624 @return ETrue if the time zone rules apply to the specified time. EFalse if not.
       
   625 @publishedAll
       
   626 @released
       
   627 */
       
   628  EXPORT_C TBool CTzRules::RulesApply(const TTime& aTime) const
       
   629  	{
       
   630 	const TTime KStart(TDateTime(iStartYear, EJanuary, 0, 0, 0, 0, 0));
       
   631 	const TTime KEnd(TDateTime(iEndYear + 1, EJanuary, 0, 0, 0, 0, 0));
       
   632 	return ((aTime >= KStart) && (aTime < KEnd));
       
   633  	}
       
   634 
       
   635 
       
   636 /**
       
   637 
       
   638 Compares two times with time references (TTzTimeReference).
       
   639 TTzTimeReference is either UTC, or STD, or ETzWallTimeReference.
       
   640 
       
   641 Comparison is done at some point in time when aStdOffset applies to item(s) with ETzStdTimeReference, 
       
   642 and aWallOffset applies to item(s) with ETzWallTimeReference.
       
   643 
       
   644 If time references for both aTimeA and aTimeB are the same, then straight comparison is done to 
       
   645 aTimeA and aTimeB. Otherwise, STD or wall-clock time is converted to UTC using either aStdOffset, 
       
   646 or aWallOffset correspondingly.
       
   647 
       
   648 Thus, aStdOffset parameter is never used if none of aTimeA and aTimeB is ETzStdTimeReference;
       
   649 and, similarly, aWallOffset is never used if none of aTimeA and aTimeB is ETzWallTimeReference.
       
   650 
       
   651 @param	aTimeA		- first time with reference;
       
   652 @param	aTimeB		- second time with reference, to compare to aTimeA;
       
   653 @param	aStdOffset	- an offset (in minutes) to be used for a time with ETzStdTimeReference;
       
   654 @param	aWallOffset	- an offset (in minutes) to be used for a time with ETzWallTimeReference;
       
   655 @param	aMinutesDifference	-on return, the time difference between aTimeA and aTimeB in minutes;
       
   656 
       
   657 @return TInt		-1 if aTimeA is < aTimeB;
       
   658 					 0 if aTimeA is equal to aTimeB;
       
   659 					 1 if aTimeA is > aTimeB.	 
       
   660 Example: 
       
   661 	compare 20050403T020200 local with 20050403T020100Z UTC in PST time zone (-0800):
       
   662 			CompareTimesWithRef(20050403T020200, wall, 20050403T020100, utc, 0(not used), -8(PST))  gives -1;
       
   663 	while 	CompareTimesWithRef(20050403T020200, wall, 20050403T020100, utc, 0(not used), 0(GMT))  gives 1.
       
   664 
       
   665 @internalComponent
       
   666 @released
       
   667  */ 
       
   668 TInt CTzRules::CompareTimesWithRef(TTime aTimeA, TTzTimeReference aTimeARef,
       
   669 								   TTime aTimeB, TTzTimeReference aTimeBRef,
       
   670 								   TInt aStdOffset, TInt aWallOffset, TTimeIntervalMinutes* aMinutesDifference) const
       
   671 	{
       
   672 	TTime timeA(aTimeA), timeB(aTimeB);
       
   673 	if (aTimeARef != aTimeBRef)
       
   674 		{
       
   675 		if (aTimeARef == ETzStdTimeReference)
       
   676 			{
       
   677 			timeA -= TTimeIntervalMinutes(aStdOffset);	
       
   678 			}
       
   679 		if (aTimeARef == ETzWallTimeReference)
       
   680 			{
       
   681 			timeA -= TTimeIntervalMinutes(aWallOffset);	
       
   682 			}
       
   683 		if (aTimeBRef == ETzStdTimeReference)
       
   684 			{
       
   685 			timeB -= TTimeIntervalMinutes(aStdOffset);	
       
   686 			}
       
   687 		if (aTimeBRef == ETzWallTimeReference)
       
   688 			{
       
   689 			timeB -= TTimeIntervalMinutes(aWallOffset);	
       
   690 			}
       
   691 		}
       
   692 
       
   693 	if (aMinutesDifference)
       
   694 		{
       
   695 		timeA.MinutesFrom(timeB, *aMinutesDifference);
       
   696 		}
       
   697 
       
   698 	return (timeA<timeB) ? -1 : ((timeA>timeB) ? 1 : 0);
       
   699 	}
       
   700 
       
   701 /**
       
   702 Based on the rules in the object calculates actualised rules for particular year and adds them
       
   703 to the specified array of actualised rules (CVTzActualisedRules).
       
   704 
       
   705 @param	aActRules	- an array of actualised rules where new actualised rules are added;
       
   706 @param	aYear		- a year for which actualised rules are added.
       
   707 
       
   708 @internalComponent
       
   709 @released
       
   710 */
       
   711 void CTzRules::AddActualisedRulesL(CVTzActualisedRules& aActRules, TInt aYear) const
       
   712    	{
       
   713    	const TInt count=iRules.Count();
       
   714    	const TTzRule* trule = NULL;
       
   715 
       
   716 	const TTime KYearBegin(TDateTime(aYear, EJanuary, 0, 0, 0, 0, 0));
       
   717 	const TTime KYearEnd(TDateTime(aYear + 1, EJanuary, 0, 0, 0, 0, 0));
       
   718 
       
   719    	for (TInt i = 0; i < count; i++)
       
   720    		{
       
   721    		trule = &(iRules[i]);
       
   722    		if ( trule->RuleApplies(KYearBegin, KYearEnd))
       
   723    			{
       
   724    			TVTzActualisedRule tactRule = trule->Actualise(aYear);
       
   725    
       
   726    			// ETzStdTimeReference is not useful for VTIMEZONE or for conversions
       
   727    			if(trule->iTimeReference == ETzStdTimeReference)
       
   728    				{
       
   729 				//# Time: Time for the DST switch. Important: sometimes the time is followed by a letter. The meaning of this letter is:
       
   730 				//no letter or w: wall clock time, actual local time.
       
   731 				//s: local standard time (winter time)
       
   732 				//u or g or z: UTC time.
       
   733 				//So, if a 'DST on' time is given as '0:00s', this means a switch on 0:00 local time.
       
   734    				//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).
       
   735    				
       
   736    				//DST off time is always the lowest among the two.
       
   737 				//We do not want to use the oldlocaltimeoffset for DST Off conditions.
       
   738    				TInt standardOffset = trule->iOldLocalTimeOffset;
       
   739    				if(trule->iNewLocalTimeOffset < trule->iOldLocalTimeOffset)
       
   740    					{
       
   741    					standardOffset = trule->iNewLocalTimeOffset;
       
   742    					}
       
   743    				tactRule.iTimeOfChange -= TTimeIntervalMinutes(standardOffset);
       
   744    				tactRule.iTimeReference = ETzUtcTimeReference;
       
   745    				}
       
   746    				
       
   747   			if ( 0 >= CompareTimesWithRef(tactRule.iTimeOfChange, tactRule.iTimeReference,
       
   748   											trule->iTo.iTime, trule->iTo.iTimeReference,
       
   749   											0, trule->iOldLocalTimeOffset, NULL) )
       
   750   				{
       
   751   				// tactRule.iTimeOfChange w/ref is less or equal to trule->iTo
       
   752 
       
   753   				/*Fix for INC117764:
       
   754 				Before adding make sure that rule does not occur before the rules which have already been added.
       
   755 				For Ex-"Europe\Tirane" 
       
   756 				1) Rule Starts at 1/4/1984, Rule Ends at 30/6/1984, Old offset = 60, New Offset = 120 (Summer rule)
       
   757 				2) Rule Starts at 1/7/1984, Rule Ends at 1/7/1984, Old offset = 60, New Offset = 120 (Summer rule contd.)
       
   758 				3) Rule Starts at 1/9/1984, Rule Ends at 31/12/1995, Old offset = 60, New Offset = 60(winter rule) 
       
   759 				4) Rule Starts at 1/3/1984, Rule Ends at 31/12/9998, Old offset = 60, New Offset = 120 (Summer Rule)
       
   760 				The 4th rule should follow from 7/7/1984 onwards, otherwise if 4th rule is actualised for year 1984
       
   761 				it would look like --Rule Starts at 1/3/1984, NewOffset = 120, this will cause issues when converting time in March since summer
       
   762 				time won't start until April 1984.
       
   763 				*/
       
   764   				TBool ruleAdded = ETrue;
       
   765 				for(TInt loop = aActRules.Count()-1; loop >=0; --loop)
       
   766 					{
       
   767 					TVTzActualisedRule prevActRule = aActRules[loop];
       
   768 					TDateTime prevRdt = prevActRule.iTimeOfChange.DateTime();
       
   769 					TDateTime actRdt = tactRule.iTimeOfChange.DateTime();	
       
   770 					if(actRdt.Year() > prevRdt.Year())
       
   771 						{
       
   772 						//no covering rule for this year in previously added rules
       
   773 						//no need of looking into other year rules
       
   774 						break;						
       
   775 						}
       
   776 					if(actRdt.Year() == prevRdt.Year() &&
       
   777 					   actRdt.Month() < prevRdt.Month() &&
       
   778 					   tactRule.iNewOffset == prevActRule.iNewOffset)
       
   779 						{
       
   780 						//covering rule already exists so dont add this one
       
   781 						ruleAdded = EFalse;
       
   782 						break;
       
   783 						}	
       
   784 					}
       
   785 				if(ruleAdded)
       
   786 					{
       
   787 					aActRules.AddRuleL(tactRule);	
       
   788 					}
       
   789   				}
       
   790 			}
       
   791    		}
       
   792    	}
       
   793 
       
   794 /**
       
   795 Get actualised rules for time zone rules.
       
   796 @param aActRules Actualised rules for time zone rules.
       
   797 @publishedAll
       
   798 @released
       
   799 */
       
   800 EXPORT_C void CTzRules::GetActualisedRulesL(CVTzActualisedRules& aActRules) const
       
   801 	{
       
   802 	// Always add the initial offset because there may not have been
       
   803 	// any rules to actualise before the actualised rules range specified
       
   804 	TVTzActualisedRule tDefRule(TDateTime(iStartYear, EJanuary, 0, 0, 0, 0, 0), iInitialStdTimeOffset, ETzWallTimeReference);
       
   805 	aActRules.AddRuleL(tDefRule);
       
   806 	
       
   807 	if (iRules.Count() == 0)
       
   808 		{
       
   809 		// do nothing
       
   810 		}
       
   811 	if (iRules.Count() == 1)
       
   812 		{
       
   813 		// There is only one rule, perhaps this is an unknown timezone
       
   814 		// or a timezone that has never had DST, so just add that one rule
       
   815 		
       
   816 		TVTzActualisedRule tDefRule(TDateTime(aActRules.StartYear(), EJanuary, 0, 0, 0, 0, 0), iRules[0].iNewLocalTimeOffset, ETzWallTimeReference);
       
   817 		aActRules.AddRuleL(tDefRule);
       
   818 		}
       
   819 	else
       
   820 		{
       
   821 		// Add actualised rules for the year range spcified in aActRules
       
   822 		// also make sure that a year before this range is actualised
       
   823 		// so that the initial offset for the actualised rules range is correct
       
   824 		
       
   825 		TInt32 year(0);
       
   826 		for (year = aActRules.EndYear() ; year >= aActRules.StartYear() ; --year) 
       
   827 			{
       
   828 			AddActualisedRulesL(aActRules, year);
       
   829 			}
       
   830 		
       
   831 		// try to add an actualised rule for the previous year
       
   832 		// so that the start of the range will be correct
       
   833 		const TInt KActRulesCount(aActRules.Count());
       
   834 		AddActualisedRulesL(aActRules, year);
       
   835 		
       
   836 		if (aActRules.Count() == KActRulesCount)
       
   837 			{
       
   838 			// No rules were added for the year before the range being actualised
       
   839 			// so find the first rule that applies before this year
       
   840 			
       
   841 			TTime timeSoFar(TDateTime(iStartYear, EJanuary, 0, 0, 0, 0, 0));	
       
   842 			TTime endTime(TDateTime(year, EJanuary, 0, 0, 0, 0, 0));
       
   843 			
       
   844 			TBool found(EFalse);
       
   845 			
       
   846 			for (TInt i(iRules.Count() - 1) ; i >= 0 ; --i)
       
   847 				{
       
   848 				if (iRules[i].iTo.iTime > timeSoFar && iRules[i].iTo.iTime < endTime)
       
   849 					{
       
   850 					timeSoFar = iRules[i].iTo.iTime;
       
   851 					found = ETrue;
       
   852 					}
       
   853 				}
       
   854 			
       
   855 			if (found)
       
   856 				{
       
   857 				AddActualisedRulesL(aActRules, timeSoFar.DateTime().Year());
       
   858 				}
       
   859 			}
       
   860 		}
       
   861 	}
       
   862 
       
   863 /**
       
   864 Converts the received local time to UTC time.
       
   865 @param aTime The time to convert. On return, this contains the converted time.
       
   866 @publishedAll
       
   867 @released
       
   868 */ 
       
   869 EXPORT_C void CTzRules::ConvertToUtcL(TTime& aTime) const
       
   870 	{
       
   871 	// This check would not be necessary if we can ensure this function
       
   872 	// is never called with a null TTime
       
   873 	if (aTime == Time::NullTTime())
       
   874 		{
       
   875 		return;
       
   876 		}
       
   877 	
       
   878 	TInt offset = GetOffsetL(aTime, ETzWallTimeReference);
       
   879 	aTime -= (TTimeIntervalMinutes)(offset);	
       
   880 	}
       
   881 
       
   882 /**
       
   883 Converts the received UTC time to local time.
       
   884 @param aTime The time to convert. On return, this contains the converted time.
       
   885 @publishedAll
       
   886 @released
       
   887 */
       
   888 EXPORT_C void CTzRules::ConvertToLocalL(TTime& aTime) const
       
   889 	{
       
   890 	// This check would not be necessary if we can ensure this function
       
   891 	// is never called with a null TTime	
       
   892 	if (aTime == Time::NullTTime())
       
   893 		{
       
   894 		return;
       
   895 		}
       
   896 	
       
   897 	TInt offset = GetOffsetL(aTime, ETzUtcTimeReference);
       
   898 	aTime += (TTimeIntervalMinutes)(offset);	
       
   899 	}
       
   900 	
       
   901 /**
       
   902 Calculate the local time offset at the supplied time.
       
   903 
       
   904 @return local time offset
       
   905 @internalComponent
       
   906 @released
       
   907 */
       
   908 EXPORT_C TInt CTzRules::GetOffsetL(const TTime& aTime, TTzTimeReference aTimeRef) const
       
   909 	{
       
   910 	if (iActualisedRulesCache)
       
   911 		{
       
   912 		TTime startTime(TDateTime(iActualisedRulesCache->StartYear(), EJanuary, 0, 0, 0, 0, 0));	
       
   913 		TTime endTime(TDateTime(iActualisedRulesCache->EndYear() + 1, EJanuary, 0, 0, 0, 0, 0));
       
   914 		
       
   915 		if (aTime >= startTime && aTime <= endTime)
       
   916 			{
       
   917 			return iActualisedRulesCache->GetOffsetFromRuleL(aTime, aTimeRef);
       
   918 			}
       
   919 		}
       
   920 
       
   921 	TInt year(aTime.DateTime().Year());
       
   922 			
       
   923 	// actualise rules
       
   924 	delete iActualisedRulesCache;
       
   925 	iActualisedRulesCache = NULL;
       
   926 	iActualisedRulesCache = CVTzActualisedRules::NewL(year, year);
       
   927 	TRAPD(leaveCode,GetActualisedRulesL(*iActualisedRulesCache));
       
   928 	if(leaveCode != KErrNone)
       
   929 		{
       
   930 		delete iActualisedRulesCache;
       
   931 		iActualisedRulesCache = NULL;
       
   932 		User::LeaveIfError(leaveCode);		
       
   933 		}
       
   934 	
       
   935 	return iActualisedRulesCache->GetOffsetFromRuleL(aTime, aTimeRef);;
       
   936 	}
       
   937 
       
   938 /**
       
   939 Creates a copy of these timezone rules.
       
   940 
       
   941 @capability None
       
   942 @return A pointer to the CTzRules copy.
       
   943 @publishedAll
       
   944 @released
       
   945 */
       
   946 EXPORT_C CTzRules* CTzRules::CloneL() const
       
   947 	{
       
   948 	CTzRules* newRules = CTzRules::NewL();
       
   949 	CleanupStack::PushL(newRules);
       
   950 	
       
   951 	newRules->SetStartYear(iStartYear);
       
   952 	newRules->SetEndYear(iEndYear);
       
   953 	newRules->SetInitialStdTimeOffset(iInitialStdTimeOffset);
       
   954 	
       
   955 	TInt numRules = Count();
       
   956 	for (TInt i = 0; i < numRules; i++)
       
   957 		{
       
   958 		newRules->AddRuleL(iRules[i]);
       
   959 		}
       
   960 	
       
   961 	CleanupStack::Pop(newRules);
       
   962 	return newRules;
       
   963 	}
       
   964 
       
   965 /** Copy a time zone rule to this time zone rule.
       
   966 
       
   967 @capability None
       
   968 @param aTzRule A rule to copy from.
       
   969 @internalAll
       
   970 @released
       
   971 */
       
   972 EXPORT_C void CTzRules::CopyL(const CTzRules& aTzRule)
       
   973 	{
       
   974 	SetStartYear(aTzRule.iStartYear);
       
   975 	SetEndYear(aTzRule.iEndYear);
       
   976 	SetInitialStdTimeOffset(aTzRule.iInitialStdTimeOffset);
       
   977 	iRules.Reset();	
       
   978 	const TInt numRules = aTzRule.Count();
       
   979 	for (TInt i = 0; i < numRules; i++)
       
   980 		{
       
   981 		AddRuleL(aTzRule.iRules[i]);
       
   982 		}
       
   983 	}
       
   984 /**
       
   985 Compares two sets of timezone rules.
       
   986 
       
   987 @capability None
       
   988 @param aRules The timezone rules to compare with.
       
   989 @return ETrue if the rules are identical. EFalse if not.
       
   990 @publishedAll
       
   991 @released
       
   992 */
       
   993 EXPORT_C TBool CTzRules::IsEqualTo(const CTzRules& aRules) const
       
   994 	{
       
   995 	if (iStartYear != aRules.StartYear() ||
       
   996 		iEndYear != aRules.EndYear() ||
       
   997 		iInitialStdTimeOffset != aRules.InitialStdTimeOffset() ||
       
   998 		Count() != aRules.Count())
       
   999 		{
       
  1000 		return EFalse;
       
  1001 		}
       
  1002 
       
  1003 	const TInt KRuleCount(Count());
       
  1004 	for (TInt i = 0; i < KRuleCount; i++)
       
  1005 		{
       
  1006 		TTzRule rule1 = const_cast<CTzRules&>(*this)[i];
       
  1007 		TTzRule rule2 = const_cast<CTzRules&>(aRules)[i];
       
  1008 		
       
  1009 		if (rule1.iFrom != rule2.iFrom ||
       
  1010 			rule1.iTo != rule2.iTo ||
       
  1011 			rule1.iOldLocalTimeOffset != rule2.iOldLocalTimeOffset ||
       
  1012 			rule1.iNewLocalTimeOffset != rule2.iNewLocalTimeOffset ||
       
  1013 			rule1.iMonth != rule2.iMonth ||
       
  1014 			rule1.iDayRule != rule2.iDayRule ||
       
  1015 			rule1.iDayOfMonth != rule2.iDayOfMonth ||
       
  1016 			rule1.iDayOfWeek != rule2.iDayOfWeek ||
       
  1017 			rule1.iTimeReference != rule2.iTimeReference ||
       
  1018 			rule1.iTimeOfChange != rule2.iTimeOfChange )
       
  1019 			{
       
  1020 			return EFalse;
       
  1021 			}
       
  1022 		}
       
  1023 	return ETrue;
       
  1024 	}
       
  1025 	
       
  1026 /**
       
  1027 Converts between local (wall-clock) and UTC times.
       
  1028 
       
  1029 @return KErrNone if successful, otherwise KErrNotSupported or KErrNotFound
       
  1030 @param aRules The actualised rules to use.
       
  1031 @param aTime The time to convert, specified by aTimerRef if the time is in UTC or local time. On return, 
       
  1032        it will contain the converted time from UTC to local time or vice versa, depending on aTimerRef's value. 
       
  1033 @param aTimerRef What aTime is expressed in.
       
  1034 @publishedAll
       
  1035 @released
       
  1036 */
       
  1037 EXPORT_C TInt CTzRules::ConvertTime(CVTzActualisedRules& aRules, TTime& aTime, TTzTimeReference aTimeRef) const
       
  1038 	{
       
  1039 	TInt results = KErrNone;
       
  1040 	TInt offset = 0;
       
  1041 
       
  1042 #ifdef _DEBUG
       
  1043 	TDateTime aDateTime = aTime.DateTime();
       
  1044 #endif
       
  1045 	
       
  1046 	TRAP( results, offset = aRules.GetOffsetFromRuleL(aTime, aTimeRef));
       
  1047 	
       
  1048 	if (results == KErrNone)
       
  1049 		{
       
  1050 		switch (aTimeRef)
       
  1051 			{
       
  1052 			case ETzUtcTimeReference:
       
  1053 				aTime += TTimeIntervalMinutes(offset);
       
  1054 				break;
       
  1055 			case ETzWallTimeReference:
       
  1056 				aTime -= TTimeIntervalMinutes(offset);
       
  1057 				break;
       
  1058 			default:
       
  1059 				results = KErrNotSupported;
       
  1060 				break;
       
  1061 			}
       
  1062 		}
       
  1063 
       
  1064 	return (results);
       
  1065 	}
       
  1066 
       
  1067 //
       
  1068 // TVTzActualisedRule
       
  1069 //
       
  1070 
       
  1071 /** 
       
  1072 Constructor for an actualised rule (local time change).
       
  1073 
       
  1074 @param aTimeOfChange Time of local time change
       
  1075 @param aNewOffset New UTC offset in minutes 
       
  1076 @param aTimeReference Time reference
       
  1077 @publishedAll
       
  1078 @released
       
  1079 */
       
  1080 EXPORT_C TVTzActualisedRule::TVTzActualisedRule(TTime aTimeOfChange, TInt aNewOffset, TTzTimeReference aTimeReference) :
       
  1081 	iTimeOfChange(aTimeOfChange),
       
  1082 	iNewOffset(aNewOffset),
       
  1083 	iTimeReference(aTimeReference)
       
  1084 	{
       
  1085 	}
       
  1086 
       
  1087 
       
  1088 /** 
       
  1089 Default constructor for an actualised rule (local time change).
       
  1090 @publishedAll
       
  1091 @released
       
  1092 */
       
  1093 EXPORT_C TVTzActualisedRule::TVTzActualisedRule() :
       
  1094 	iTimeOfChange(0),
       
  1095 	iNewOffset(0),
       
  1096 	iTimeReference(ETzUtcTimeReference)
       
  1097 	{
       
  1098 	}
       
  1099 
       
  1100 /** 
       
  1101 Assignment operator for an actualised rule.
       
  1102 @param aRule Actualised rule
       
  1103 @publishedAll
       
  1104 @released
       
  1105 */
       
  1106 EXPORT_C void TVTzActualisedRule::operator=(TVTzActualisedRule aRule)
       
  1107 	{
       
  1108 	iTimeOfChange = aRule.iTimeOfChange;
       
  1109 	iNewOffset = aRule.iNewOffset;
       
  1110 	iTimeReference = aRule.iTimeReference;
       
  1111 	}
       
  1112 
       
  1113 /**
       
  1114 Order actualised rules by time of local time change.
       
  1115 @internalComponent
       
  1116 @released
       
  1117 */
       
  1118 TInt TVTzActualisedRule::Order(const TVTzActualisedRule& aLeft, const TVTzActualisedRule& aRight)
       
  1119 	{
       
  1120 	if (aLeft.iTimeOfChange < aRight.iTimeOfChange)
       
  1121 		{
       
  1122 		return -1;
       
  1123 		}
       
  1124 	if (aLeft.iTimeOfChange == aRight.iTimeOfChange)
       
  1125 		{
       
  1126 		return 0;
       
  1127 		}
       
  1128 	return 1;
       
  1129 	}
       
  1130 
       
  1131 
       
  1132 //
       
  1133 // CVTzActualisedRules
       
  1134 //
       
  1135 
       
  1136 /**
       
  1137 Factory method for CVTzActualisedRules objects.
       
  1138 Creates a new instance of CVTzActualizedRules - an array of actualised rules (TVTzActualisedRule).
       
  1139 
       
  1140 The array of rules can be populated later by invoking CTzRules::GetActualisedRulesL() method.
       
  1141 
       
  1142 Rules in the array are sorted ascending by rule's start time (TVTzActualisedRule.iTimeOfChange);
       
  1143 The very first rule in the array, if present, defines "default standard rule" for the time zone 
       
  1144 indicating the STD time offset from UTC, in effect from the start of the first year (aStartYear).
       
  1145 
       
  1146 @param aStartYear, aEndYear	- specify range of years for to which actualised rules apply.
       
  1147 @return 	A pointer to the newly created rules.
       
  1148 @panic RTz 10 if aStartYear is larger than aEndYear.
       
  1149 @publishedAll
       
  1150 @released
       
  1151 */
       
  1152 EXPORT_C CVTzActualisedRules* CVTzActualisedRules::NewL(TInt aStartYear, TInt aEndYear)
       
  1153 	{
       
  1154 	__ASSERT_ALWAYS(aStartYear <= aEndYear, RTz::Panic(RTz::EPanicInvalidArgument));  
       
  1155 
       
  1156 	CVTzActualisedRules* self = new (ELeave) CVTzActualisedRules(aStartYear, aEndYear);
       
  1157 	return self;
       
  1158 	}
       
  1159 
       
  1160 /**
       
  1161 Constructor.
       
  1162 @internalComponent
       
  1163 @released
       
  1164 */
       
  1165 CVTzActualisedRules::CVTzActualisedRules(TInt aStartYear, TInt aEndYear) :
       
  1166 	iStartYear(aStartYear),
       
  1167 	iEndYear(aEndYear),
       
  1168 	iRules(KVTzRulesGranularity)
       
  1169 	{
       
  1170 	}
       
  1171 
       
  1172 /**
       
  1173 Default constructor.
       
  1174 @internalComponent
       
  1175 @released
       
  1176 */
       
  1177 CVTzActualisedRules::CVTzActualisedRules() :
       
  1178 	iRules(KVTzRulesGranularity)
       
  1179 	{
       
  1180 	}
       
  1181 
       
  1182 /**
       
  1183 Destructor.
       
  1184 @publishedAll
       
  1185 @released
       
  1186 */
       
  1187 EXPORT_C CVTzActualisedRules::~CVTzActualisedRules()
       
  1188 	{
       
  1189 	iRules.Reset();
       
  1190 	}
       
  1191 
       
  1192 /**
       
  1193 Returns specified TVTzActualisedRule.
       
  1194 
       
  1195 @param aIndex Index of a rule
       
  1196 @return A reference to TVTzActualised rule at index aIndex.
       
  1197 @panic RTz 4 if aIndex is out of bounds.
       
  1198 @publishedAll
       
  1199 @released
       
  1200 */
       
  1201 EXPORT_C TVTzActualisedRule& CVTzActualisedRules::operator[](TInt aIndex) const
       
  1202 	{
       
  1203 	// prevent array bounds error
       
  1204 	__ASSERT_ALWAYS( (aIndex < iRules.Count() && aIndex >= 0), RTz::Panic(RTz::EPanicRulesIndexOutofRange));
       
  1205 	
       
  1206 	return const_cast<TVTzActualisedRule&>(iRules[aIndex]);
       
  1207 	}
       
  1208 
       
  1209 /** 
       
  1210 Add an actualised rule to the collection.
       
  1211 
       
  1212 @param aRule An actualised rule to be added into the collection.
       
  1213 @publishedAll
       
  1214 @released
       
  1215 */
       
  1216 EXPORT_C void CVTzActualisedRules::AddRuleL(const TVTzActualisedRule& aRule)
       
  1217 	{
       
  1218 	TLinearOrder<TVTzActualisedRule> order(TVTzActualisedRule::Order);
       
  1219 	
       
  1220 	User::LeaveIfError(iRules.InsertInOrderAllowRepeats(aRule, order));
       
  1221 	}
       
  1222 
       
  1223 /**
       
  1224 Returns number of rules currently held in array of rules.
       
  1225 
       
  1226 @return Number of rules.
       
  1227 @publishedAll
       
  1228 @released
       
  1229 */
       
  1230 EXPORT_C TInt CVTzActualisedRules::Count() const
       
  1231 	{
       
  1232 	return iRules.Count();
       
  1233 	}
       
  1234 
       
  1235 /**
       
  1236 Returns min year of the year range the CVTzActualisedRules object describes the rules for.
       
  1237 It is guaranteed that the array of rules does not contain any rules for years before that min year.
       
  1238 
       
  1239 @return 	Start year (e.g. 1998).
       
  1240 @publishedAll
       
  1241 @released
       
  1242 */
       
  1243 EXPORT_C TInt CVTzActualisedRules::StartYear() const
       
  1244 	{
       
  1245 	return iStartYear;
       
  1246 	}
       
  1247 
       
  1248 /**
       
  1249 Returns max year of the year range the CVTzActualisedRules object describes the rules for.
       
  1250 
       
  1251 @return 	End year (e.g. 2005).
       
  1252 @publishedAll
       
  1253 @released
       
  1254 */
       
  1255 EXPORT_C TInt CVTzActualisedRules::EndYear() const
       
  1256 	{
       
  1257 	return iEndYear;
       
  1258 	}
       
  1259 
       
  1260 /**
       
  1261 Tells if Daylight Savings Applies for the current time zone at the current time
       
  1262 @return EFalse if Daylight Savings does not apply (winter time) and ETrue if Daylight Savings does apply
       
  1263 @param aTime The time of interest given in UTC.
       
  1264 @panic RTz 5 if aTime is not covered by the current set of time zone rules.
       
  1265 @panic RTz 7 if one of the time zone rules uses standard time reference.
       
  1266 @publishedAll
       
  1267 @released
       
  1268 */
       
  1269 EXPORT_C TBool CVTzActualisedRules::IsDaylightSavingOn(TTime& aTime) const
       
  1270 	{
       
  1271 	const TInt count = iRules.Count();
       
  1272 
       
  1273 	// ensure that there are rules
       
  1274 	__ASSERT_ALWAYS((count > 0), RTz::Panic(RTz::EPanicTimeNotCoveredByRules));
       
  1275 
       
  1276 	// initialisation separated from declaration to avoid arm4 'unused variable warning'
       
  1277 	TDateTime dateTime;
       
  1278 	dateTime = aTime.DateTime();
       
  1279 
       
  1280 	// ensure that there are rules defined for the time in question
       
  1281 	__ASSERT_ALWAYS(dateTime.Year() >= StartYear() && dateTime.Year() <= EndYear(), 
       
  1282 					RTz::Panic(RTz::EPanicTimeNotCoveredByRules));
       
  1283 	
       
  1284 	// the illustration below is for a location in the northern hemisphere
       
  1285 	// the opposite applies to southern hemisphere locations
       
  1286 	//
       
  1287 	//          --------|--------|---------
       
  1288 	// season:  winter    summer    winter
       
  1289 	// rule:           [1]      [2]   
       
  1290 	//
       
  1291 	// the rules are sorted by iTimeOfChange.
       
  1292 	// we start searching for the applicable rule with time 0.
       
  1293 	//
       
  1294 	// general dst example from southern hemisphere:
       
  1295 	//	America/Sao_Paulo
       
  1296 	//	UTC offset (dst off): -180min (-3h)	
       
  1297 	//	UTC offset (dst on):  -120min (-2h)		
       
  1298 	//	starting dst (Nov) 4/11/2007 at 00:00:00
       
  1299 	//	utc time:  local time:   expected dst status:
       
  1300 	//	02:00       23:00        off (-180)
       
  1301 	//	02:58       23:58        off (-180)
       
  1302 	//	02:59       23:59        off (-180)
       
  1303 	//	n/a         (00:00)      n/a
       
  1304 	//	03:00       01:00        on (-120)
       
  1305 	//	03:01       01:01        on (-120)
       
  1306 	//	04:00       02:00        on (-120)
       
  1307 	//	05:00       03:00        on (-120)	
       
  1308 	//
       
  1309 	//	ending dst (Feb) 24/02/2008: 00:00:00
       
  1310 	//	utc time:  local time:   expected dst status:
       
  1311 	//	01:00       23:00        on (-120)
       
  1312 	//	01:58       23:58        on (-120)
       
  1313 	//	01:59       23:59        on (-120)
       
  1314 	//	n/a	        (00:00)      n/a
       
  1315 	//	02:00       23:00        off (-180)
       
  1316 	//	02:58       23:58        off (-180)
       
  1317 	//	02:59       23:59        off (-180)
       
  1318 	//	03:00       00:00        off (-180)
       
  1319 	//	04:00       01:00        off (-180)
       
  1320 	//	05:00       02:00        off (-180)
       
  1321 	//   
       
  1322 	TBool dstOn(EFalse);
       
  1323 	TTime lastTimeOfChange(0);
       
  1324     TInt lowestOffset = 0;
       
  1325     TBool firstMatchFound = EFalse;
       
  1326     
       
  1327     // Retrieve lowest applicable time offset.
       
  1328 	// This is used to determine if DST is on.
       
  1329 	for (TInt i = 0; i < count; ++i)
       
  1330 		{
       
  1331 		const TVTzActualisedRule& rule = iRules[i];
       
  1332 		
       
  1333 		// Only check for the same year as requested (aTime)
       
  1334 		if (rule.iTimeOfChange.DateTime().Year() == dateTime.Year())
       
  1335    		    {
       
  1336    		    if (!firstMatchFound)
       
  1337 	   		    {
       
  1338 	   		    lowestOffset = rule.iNewOffset;
       
  1339 	   		    firstMatchFound = ETrue;	
       
  1340 	   		    }
       
  1341    		    
       
  1342 			if (rule.iNewOffset < lowestOffset)
       
  1343 				{
       
  1344 				lowestOffset = rule.iNewOffset;
       
  1345 				}	
       
  1346 			}	
       
  1347 		}
       
  1348 	
       
  1349 	if (firstMatchFound) // lowest offset has been found in year of interest
       
  1350 	    {
       
  1351 	    // there are only a few actualised rules
       
  1352 	    // so simple sequential search will suffice
       
  1353 	    // Times may be expressed in utc, or local
       
  1354 	    // so we need to compare like for like
       
  1355 		for (TInt i = 0; i < count; ++i)
       
  1356 			{
       
  1357 			const TVTzActualisedRule& rule = iRules[i];
       
  1358 			TInt oldOffset = (i>0) ?  iRules[i-1].iNewOffset : rule.iNewOffset;
       
  1359  			
       
  1360 			__ASSERT_ALWAYS(rule.iTimeReference!=ETzStdTimeReference, RTz::Panic(RTz::EPanicUnsupportedTimeReference));
       
  1361 		
       
  1362 			TTime timeOfChange(rule.iTimeOfChange);
       
  1363 			
       
  1364 			// convert to utc
       
  1365 		    if (rule.iTimeReference == ETzWallTimeReference)
       
  1366 				{
       
  1367 				timeOfChange -= (TTimeIntervalMinutes)oldOffset;				
       
  1368 				}
       
  1369 
       
  1370 		#if defined(_DEBUG)
       
  1371 			// initialisation separated from declaration to avoid arm4 'unused variable warning'
       
  1372 			TDateTime dateTimeofChange;
       
  1373 			dateTimeofChange = timeOfChange.DateTime();
       
  1374 		#endif
       
  1375 
       
  1376 			if (aTime >= timeOfChange) // continue until finding the rule which applies to the current time
       
  1377 				{
       
  1378 				if (timeOfChange > lastTimeOfChange) // a double check that rules are in order
       
  1379 					{
       
  1380 					// Check to see if the lowest offset is greater than the current
       
  1381 					// offset. If it is, then this implies DST is on.
       
  1382 					if (rule.iNewOffset > lowestOffset)
       
  1383 						{
       
  1384 						dstOn = ETrue;  // daylight savings is on
       
  1385 						}
       
  1386 					else
       
  1387 						{
       
  1388 						dstOn = EFalse; // daylight savings is off
       
  1389 						}
       
  1390 					
       
  1391 					lastTimeOfChange = timeOfChange;
       
  1392 					}
       
  1393 				}
       
  1394 			else
       
  1395 				{
       
  1396 				// found the matching rule on previous run through loop
       
  1397 				break;
       
  1398 				}
       
  1399 			}
       
  1400 	    }
       
  1401 	return(dstOn);
       
  1402 	}
       
  1403 	
       
  1404 /**
       
  1405 Receives a time. Finds out which of these rules applies at the received time
       
  1406 and returns the offset in effect at the specified time.
       
  1407 
       
  1408 Leaves with KErrNotFound, if it doesn't find the rule 
       
  1409 (i.e. aTime is earlier than the very first time in CVTzActualisedRules).
       
  1410 
       
  1411 @param	aUserTime		- time of interest
       
  1412 @param	aUserTimeRef	- time reference for the aUserTime (UTC or wall-time)
       
  1413 					note: ETzStdTimeReference for aTimeRef is not supported, will 
       
  1414 					panic with RTz::EPanicUnsupportedTimeReference.
       
  1415 
       
  1416 @return	TInt		  - offset from UTC (in minutes).
       
  1417  */
       
  1418 EXPORT_C TInt CVTzActualisedRules::GetOffsetFromRuleL(const TTime& aUserTime, TTzTimeReference aUserTimeRef) const
       
  1419 	{
       
  1420 	// The first rule with iTimeOfChange <= aUserTime that is found going backwards in the array is the one that
       
  1421 	// applies at the requested aUserTime.
       
  1422 	__ASSERT_ALWAYS(aUserTimeRef!=ETzStdTimeReference, RTz::Panic(RTz::EPanicUnsupportedTimeReference));
       
  1423 
       
  1424 	// we traverse the array of rules, starting from the last one, until we find the
       
  1425 	// rule that has a start time just before aTime
       
  1426 	TBool ruleFound = EFalse;
       
  1427 	TInt resultOffset = 0;
       
  1428 	
       
  1429 	TLinearOrder<TVTzActualisedRule> linearOrder(TVTzActualisedRule::Order);
       
  1430 	TVTzActualisedRule findActualisedRule(aUserTime, 0, aUserTimeRef);
       
  1431 	TInt position;
       
  1432 	TInt error = iRules.FindInOrder(findActualisedRule, position, linearOrder);
       
  1433 	
       
  1434 	for (TInt i(Min(position, iRules.Count()-1)); i >= 0; i--)
       
  1435 		{
       
  1436 		const TVTzActualisedRule& actRule = iRules[i];
       
  1437 		TInt oldOffset = (i>0) ? iRules[i-1].iNewOffset : actRule.iNewOffset;
       
  1438 
       
  1439 		TTime rolloverTime = actRule.iTimeOfChange;
       
  1440 		TTzTimeReference rolloverTimeRef = actRule.iTimeReference;
       
  1441 
       
  1442     #if defined(_DEBUG)
       
  1443 		TDateTime dtRolloverTime = rolloverTime.DateTime();
       
  1444 		TDateTime dtUserTime     = aUserTime.DateTime();
       
  1445     #endif
       
  1446 		
       
  1447 		TTimeIntervalMinutes diffMinutes;
       
  1448 		// Find out if rolloverTime is earlier than aUserTime
       
  1449 		if (CompareTimesWithRef(rolloverTime, rolloverTimeRef, aUserTime, aUserTimeRef, oldOffset, diffMinutes) <= 0)
       
  1450 			{// rolloverTime is now earlier than aUserTime, so we are done iterating backwards
       
  1451 			//  and aUserTime is now between this iteration and the last iterated rule.
       
  1452 			//  This means we need to use the current iNewOffset for the correct offset to give aUserTime on return.
       
  1453 			resultOffset = actRule.iNewOffset;			
       
  1454 			
       
  1455             // If diffMinutes is less than difference between iNewOffset and oldOffset,              
       
  1456             // then we are potentially in the "missing" hour, which should return the  
       
  1457             // oldOffset instead of iNewOffset. 			
       
  1458     		if (aUserTimeRef == ETzWallTimeReference &&
       
  1459     		    oldOffset < actRule.iNewOffset &&
       
  1460     		    diffMinutes.Int() < (actRule.iNewOffset-oldOffset))
       
  1461 				{
       
  1462 				// the missing hour - use oldOffset instead.
       
  1463 				// see general dst example in CVTzActualisedRules::IsDaylightSavingOn
       
  1464 				// why this is necessary.
       
  1465 				resultOffset = oldOffset;
       
  1466 				}
       
  1467 			
       
  1468 			ruleFound = ETrue;
       
  1469 			break;
       
  1470 			}
       
  1471 		}
       
  1472 
       
  1473 	if (!ruleFound)
       
  1474 		{
       
  1475 		User::Leave(KErrNotFound);
       
  1476 		}
       
  1477 		
       
  1478 	return resultOffset;
       
  1479 	}
       
  1480 	
       
  1481 /**	
       
  1482 
       
  1483 Compares two times with time references (TTzTimeReference).
       
  1484 TTzTimeReference is either ETzUtcTimeReference or ETzWallTimeReference.
       
  1485 
       
  1486 If time references for both aRolloverTime and aUserTime are the same, 
       
  1487 then straight comparison is done. Otherwise aRolloverTime is converted to match
       
  1488 the time reference of aUserTime.
       
  1489 
       
  1490 @param	aRolloverTime	 - the time of change from/to Daylight Savings Time (DST)
       
  1491 @param  aTimeRefRollover - the time reference used in aRolloverTime
       
  1492 @param	aUserTime		 - the time provided by the user to compare with 
       
  1493 @param  aTimeRefUser     - the time reference used for the user time
       
  1494 @param  aOldWallOffset   - the offset that is active before aRolloverTime happens
       
  1495 
       
  1496 @return TInt		-1 if aRolloverTime is earlier than aUserTime;
       
  1497 					 0 if aRolloverTime is equal to aUserTime;
       
  1498 					 1 if aRolloverTime is later than aUserTime.	 
       
  1499  */ 
       
  1500 TInt CVTzActualisedRules::CompareTimesWithRef(	
       
  1501 		TTime aRolloverTime, TTzTimeReference aTimeRefRollover, 
       
  1502 		TTime aUserTime,     TTzTimeReference aTimeRefUser,
       
  1503 		TInt aOldWallOffset, TTimeIntervalMinutes& aDiffMinutes) const
       
  1504 	{
       
  1505 	TInt result = 0;		
       
  1506 
       
  1507 	// Always convert the Rollover time if it has not 
       
  1508 	// the same reference type as user time
       
  1509 	if ( aTimeRefRollover != aTimeRefUser)
       
  1510 		{
       
  1511 		// As they are different; if RolloverTime is of
       
  1512 		// wall time type, we need to convert it to Utc
       
  1513 		// and vice versa, to match aTimeRefUser
       
  1514 		if ( aTimeRefRollover == ETzWallTimeReference)
       
  1515 			{
       
  1516 			// Convert to utc time reference
       
  1517 			aRolloverTime -= TTimeIntervalMinutes (aOldWallOffset);
       
  1518 			}
       
  1519 		else // aTimeRefRollover is ETzUtcTimeReference
       
  1520 			{
       
  1521 			// Convert to wall time reference
       
  1522 			aRolloverTime += TTimeIntervalMinutes (aOldWallOffset);
       
  1523  			}
       
  1524 		}
       
  1525 
       
  1526 	#if defined(_DEBUG)
       
  1527 		TDateTime dtRollover = aRolloverTime.DateTime ();
       
  1528 		TDateTime dtUser     = aUserTime.DateTime ();
       
  1529 	#endif
       
  1530 		
       
  1531 	TInt err = aUserTime.MinutesFrom(aRolloverTime, aDiffMinutes);
       
  1532 	
       
  1533 	if (aRolloverTime < aUserTime)
       
  1534 		{
       
  1535 		result = -1;
       
  1536  		}
       
  1537 	else if (aRolloverTime > aUserTime)
       
  1538 		{
       
  1539 		result = 1;
       
  1540 		}
       
  1541 
       
  1542 	return result;
       
  1543 	}
       
  1544 
       
  1545 
       
  1546