|
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 |