From 7bc18035816a2eac15dfac4d987eb9bf43f90ef6 Mon Sep 17 00:00:00 2001
From: Janne Koskinen <janne.p.koskinen@digia.com>
Date: Mon, 28 Dec 2009 13:47:46 +0200
Subject: Daylight savings time for Symbian take 2

Second try to make this work for all S60 platforms
---
 src/corelib/corelib.pro                |  2 ++
 src/corelib/tools/qdatetime.cpp        | 60 +++++++++++++++++++++-------------
 tests/auto/qdatetime/tst_qdatetime.cpp |  7 ++++
 3 files changed, 46 insertions(+), 23 deletions(-)

diff --git a/src/corelib/corelib.pro b/src/corelib/corelib.pro
index 9a15bf1..7f33791 100644
--- a/src/corelib/corelib.pro
+++ b/src/corelib/corelib.pro
@@ -35,4 +35,6 @@ symbian: {
     # Workaroud for problems with paging this dll
     MMP_RULES -= PAGED
     MMP_RULES *= UNPAGED
+    # Timezone server
+    LIBS += -ltzclient
 }
diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp
index db6435e..240f0cf 100644
--- a/src/corelib/tools/qdatetime.cpp
+++ b/src/corelib/tools/qdatetime.cpp
@@ -75,6 +75,7 @@
 
 #if defined(Q_OS_SYMBIAN)
 #include <e32std.h>
+#include <tz.h>
 #endif
 
 QT_BEGIN_NAMESPACE
@@ -3721,23 +3722,32 @@ static QDateTimePrivate::Spec utcToLocal(QDate &date, QTime &time)
 #elif defined(Q_OS_SYMBIAN)
     // months and days are zero index based
     _LIT(KUnixEpoch, "19700000:000000.000000");
-    TTimeIntervalSeconds utcOffset = User::UTCOffset();
     TTimeIntervalSeconds tTimeIntervalSecsSince1Jan1970UTC(secsSince1Jan1970UTC);
     TTime epochTTime;
     TInt err = epochTTime.Set(KUnixEpoch);
     tm res;
     if(err == KErrNone) {
         TTime utcTTime = epochTTime + tTimeIntervalSecsSince1Jan1970UTC;
-        utcTTime = utcTTime + utcOffset;
-        TDateTime utcDateTime = utcTTime.DateTime();
-        res.tm_sec = utcDateTime.Second();
-        res.tm_min = utcDateTime.Minute();
-        res.tm_hour = utcDateTime.Hour();
-        res.tm_mday = utcDateTime.Day() + 1; // non-zero based index for tm struct
-        res.tm_mon = utcDateTime.Month();
-        res.tm_year = utcDateTime.Year() - 1900;
-        res.tm_isdst = 0;
-        brokenDown = &res;
+        TRAP(err,
+            RTz tz;
+            User::LeaveIfError(tz.Connect());
+            CleanupClosePushL(tz);
+            res.tm_isdst = tz.IsDaylightSavingOnL(*tz.GetTimeZoneIdL(),utcTTime);
+            User::LeaveIfError(tz.ConvertToLocalTime(utcTTime));
+            CleanupStack::PopAndDestroy(&tz));
+        if (KErrNone == err) {
+            TDateTime localDateTime = utcTTime.DateTime();
+            res.tm_sec = localDateTime.Second();
+            res.tm_min = localDateTime.Minute();
+            res.tm_hour = localDateTime.Hour();
+            res.tm_mday = localDateTime.Day() + 1; // non-zero based index for tm struct
+            res.tm_mon = localDateTime.Month();
+            res.tm_year = localDateTime.Year() - 1900;
+            // Symbian's timezone server doesn't know how to handle DST before year 1997
+            if (res.tm_year < 97)
+                res.tm_isdst = -1;
+            brokenDown = &res;
+        }
     }
 #elif !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
     // use the reentrant version of localtime() where available
@@ -3812,23 +3822,27 @@ static void localToUtc(QDate &date, QTime &time, int isdst)
 #elif defined(Q_OS_SYMBIAN)
     // months and days are zero index based
     _LIT(KUnixEpoch, "19700000:000000.000000");
-    TTimeIntervalSeconds utcOffset = TTimeIntervalSeconds(0 - User::UTCOffset().Int());
     TTimeIntervalSeconds tTimeIntervalSecsSince1Jan1970UTC(secsSince1Jan1970UTC);
     TTime epochTTime;
     TInt err = epochTTime.Set(KUnixEpoch);
     tm res;
     if(err == KErrNone) {
-        TTime utcTTime = epochTTime + tTimeIntervalSecsSince1Jan1970UTC;
-        utcTTime = utcTTime + utcOffset;
-        TDateTime utcDateTime = utcTTime.DateTime();
-        res.tm_sec = utcDateTime.Second();
-        res.tm_min = utcDateTime.Minute();
-        res.tm_hour = utcDateTime.Hour();
-        res.tm_mday = utcDateTime.Day() + 1; // non-zero based index for tm struct
-        res.tm_mon = utcDateTime.Month();
-        res.tm_year = utcDateTime.Year() - 1900;
-        res.tm_isdst = (int)isdst;
-        brokenDown = &res;
+        TTime localTTime = epochTTime + tTimeIntervalSecsSince1Jan1970UTC;
+        RTz tz;
+        if (KErrNone == tz.Connect()) {
+            if (KErrNone == tz.ConvertToUniversalTime(localTTime)) {
+                TDateTime utcDateTime = localTTime.DateTime();
+                res.tm_sec = utcDateTime.Second();
+                res.tm_min = utcDateTime.Minute();
+                res.tm_hour = utcDateTime.Hour();
+                res.tm_mday = utcDateTime.Day() + 1; // non-zero based index for tm struct
+                res.tm_mon = utcDateTime.Month();
+                res.tm_year = utcDateTime.Year() - 1900;
+                res.tm_isdst = (int)isdst;
+                brokenDown = &res;
+            }
+        tz.Close();
+        }
     }
 #elif !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
     // use the reentrant version of gmtime() where available
diff --git a/tests/auto/qdatetime/tst_qdatetime.cpp b/tests/auto/qdatetime/tst_qdatetime.cpp
index 1140402..32fa398 100644
--- a/tests/auto/qdatetime/tst_qdatetime.cpp
+++ b/tests/auto/qdatetime/tst_qdatetime.cpp
@@ -147,9 +147,16 @@ Q_DECLARE_METATYPE(QTime)
 
 tst_QDateTime::tst_QDateTime()
 {
+#ifdef Q_OS_SYMBIAN
+    // Symbian's timezone server cannot handle DST correctly for dates before year 1997
+    uint x1 = QDateTime(QDate(2000, 1, 1), QTime()).toTime_t();
+    uint x2 = QDateTime(QDate(2000, 6, 1), QTime()).toTime_t();
+    europeanTimeZone = (x1 == 946681200 && x2 == 959810400);
+#else
     uint x1 = QDateTime(QDate(1990, 1, 1), QTime()).toTime_t();
     uint x2 = QDateTime(QDate(1990, 6, 1), QTime()).toTime_t();
     europeanTimeZone = (x1 == 631148400 && x2 == 644191200);
+#endif
 }
 
 tst_QDateTime::~tst_QDateTime()
-- 
cgit v0.12

