Update contrib.
2 * Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
4 * This component and the accompanying materials are made available
5 * under the terms of "Eclipse Public License v1.0"
6 * which accompanies this distribution, and is available
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
14 * Description: This is a project specific include file for building the
15 * clock related functions as part of libc library.
23 #include <tzconverter.h>
24 #include "tzlocalizer.h"
25 #include "tzlocalizationdatatypes.h"
28 #include "timefuncs.h"
31 #include "libc_wsd_defs.h"
33 // This represents the base EpochTime in microseconds,
34 // which happens to be January 1, 1970 (midnight UTC/GMT),
35 // not counting leap seconds. This effectively represents
36 // the number of microseconds in 1970 years.
37 static const TInt64 KEpochTime = 62168256000000000;
49 GET_GLOBAL_VAR_FROM_TLS(cachetm, struct tm)
50 #define cachetm (*GET_WSD_VAR_NAME(cachetm, g)())
51 GET_GLOBAL_VAR_FROM_TLS(prevchange, time_t)
52 #define prevchange (*GET_WSD_VAR_NAME(prevchange, g)())
53 GET_GLOBAL_VAR_FROM_TLS(nextchange, time_t)
54 #define nextchange (*GET_WSD_VAR_NAME(nextchange, g)())
57 #if !defined(__SERIES60_30__)
58 TTzTimeReference FindChangeBracket(TTime& aTime ,TTime& aUTime, CVTzActualisedRules& aRule,TBool& aDstOn)
60 TInt cnt = aRule.Count();
61 TInt lowestOffset = -1, curOffset=-1;
62 TBool isInit = EFalse;
64 TTime Previous(-1), Next(-1);
65 TTzTimeReference ref(ETzWallTimeReference);
67 //datetime to be created from the UTC time.
68 TDateTime dateTime = aUTime.DateTime();
70 // Initially set aDstOn to False
73 // Loop to find the lowest time offset applicable in the year.
74 for(TInt idx=0; idx<cnt; idx++)
76 TVTzActualisedRule& Actual = aRule[idx];
77 if (Actual.iTimeOfChange.DateTime().Year() == dateTime.Year())
81 lowestOffset = Actual.iNewOffset;
85 if (isInit && Actual.iNewOffset < lowestOffset)
87 lowestOffset = Actual.iNewOffset;
91 // Loop to find the current offset, previous time of change and the next time of change.
92 for(TInt idx=0; idx<cnt; idx++)
94 TVTzActualisedRule& Actual = aRule[idx];
95 if(Actual.iTimeReference == ETzUtcTimeReference && CurTime != aUTime)
98 ref = ETzUtcTimeReference;
100 // Rules are arranged in increasing order of iTimeofChange
101 if(CurTime >= Actual.iTimeOfChange)
103 Previous = Actual.iTimeOfChange;
104 curOffset = Actual.iNewOffset;
108 Next = Actual.iTimeOfChange;
113 * If the Next and Previous were not set due to some reason,
114 * Set them to one year after and one year before the time passed.
119 Next = CurTime + (TTimeIntervalSeconds)(365*86400);
124 Previous = CurTime - (TTimeIntervalSeconds)(365*86400);
128 if(lowestOffset != -1 && curOffset > lowestOffset)
136 void UpdateDstAndTznameL(RTz &aServer,CTzId& aId,struct tm* aTmStruct, TTime aTime, TTime aUTime, TDateTime aDate, TTzTimeReference aReference)
138 #if !defined(__SERIES60_30__)
139 CTzRules* zonerules = aServer.GetTimeZoneRulesL(aId, aTime, aTime, aReference);
140 CleanupStack::PushL(zonerules);
141 CVTzActualisedRules* actual = CVTzActualisedRules::NewL(aDate.Year()-1, aDate.Year()+1);
142 CleanupStack::PushL(actual);
143 zonerules->GetActualisedRulesL(*actual);
144 TTime PrevTime(aTime), NextTime(aUTime);
146 /* Send local TTimes */
147 if(FindChangeBracket(PrevTime, NextTime, *actual, IsDstOn)== ETzWallTimeReference)
149 aServer.ConvertToUniversalTime(PrevTime,aId);
150 aServer.ConvertToUniversalTime(NextTime,aId);
152 prevchange = (PrevTime.Int64() - KEpochTime)/1000000;
153 nextchange = (NextTime.Int64() - KEpochTime)/1000000;
155 aTmStruct->tm_isdst = IsDstOn;
156 CleanupStack::PopAndDestroy(actual);
157 CleanupStack::PopAndDestroy(zonerules);
158 #else // __SERIES60_30__ defined
165 /* //This part has been commented out because of performance issue. Also this requires capability.
166 if(RProcess().HasCapability(ECapabilityReadUserData,ECapabilityWriteUserData,NULL))
168 // tm_zone updated only in this case. Otherwise always has UTC.
169 CTzLocalizer *localizer = CTzLocalizer::NewL();
170 CleanupStack::PushL(localizer);
171 CTzLocalizedTimeZone* timezone = localizer->GetLocalizedTimeZoneL(aId.TimeZoneNumericID());
172 CleanupStack::PushL(timezone);
174 if (aTmStruct->tm_isdst)
176 zoneNameDesc.Set(timezone->ShortDaylightName());
180 zoneNameDesc.Set(timezone->ShortStandardName());
182 //TODO: Value should not be hardcoded here. Get it from the struct state again.
183 TPtr8 ptr((unsigned char*)tzname[0],zoneNameDesc.Size());
184 CnvUtfConverter::ConvertFromUnicodeToUtf8(ptr,zoneNameDesc);
185 CleanupStack::PopAndDestroy(timezone);
186 CleanupStack::PopAndDestroy(localizer);
189 aTmStruct->tm_zone = tzname[0]; */
191 aTmStruct->tm_zone = "WILDABBR";
194 void ConvertUtcToLocalTimeL(const time_t* aUTCTime, struct tm* const atmStruct)
198 User::Leave(KErrArgument);
200 TTime time(KEpochTime + (*aUTCTime) * (TInt64)1000000);
204 TTimeIntervalSeconds UtcOffset = User::UTCOffset();
205 if( cachetm.tm_gmtoff == UtcOffset.Int() && prevchange <= *aUTCTime && *aUTCTime<= nextchange)
207 time += UtcOffset; // Convert to local time.
208 TDateTime tdt = time.DateTime();
209 cachetm.tm_sec = tdt.Second();
210 cachetm.tm_min = tdt.Minute();
211 cachetm.tm_hour = tdt.Hour();
212 cachetm.tm_mday = tdt.Day() + 1;
213 cachetm.tm_mon = tdt.Month();
214 cachetm.tm_year = tdt.Year() - 1900; // This is as per the tm structure format.
215 cachetm.tm_wday = (time.DayNoInWeek()+1)%7; // Note: first day of the week is considered as Monday, so adding +1.
216 cachetm.tm_yday = time.DayNoInYear()-1; // Note: first day of the year is considered as 1, so
217 *atmStruct = cachetm;
221 TDateTime tdt = time.DateTime();
224 TInt status = KErrNone;
225 RTz& rtzServer = Backend()->TZServer(status);
226 if(status != KErrNone)
229 CTzConverter* ctzConverter = CTzConverter::NewL(rtzServer);
231 CleanupStack::PushL(ctzConverter);
232 if(ctzConverter->ConvertToLocalTime(time) == KErrNone)
234 tdt = time.DateTime();
235 atmStruct->tm_sec = tdt.Second();
236 atmStruct->tm_min = tdt.Minute();
237 atmStruct->tm_hour = tdt.Hour();
238 atmStruct->tm_mday = tdt.Day() + 1;
239 atmStruct->tm_mon = tdt.Month();
240 atmStruct->tm_year = tdt.Year() - 1900; // This is as per the tm structure format.
241 atmStruct->tm_wday = (time.DayNoInWeek()+1)%7; // Note: first day of the week is considered as Monday, so adding +1.
242 atmStruct->tm_yday = time.DayNoInYear()-1; // Note: first day of the year is considered as 1, so
244 atmStruct->tm_gmtoff = (time.Int64() - Utime.Int64())/1000000;
246 TInt timeZoneId = ctzConverter->CurrentTzId();
247 CTzId* zoneid = CTzId::NewL((TUint)timeZoneId);
248 CleanupStack::PushL(zoneid);
250 atmStruct->tm_isdst = -1;
251 UpdateDstAndTznameL(rtzServer, *zoneid, atmStruct, time, Utime, tdt, ETzWallTimeReference);
252 CleanupStack::PopAndDestroy(zoneid);
256 CleanupStack::PopAndDestroy(1);
257 cachetm = *atmStruct;
260 void ConvertLocalToUtcTimeL(time_t* aUTCTime, struct tm* const aTmStruct)
262 if(!aTmStruct || aTmStruct->tm_year < 0 || aTmStruct->tm_mon < 0 || aTmStruct->tm_mday < 1 || aTmStruct->tm_hour < 0 || aTmStruct->tm_min < 0 || aTmStruct->tm_sec < 0 )
264 User::Leave(KErrArgument);
267 TDateTime tdt(aTmStruct->tm_year + 1900, (TMonth)aTmStruct->tm_mon, aTmStruct->tm_mday-1,
268 aTmStruct->tm_hour, aTmStruct->tm_min, aTmStruct->tm_sec, 0);
273 TTimeIntervalSeconds UtcOffset = User::UTCOffset();
274 if(cachetm.tm_gmtoff == UtcOffset.Int() && cachetm.tm_year == aTmStruct->tm_year && cachetm.tm_mon == aTmStruct->tm_mon && cachetm.tm_mday == aTmStruct->tm_mday)
276 aTmStruct->tm_gmtoff = cachetm.tm_gmtoff;
277 aTmStruct->tm_isdst = cachetm.tm_isdst;
278 aTmStruct->tm_zone = cachetm.tm_zone;
279 aTmStruct->tm_wday = (time.DayNoInWeek()+1)%7; // Note: first day of the week is considered as Monday, so adding +1.
280 aTmStruct->tm_yday = time.DayNoInYear()-1; // Note: first day of the year is considered as 1, so
281 time -= UtcOffset; // Converting to UTC time.
282 TInt64 utcTimeMicroSec = time.Int64();
283 TInt64 epochRefTime = utcTimeMicroSec - KEpochTime;
284 (*aUTCTime) = (TInt) (epochRefTime / 1000000);
288 TInt status = KErrNone;
289 RTz& rtzServer = Backend()->TZServer(status);
290 if(status != KErrNone)
293 CTzConverter* ctzConverter = CTzConverter::NewL(rtzServer);
294 CleanupStack::PushL(ctzConverter);
295 /* Following fields are updated if successful:
300 * tm_zone ( Conditional on capabilities available)
302 if(ctzConverter->ConvertToUniversalTime(time) == KErrNone)
304 //conversion successful
305 TInt64 utcTimeMicroSec = time.Int64();
306 TInt64 epochRefTime = utcTimeMicroSec - KEpochTime;
307 (*aUTCTime) = (TInt) (epochRefTime / 1000000);
308 aTmStruct->tm_wday = (oldTime.DayNoInWeek()+1)%7; // Note: first day of the week is considered as Monday, so adding +1.
309 aTmStruct->tm_yday = oldTime.DayNoInYear()-1; // Note: first day of the year is considered as 1, so
310 aTmStruct->tm_gmtoff = (oldTime.Int64() - utcTimeMicroSec)/1000000;
312 TInt timeZoneId = ctzConverter->CurrentTzId();
313 CTzId* zoneid = CTzId::NewL((TUint)timeZoneId);
314 CleanupStack::PushL(zoneid);
316 aTmStruct->tm_isdst = -1;
317 UpdateDstAndTznameL(rtzServer, *zoneid, aTmStruct, oldTime, time, tdt, ETzUtcTimeReference);
318 CleanupStack::PopAndDestroy(zoneid);
320 cachetm = *aTmStruct;
321 CleanupStack::PopAndDestroy(1);
324 // converts a UTC time to local time, or, local time to UTC time.
325 TInt ConvertTime(const TInt atimeConverFlg, time_t *aUTCTime, struct tm *const atmStruct)
329 CActiveScheduler* oldAs = CActiveScheduler::Current();
330 RHeap* oldHeap = User::SwitchHeap(Backend()->Heap());
331 CActiveScheduler* newAs = new CActiveScheduler();
332 User::SwitchHeap(oldHeap);
340 (void)CActiveScheduler::Replace(newAs);
344 CActiveScheduler::Install(newAs);
347 oldHeap = User::SwitchHeap(Backend()->Heap());
348 // Cleanup stack needed
349 CTrapCleanup* cleanup=CTrapCleanup::New();
353 if(EUtcToLocal == atimeConverFlg)
355 TRAP(err, ConvertUtcToLocalTimeL(aUTCTime, atmStruct));
357 else if(ELocalToUtc == atimeConverFlg)
359 TRAP(err, ConvertLocalToUtcTimeL(aUTCTime, atmStruct));
369 (void)CActiveScheduler::Replace(oldAs);
374 User::SwitchHeap(oldHeap);
375 return MapError(err,errno);