1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/ossrv/genericopenlibs/openenvcore/libc/src/timefuncs.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,377 @@
1.4 +/*
1.5 +* Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
1.6 +* All rights reserved.
1.7 +* This component and the accompanying materials are made available
1.8 +* under the terms of "Eclipse Public License v1.0"
1.9 +* which accompanies this distribution, and is available
1.10 +* at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.11 +*
1.12 +* Initial Contributors:
1.13 +* Nokia Corporation - initial contribution.
1.14 +*
1.15 +* Contributors:
1.16 +*
1.17 +* Description: This is a project specific include file for building the
1.18 +* clock related functions as part of libc library.
1.19 +*
1.20 +*/
1.21 +
1.22 +
1.23 +#include <e32base.h>
1.24 +#include <e32cons.h>
1.25 +#include <tz.h>
1.26 +#include <tzconverter.h>
1.27 +#include "tzlocalizer.h"
1.28 +#include "tzlocalizationdatatypes.h"
1.29 +#include "vtzrules.h"
1.30 +#include "utf.h"
1.31 +#include "timefuncs.h"
1.32 +#include "lposix.h"
1.33 +#include "sysif.h"
1.34 +#include "libc_wsd_defs.h"
1.35 +
1.36 +// This represents the base EpochTime in microseconds,
1.37 +// which happens to be January 1, 1970 (midnight UTC/GMT),
1.38 +// not counting leap seconds. This effectively represents
1.39 +// the number of microseconds in 1970 years.
1.40 +static const TInt64 KEpochTime = 62168256000000000;
1.41 +
1.42 +
1.43 +
1.44 +#ifndef EMULATOR
1.45 +struct tm cachetm;
1.46 +time_t prevchange;
1.47 +time_t nextchange;
1.48 +#else //EMULATOR
1.49 +
1.50 +
1.51 +
1.52 +GET_GLOBAL_VAR_FROM_TLS(cachetm, struct tm)
1.53 +#define cachetm (*GET_WSD_VAR_NAME(cachetm, g)())
1.54 +GET_GLOBAL_VAR_FROM_TLS(prevchange, time_t)
1.55 +#define prevchange (*GET_WSD_VAR_NAME(prevchange, g)())
1.56 +GET_GLOBAL_VAR_FROM_TLS(nextchange, time_t)
1.57 +#define nextchange (*GET_WSD_VAR_NAME(nextchange, g)())
1.58 +#endif //EMULATOR
1.59 +
1.60 +#if !defined(__SERIES60_30__)
1.61 +TTzTimeReference FindChangeBracket(TTime& aTime ,TTime& aUTime, CVTzActualisedRules& aRule,TBool& aDstOn)
1.62 + {
1.63 + TInt cnt = aRule.Count();
1.64 + TInt lowestOffset = -1, curOffset=-1;
1.65 + TBool isInit = EFalse;
1.66 + TTime CurTime(aTime);
1.67 + TTime Previous(-1), Next(-1);
1.68 + TTzTimeReference ref(ETzWallTimeReference);
1.69 +
1.70 +//datetime to be created from the UTC time.
1.71 + TDateTime dateTime = aUTime.DateTime();
1.72 +
1.73 +// Initially set aDstOn to False
1.74 + aDstOn = EFalse;
1.75 +
1.76 +// Loop to find the lowest time offset applicable in the year.
1.77 + for(TInt idx=0; idx<cnt; idx++)
1.78 + {
1.79 + TVTzActualisedRule& Actual = aRule[idx];
1.80 + if (Actual.iTimeOfChange.DateTime().Year() == dateTime.Year())
1.81 + {
1.82 + if (!isInit)
1.83 + {
1.84 + lowestOffset = Actual.iNewOffset;
1.85 + isInit = ETrue;
1.86 + }
1.87 +
1.88 + if (isInit && Actual.iNewOffset < lowestOffset)
1.89 + {
1.90 + lowestOffset = Actual.iNewOffset;
1.91 + }
1.92 + }
1.93 + }
1.94 +// Loop to find the current offset, previous time of change and the next time of change.
1.95 + for(TInt idx=0; idx<cnt; idx++)
1.96 + {
1.97 + TVTzActualisedRule& Actual = aRule[idx];
1.98 + if(Actual.iTimeReference == ETzUtcTimeReference && CurTime != aUTime)
1.99 + {
1.100 + CurTime = aUTime;
1.101 + ref = ETzUtcTimeReference;
1.102 + }
1.103 + // Rules are arranged in increasing order of iTimeofChange
1.104 + if(CurTime >= Actual.iTimeOfChange)
1.105 + {
1.106 + Previous = Actual.iTimeOfChange;
1.107 + curOffset = Actual.iNewOffset;
1.108 + }
1.109 + else
1.110 + {
1.111 + Next = Actual.iTimeOfChange;
1.112 + break;
1.113 + }
1.114 + }
1.115 +/*
1.116 + * If the Next and Previous were not set due to some reason,
1.117 + * Set them to one year after and one year before the time passed.
1.118 + */
1.119 + if(Next == -1)
1.120 + {
1.121 + /* Next year */
1.122 + Next = CurTime + (TTimeIntervalSeconds)(365*86400);
1.123 + }
1.124 + if (Previous == -1)
1.125 + {
1.126 + /* Prev Year */
1.127 + Previous = CurTime - (TTimeIntervalSeconds)(365*86400);
1.128 + }
1.129 + aTime = Previous;
1.130 + aUTime = Next;
1.131 + if(lowestOffset != -1 && curOffset > lowestOffset)
1.132 + {
1.133 + aDstOn = ETrue;
1.134 + }
1.135 + return ref;
1.136 + }
1.137 +#endif
1.138 +
1.139 +void UpdateDstAndTznameL(RTz &aServer,CTzId& aId,struct tm* aTmStruct, TTime aTime, TTime aUTime, TDateTime aDate, TTzTimeReference aReference)
1.140 + {
1.141 +#if !defined(__SERIES60_30__)
1.142 + CTzRules* zonerules = aServer.GetTimeZoneRulesL(aId, aTime, aTime, aReference);
1.143 + CleanupStack::PushL(zonerules);
1.144 + CVTzActualisedRules* actual = CVTzActualisedRules::NewL(aDate.Year()-1, aDate.Year()+1);
1.145 + CleanupStack::PushL(actual);
1.146 + zonerules->GetActualisedRulesL(*actual);
1.147 + TTime PrevTime(aTime), NextTime(aUTime);
1.148 + TBool IsDstOn;
1.149 + /* Send local TTimes */
1.150 + if(FindChangeBracket(PrevTime, NextTime, *actual, IsDstOn)== ETzWallTimeReference)
1.151 + {
1.152 + aServer.ConvertToUniversalTime(PrevTime,aId);
1.153 + aServer.ConvertToUniversalTime(NextTime,aId);
1.154 + }
1.155 + prevchange = (PrevTime.Int64() - KEpochTime)/1000000;
1.156 + nextchange = (NextTime.Int64() - KEpochTime)/1000000;
1.157 +
1.158 + aTmStruct->tm_isdst = IsDstOn;
1.159 + CleanupStack::PopAndDestroy(actual);
1.160 + CleanupStack::PopAndDestroy(zonerules);
1.161 +#else // __SERIES60_30__ defined
1.162 + aServer;
1.163 + aTime;
1.164 + aUTime;
1.165 + aDate;
1.166 + aReference;
1.167 +#endif
1.168 +/* //This part has been commented out because of performance issue. Also this requires capability.
1.169 + if(RProcess().HasCapability(ECapabilityReadUserData,ECapabilityWriteUserData,NULL))
1.170 + {
1.171 + // tm_zone updated only in this case. Otherwise always has UTC.
1.172 + CTzLocalizer *localizer = CTzLocalizer::NewL();
1.173 + CleanupStack::PushL(localizer);
1.174 + CTzLocalizedTimeZone* timezone = localizer->GetLocalizedTimeZoneL(aId.TimeZoneNumericID());
1.175 + CleanupStack::PushL(timezone);
1.176 + TPtrC zoneNameDesc;
1.177 + if (aTmStruct->tm_isdst)
1.178 + {
1.179 + zoneNameDesc.Set(timezone->ShortDaylightName());
1.180 + }
1.181 + else
1.182 + {
1.183 + zoneNameDesc.Set(timezone->ShortStandardName());
1.184 + }
1.185 + //TODO: Value should not be hardcoded here. Get it from the struct state again.
1.186 + TPtr8 ptr((unsigned char*)tzname[0],zoneNameDesc.Size());
1.187 + CnvUtfConverter::ConvertFromUnicodeToUtf8(ptr,zoneNameDesc);
1.188 + CleanupStack::PopAndDestroy(timezone);
1.189 + CleanupStack::PopAndDestroy(localizer);
1.190 + }
1.191 +
1.192 + aTmStruct->tm_zone = tzname[0]; */
1.193 +
1.194 + aTmStruct->tm_zone = "WILDABBR";
1.195 + }
1.196 +
1.197 +void ConvertUtcToLocalTimeL(const time_t* aUTCTime, struct tm* const atmStruct)
1.198 + {
1.199 + if(!aUTCTime)
1.200 + {
1.201 + User::Leave(KErrArgument);
1.202 + }
1.203 + TTime time(KEpochTime + (*aUTCTime) * (TInt64)1000000);
1.204 + TTime Utime(time);
1.205 +
1.206 + // Cache Logic.
1.207 + TTimeIntervalSeconds UtcOffset = User::UTCOffset();
1.208 + if( cachetm.tm_gmtoff == UtcOffset.Int() && prevchange <= *aUTCTime && *aUTCTime<= nextchange)
1.209 + {
1.210 + time += UtcOffset; // Convert to local time.
1.211 + TDateTime tdt = time.DateTime();
1.212 + cachetm.tm_sec = tdt.Second();
1.213 + cachetm.tm_min = tdt.Minute();
1.214 + cachetm.tm_hour = tdt.Hour();
1.215 + cachetm.tm_mday = tdt.Day() + 1;
1.216 + cachetm.tm_mon = tdt.Month();
1.217 + cachetm.tm_year = tdt.Year() - 1900; // This is as per the tm structure format.
1.218 + cachetm.tm_wday = (time.DayNoInWeek()+1)%7; // Note: first day of the week is considered as Monday, so adding +1.
1.219 + cachetm.tm_yday = time.DayNoInYear()-1; // Note: first day of the year is considered as 1, so
1.220 + *atmStruct = cachetm;
1.221 + return;
1.222 + }
1.223 +
1.224 + TDateTime tdt = time.DateTime();
1.225 +
1.226 + //enable the cache
1.227 + TInt status = KErrNone;
1.228 + RTz& rtzServer = Backend()->TZServer(status);
1.229 + if(status != KErrNone)
1.230 + User::Leave(status);
1.231 +
1.232 + CTzConverter* ctzConverter = CTzConverter::NewL(rtzServer);
1.233 +
1.234 + CleanupStack::PushL(ctzConverter);
1.235 + if(ctzConverter->ConvertToLocalTime(time) == KErrNone)
1.236 + {
1.237 + tdt = time.DateTime();
1.238 + atmStruct->tm_sec = tdt.Second();
1.239 + atmStruct->tm_min = tdt.Minute();
1.240 + atmStruct->tm_hour = tdt.Hour();
1.241 + atmStruct->tm_mday = tdt.Day() + 1;
1.242 + atmStruct->tm_mon = tdt.Month();
1.243 + atmStruct->tm_year = tdt.Year() - 1900; // This is as per the tm structure format.
1.244 + atmStruct->tm_wday = (time.DayNoInWeek()+1)%7; // Note: first day of the week is considered as Monday, so adding +1.
1.245 + atmStruct->tm_yday = time.DayNoInYear()-1; // Note: first day of the year is considered as 1, so
1.246 +
1.247 + atmStruct->tm_gmtoff = (time.Int64() - Utime.Int64())/1000000;
1.248 +
1.249 + TInt timeZoneId = ctzConverter->CurrentTzId();
1.250 + CTzId* zoneid = CTzId::NewL((TUint)timeZoneId);
1.251 + CleanupStack::PushL(zoneid);
1.252 +
1.253 + atmStruct->tm_isdst = -1;
1.254 + UpdateDstAndTznameL(rtzServer, *zoneid, atmStruct, time, Utime, tdt, ETzWallTimeReference);
1.255 + CleanupStack::PopAndDestroy(zoneid);
1.256 + }
1.257 +
1.258 +
1.259 + CleanupStack::PopAndDestroy(1);
1.260 + cachetm = *atmStruct;
1.261 + }
1.262 +
1.263 +void ConvertLocalToUtcTimeL(time_t* aUTCTime, struct tm* const aTmStruct)
1.264 + {
1.265 + 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 )
1.266 + {
1.267 + User::Leave(KErrArgument);
1.268 + }
1.269 +
1.270 + TDateTime tdt(aTmStruct->tm_year + 1900, (TMonth)aTmStruct->tm_mon, aTmStruct->tm_mday-1,
1.271 + aTmStruct->tm_hour, aTmStruct->tm_min, aTmStruct->tm_sec, 0);
1.272 + TTime time(tdt);
1.273 + TTime oldTime(time);
1.274 +
1.275 +// Cache Logic
1.276 + TTimeIntervalSeconds UtcOffset = User::UTCOffset();
1.277 + if(cachetm.tm_gmtoff == UtcOffset.Int() && cachetm.tm_year == aTmStruct->tm_year && cachetm.tm_mon == aTmStruct->tm_mon && cachetm.tm_mday == aTmStruct->tm_mday)
1.278 + {
1.279 + aTmStruct->tm_gmtoff = cachetm.tm_gmtoff;
1.280 + aTmStruct->tm_isdst = cachetm.tm_isdst;
1.281 + aTmStruct->tm_zone = cachetm.tm_zone;
1.282 + aTmStruct->tm_wday = (time.DayNoInWeek()+1)%7; // Note: first day of the week is considered as Monday, so adding +1.
1.283 + aTmStruct->tm_yday = time.DayNoInYear()-1; // Note: first day of the year is considered as 1, so
1.284 + time -= UtcOffset; // Converting to UTC time.
1.285 + TInt64 utcTimeMicroSec = time.Int64();
1.286 + TInt64 epochRefTime = utcTimeMicroSec - KEpochTime;
1.287 + (*aUTCTime) = (TInt) (epochRefTime / 1000000);
1.288 + return;
1.289 + }
1.290 +
1.291 + TInt status = KErrNone;
1.292 + RTz& rtzServer = Backend()->TZServer(status);
1.293 + if(status != KErrNone)
1.294 + User::Leave(status);
1.295 +
1.296 + CTzConverter* ctzConverter = CTzConverter::NewL(rtzServer);
1.297 + CleanupStack::PushL(ctzConverter);
1.298 + /* Following fields are updated if successful:
1.299 + * tm_wday
1.300 + * tm_yday
1.301 + * tm_isdst
1.302 + * tm_gmtoffset
1.303 + * tm_zone ( Conditional on capabilities available)
1.304 + */
1.305 + if(ctzConverter->ConvertToUniversalTime(time) == KErrNone)
1.306 + {
1.307 + //conversion successful
1.308 + TInt64 utcTimeMicroSec = time.Int64();
1.309 + TInt64 epochRefTime = utcTimeMicroSec - KEpochTime;
1.310 + (*aUTCTime) = (TInt) (epochRefTime / 1000000);
1.311 + aTmStruct->tm_wday = (oldTime.DayNoInWeek()+1)%7; // Note: first day of the week is considered as Monday, so adding +1.
1.312 + aTmStruct->tm_yday = oldTime.DayNoInYear()-1; // Note: first day of the year is considered as 1, so
1.313 + aTmStruct->tm_gmtoff = (oldTime.Int64() - utcTimeMicroSec)/1000000;
1.314 +
1.315 + TInt timeZoneId = ctzConverter->CurrentTzId();
1.316 + CTzId* zoneid = CTzId::NewL((TUint)timeZoneId);
1.317 + CleanupStack::PushL(zoneid);
1.318 +
1.319 + aTmStruct->tm_isdst = -1;
1.320 + UpdateDstAndTznameL(rtzServer, *zoneid, aTmStruct, oldTime, time, tdt, ETzUtcTimeReference);
1.321 + CleanupStack::PopAndDestroy(zoneid);
1.322 + }
1.323 + cachetm = *aTmStruct;
1.324 + CleanupStack::PopAndDestroy(1);
1.325 + }
1.326 +
1.327 +// converts a UTC time to local time, or, local time to UTC time.
1.328 +TInt ConvertTime(const TInt atimeConverFlg, time_t *aUTCTime, struct tm *const atmStruct)
1.329 + {
1.330 + TInt err = 0;
1.331 +
1.332 + CActiveScheduler* oldAs = CActiveScheduler::Current();
1.333 + RHeap* oldHeap = User::SwitchHeap(Backend()->Heap());
1.334 + CActiveScheduler* newAs = new CActiveScheduler();
1.335 + User::SwitchHeap(oldHeap);
1.336 + if(!newAs)
1.337 + {
1.338 + errno = ENOMEM;
1.339 + return ENOMEM;
1.340 + }
1.341 + if(oldAs)
1.342 + {
1.343 + (void)CActiveScheduler::Replace(newAs);
1.344 + }
1.345 + else
1.346 + {
1.347 + CActiveScheduler::Install(newAs);
1.348 + }
1.349 +
1.350 + oldHeap = User::SwitchHeap(Backend()->Heap());
1.351 + // Cleanup stack needed
1.352 + CTrapCleanup* cleanup=CTrapCleanup::New();
1.353 +
1.354 + if (cleanup)
1.355 + {
1.356 + if(EUtcToLocal == atimeConverFlg)
1.357 + {
1.358 + TRAP(err, ConvertUtcToLocalTimeL(aUTCTime, atmStruct));
1.359 + }
1.360 + else if(ELocalToUtc == atimeConverFlg)
1.361 + {
1.362 + TRAP(err, ConvertLocalToUtcTimeL(aUTCTime, atmStruct));
1.363 + }
1.364 + delete cleanup;
1.365 + }
1.366 + else
1.367 + {
1.368 + err = ENOMEM;
1.369 + }
1.370 + if(oldAs)
1.371 + {
1.372 + (void)CActiveScheduler::Replace(oldAs);
1.373 + }
1.374 +
1.375 +
1.376 + delete newAs;
1.377 + User::SwitchHeap(oldHeap);
1.378 + return MapError(err,errno);
1.379 + }
1.380 +