os/ossrv/genericopenlibs/openenvcore/libc/src/timefuncs.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /*
     2 * Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
     3 * All rights reserved.
     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".
     8 *
     9 * Initial Contributors:
    10 * Nokia Corporation - initial contribution.
    11 *
    12 * Contributors:
    13 *
    14 * Description:  This is a project specific include file for building the 
    15 *                clock related functions as part of libc library.
    16 *
    17 */
    18 
    19 
    20 #include <e32base.h>
    21 #include <e32cons.h>
    22 #include <tz.h>
    23 #include <tzconverter.h>
    24 #include "tzlocalizer.h" 
    25 #include "tzlocalizationdatatypes.h"
    26 #include "vtzrules.h"
    27 #include "utf.h" 
    28 #include "timefuncs.h"
    29 #include "lposix.h"
    30 #include "sysif.h"
    31 #include "libc_wsd_defs.h"
    32 
    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;
    38 
    39 
    40 
    41 #ifndef EMULATOR
    42 struct tm cachetm;
    43 time_t prevchange;
    44 time_t nextchange;
    45 #else //EMULATOR
    46 
    47 
    48 
    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)())
    55 #endif //EMULATOR
    56 
    57 #if !defined(__SERIES60_30__) 
    58 TTzTimeReference FindChangeBracket(TTime& aTime ,TTime& aUTime, CVTzActualisedRules& aRule,TBool& aDstOn)
    59     {
    60     TInt cnt = aRule.Count();
    61     TInt lowestOffset = -1, curOffset=-1;
    62     TBool isInit = EFalse;
    63     TTime CurTime(aTime);
    64     TTime Previous(-1), Next(-1);
    65     TTzTimeReference ref(ETzWallTimeReference);
    66     
    67 //datetime to be created from the UTC time.    
    68     TDateTime dateTime = aUTime.DateTime();
    69     
    70 // Initially set aDstOn to False
    71     aDstOn = EFalse;
    72     
    73 // Loop to find the lowest time offset applicable in the year.    
    74     for(TInt idx=0; idx<cnt; idx++)
    75         {
    76         TVTzActualisedRule& Actual = aRule[idx];  
    77         if (Actual.iTimeOfChange.DateTime().Year() == dateTime.Year())
    78             {
    79             if (!isInit)
    80                 {
    81                 lowestOffset = Actual.iNewOffset;
    82                 isInit = ETrue;    
    83                 }
    84 
    85             if (isInit && Actual.iNewOffset < lowestOffset)
    86                 {
    87                 lowestOffset = Actual.iNewOffset;
    88                 }   
    89             }
    90         }
    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++)
    93         {
    94         TVTzActualisedRule& Actual = aRule[idx];
    95         if(Actual.iTimeReference == ETzUtcTimeReference && CurTime != aUTime)
    96             {
    97             CurTime = aUTime;
    98             ref = ETzUtcTimeReference;
    99             }
   100         //  Rules are arranged in increasing order of iTimeofChange
   101         if(CurTime >= Actual.iTimeOfChange)
   102             {
   103             Previous = Actual.iTimeOfChange;
   104             curOffset = Actual.iNewOffset;
   105             }
   106         else
   107             {
   108             Next = Actual.iTimeOfChange;
   109             break;
   110             }
   111        }
   112 /*
   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.
   115  */     
   116     if(Next == -1)
   117         {
   118         /* Next year */
   119         Next = CurTime + (TTimeIntervalSeconds)(365*86400);
   120         }
   121     if (Previous == -1)
   122         {
   123         /* Prev Year */
   124         Previous = CurTime - (TTimeIntervalSeconds)(365*86400);
   125         }
   126     aTime = Previous;
   127     aUTime = Next;
   128     if(lowestOffset != -1 && curOffset > lowestOffset)
   129         {
   130         aDstOn = ETrue;
   131         }
   132     return ref;
   133     }
   134 #endif
   135 
   136 void UpdateDstAndTznameL(RTz &aServer,CTzId& aId,struct tm* aTmStruct, TTime aTime, TTime aUTime, TDateTime aDate, TTzTimeReference aReference)
   137     {
   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);
   145     TBool IsDstOn;
   146     /* Send local TTimes */
   147     if(FindChangeBracket(PrevTime, NextTime, *actual, IsDstOn)== ETzWallTimeReference)
   148         {
   149         aServer.ConvertToUniversalTime(PrevTime,aId);
   150         aServer.ConvertToUniversalTime(NextTime,aId);
   151         }
   152     prevchange = (PrevTime.Int64() - KEpochTime)/1000000;
   153     nextchange = (NextTime.Int64() - KEpochTime)/1000000;
   154 
   155     aTmStruct->tm_isdst = IsDstOn;
   156     CleanupStack::PopAndDestroy(actual);
   157     CleanupStack::PopAndDestroy(zonerules);
   158 #else // __SERIES60_30__ defined
   159     aServer;
   160     aTime;
   161     aUTime;
   162     aDate;
   163     aReference;
   164 #endif
   165 /*  //This part has been commented out because of performance issue. Also this requires capability.
   166     if(RProcess().HasCapability(ECapabilityReadUserData,ECapabilityWriteUserData,NULL))
   167         {
   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);
   173         TPtrC zoneNameDesc;
   174         if (aTmStruct->tm_isdst)
   175             {
   176             zoneNameDesc.Set(timezone->ShortDaylightName());
   177             }
   178         else            
   179             {
   180             zoneNameDesc.Set(timezone->ShortStandardName());
   181             }
   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);
   187         } 
   188     
   189     aTmStruct->tm_zone = tzname[0]; */
   190     
   191     aTmStruct->tm_zone = "WILDABBR";
   192     }  
   193 
   194 void ConvertUtcToLocalTimeL(const time_t* aUTCTime, struct tm* const atmStruct)
   195     {
   196     if(!aUTCTime)
   197         {
   198         User::Leave(KErrArgument);
   199         }
   200     TTime   time(KEpochTime + (*aUTCTime) * (TInt64)1000000);
   201     TTime   Utime(time);
   202 
   203     // Cache Logic.
   204     TTimeIntervalSeconds UtcOffset = User::UTCOffset();
   205     if( cachetm.tm_gmtoff == UtcOffset.Int() && prevchange <= *aUTCTime && *aUTCTime<= nextchange)
   206         {
   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;
   218         return;
   219         }
   220 
   221     TDateTime tdt = time.DateTime();
   222     
   223     //enable the cache
   224 	TInt status = KErrNone;
   225 	RTz& rtzServer = Backend()->TZServer(status);
   226 	if(status != KErrNone)
   227 		User::Leave(status);
   228 
   229     CTzConverter* ctzConverter = CTzConverter::NewL(rtzServer);
   230     
   231     CleanupStack::PushL(ctzConverter);
   232     if(ctzConverter->ConvertToLocalTime(time) == KErrNone)      
   233         {
   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 
   243 
   244         atmStruct->tm_gmtoff = (time.Int64() - Utime.Int64())/1000000;
   245         
   246         TInt timeZoneId = ctzConverter->CurrentTzId();
   247         CTzId* zoneid = CTzId::NewL((TUint)timeZoneId);
   248         CleanupStack::PushL(zoneid);
   249         
   250         atmStruct->tm_isdst  = -1;
   251         UpdateDstAndTznameL(rtzServer, *zoneid, atmStruct, time, Utime, tdt, ETzWallTimeReference);
   252         CleanupStack::PopAndDestroy(zoneid);
   253         }   
   254     
   255 
   256     CleanupStack::PopAndDestroy(1);
   257     cachetm = *atmStruct;
   258     }
   259 
   260 void ConvertLocalToUtcTimeL(time_t* aUTCTime, struct tm* const aTmStruct)
   261     {
   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 )
   263         {
   264         User::Leave(KErrArgument);
   265         }
   266 
   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);
   269     TTime   time(tdt);
   270     TTime   oldTime(time);
   271 
   272 //  Cache Logic 
   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)
   275         {
   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);
   285         return;
   286         }
   287 
   288 	TInt status = KErrNone;
   289 	RTz& rtzServer = Backend()->TZServer(status);
   290 	if(status != KErrNone)
   291 		User::Leave(status);
   292 
   293     CTzConverter* ctzConverter = CTzConverter::NewL(rtzServer);      
   294     CleanupStack::PushL(ctzConverter);
   295  /* Following fields are updated if successful:
   296   * tm_wday
   297   * tm_yday
   298   * tm_isdst
   299   * tm_gmtoffset
   300   * tm_zone ( Conditional on capabilities available)
   301   */
   302     if(ctzConverter->ConvertToUniversalTime(time) == KErrNone)
   303         {
   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;
   311         
   312         TInt timeZoneId = ctzConverter->CurrentTzId();
   313         CTzId* zoneid = CTzId::NewL((TUint)timeZoneId);
   314         CleanupStack::PushL(zoneid);
   315 
   316         aTmStruct->tm_isdst  = -1;
   317         UpdateDstAndTznameL(rtzServer, *zoneid, aTmStruct, oldTime, time, tdt, ETzUtcTimeReference);
   318         CleanupStack::PopAndDestroy(zoneid);
   319         }
   320     cachetm = *aTmStruct;
   321     CleanupStack::PopAndDestroy(1);
   322     }
   323 
   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)
   326     {
   327     TInt err = 0;
   328 
   329     CActiveScheduler* oldAs = CActiveScheduler::Current();
   330     RHeap* oldHeap = User::SwitchHeap(Backend()->Heap());
   331     CActiveScheduler* newAs = new CActiveScheduler();
   332     User::SwitchHeap(oldHeap);
   333     if(!newAs)
   334         {
   335         errno = ENOMEM;
   336         return ENOMEM;
   337         }
   338     if(oldAs)
   339         {
   340         (void)CActiveScheduler::Replace(newAs);
   341         }
   342     else
   343         {
   344         CActiveScheduler::Install(newAs);
   345         }
   346     
   347     oldHeap = User::SwitchHeap(Backend()->Heap());
   348     // Cleanup stack needed
   349     CTrapCleanup* cleanup=CTrapCleanup::New();
   350 
   351     if (cleanup)
   352         {
   353         if(EUtcToLocal == atimeConverFlg)
   354             {
   355             TRAP(err, ConvertUtcToLocalTimeL(aUTCTime, atmStruct));
   356             }
   357         else if(ELocalToUtc == atimeConverFlg)
   358             {
   359             TRAP(err, ConvertLocalToUtcTimeL(aUTCTime, atmStruct));
   360             }
   361         delete cleanup;
   362         }
   363     else
   364         {
   365         err = ENOMEM;
   366         }
   367     if(oldAs)
   368         {
   369         (void)CActiveScheduler::Replace(oldAs);
   370         }
   371 
   372 
   373     delete newAs;
   374     User::SwitchHeap(oldHeap);
   375     return MapError(err,errno);
   376     }
   377