• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KDECore

ktimezone_win.cpp

Go to the documentation of this file.
00001 /*
00002    This file is part of the KDE libraries
00003    Copyright (c) 2008 Marc Mutz <mutz@kde.org>, Till Adam <adam@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018    Boston, MA 02110-1301, USA.
00019 */
00020 
00021 
00022 #include "ktimezone_win.h"
00023 #include <config.h>
00024 
00025 #include <kdebug.h>
00026 
00027 #include <QStringList>
00028 #include <QLibrary>
00029 
00030 #include <windows.h>
00031 
00032 #include <memory>
00033 #include <string>
00034 #include <cassert>
00035 
00036 struct ZoneKey {
00037     QString zoneOlson;
00038     QString zoneWin;
00039 };
00040 
00041 static const ZoneKey ZoneTbl[] =
00042 {
00043     {QLatin1String("Australia/Darwin"), QLatin1String("AUS Central Standard Time")},
00044     {QLatin1String("Australia/Sydney"), QLatin1String("AUS Eastern Standard Time")},
00045     {QLatin1String("Asia/Kabul"), QLatin1String("Afghanistan Standard Time")},
00046     {QLatin1String("America/Anchorage"), QLatin1String("Alaskan Standard Time")},
00047     {QLatin1String("Asia/Riyadh"), QLatin1String("Arab Standard Time")},
00048     {QLatin1String("Asia/Dubai"), QLatin1String("Arabian Standard Time")},
00049     {QLatin1String("Asia/Baghdad"), QLatin1String("Arabic Standard Time")},
00050     {QLatin1String("America/Buenos_Aires"), QLatin1String("Argentina Standard Time")},
00051     {QLatin1String("Asia/Yerevan"), QLatin1String("Armenian Standard Time")},
00052     {QLatin1String("America/Halifax"), QLatin1String("Atlantic Standard Time")},
00053     {QLatin1String("Asia/Baku"), QLatin1String("Azerbaijan Standard Time")},
00054     {QLatin1String("Atlantic/Azores"), QLatin1String("Azores Standard Time")},
00055     {QLatin1String("America/Regina"), QLatin1String("Canada Central Standard Time")},
00056     {QLatin1String("Atlantic/Cape_Verde"), QLatin1String("Cape Verde Standard Time")},
00057     {QLatin1String("Asia/Yerevan"), QLatin1String("Caucasus Standard Time")},
00058     {QLatin1String("Australia/Adelaide"), QLatin1String("Cen. Australia Standard Time")},
00059     {QLatin1String("America/Guatemala"), QLatin1String("Central America Standard Time")},
00060     {QLatin1String("Asia/Dhaka"), QLatin1String("Central Asia Standard Time")},
00061     {QLatin1String("America/Manaus"), QLatin1String("Central Brazilian Standard Time")},
00062     {QLatin1String("Europe/Budapest"), QLatin1String("Central Europe Standard Time")},
00063     {QLatin1String("Europe/Warsaw"), QLatin1String("Central European Standard Time")},
00064     {QLatin1String("Pacific/Guadalcanal"), QLatin1String("Central Pacific Standard Time")},
00065     {QLatin1String("America/Chicago"), QLatin1String("Central Standard Time")},
00066     {QLatin1String("America/Mexico_City"), QLatin1String("Central Standard Time (Mexico)")},
00067     {QLatin1String("Asia/Shanghai"), QLatin1String("China Standard Time")},
00068     {QLatin1String("Etc/GMT+12"), QLatin1String("Dateline Standard Time")},
00069     {QLatin1String("Africa/Nairobi"), QLatin1String("E. Africa Standard Time")},
00070     {QLatin1String("Australia/Brisbane"), QLatin1String("E. Australia Standard Time")},
00071     {QLatin1String("Europe/Minsk"), QLatin1String("E. Europe Standard Time")},
00072     {QLatin1String("America/Sao_Paulo"), QLatin1String("E. South America Standard Time")},
00073     {QLatin1String("America/New_York"), QLatin1String("Eastern Standard Time")},
00074     {QLatin1String("Africa/Cairo"), QLatin1String("Egypt Standard Time")},
00075     {QLatin1String("Asia/Yekaterinburg"), QLatin1String("Ekaterinburg Standard Time")},
00076     {QLatin1String("Europe/Kiev"), QLatin1String("FLE Standard Time")},
00077     {QLatin1String("Pacific/Fiji"), QLatin1String("Fiji Standard Time")},
00078     {QLatin1String("Europe/London"), QLatin1String("GMT Standard Time")},
00079     {QLatin1String("Europe/Istanbul"), QLatin1String("GTB Standard Time")},
00080     {QLatin1String("Etc/GMT-3"), QLatin1String("Georgian Standard Time")},
00081     {QLatin1String("America/Godthab"), QLatin1String("Greenland Standard Time")},
00082     {QLatin1String("Atlantic/Reykjavik"), QLatin1String("Greenwich Standard Time")},
00083     {QLatin1String("Pacific/Honolulu"), QLatin1String("Hawaiian Standard Time")},
00084     {QLatin1String("Asia/Calcutta"), QLatin1String("India Standard Time")},
00085     {QLatin1String("Asia/Tehran"), QLatin1String("Iran Standard Time")},
00086     {QLatin1String("Asia/Jerusalem"), QLatin1String("Israel Standard Time")},
00087     {QLatin1String("Asia/Amman"), QLatin1String("Jordan Standard Time")},
00088     {QLatin1String("Asia/Seoul"), QLatin1String("Korea Standard Time")},
00089     {QLatin1String("Indian/Mauritius"), QLatin1String("Mauritius Standard Time")},
00090     {QLatin1String("America/Mexico_City"), QLatin1String("Mexico Standard Time")},
00091     {QLatin1String("America/Chihuahua"), QLatin1String("Mexico Standard Time 2")},
00092     {QLatin1String("Atlantic/South_Georgia"), QLatin1String("Mid-Atlantic Standard Time")},
00093     {QLatin1String("Asia/Beirut"), QLatin1String("Middle East Standard Time")},
00094     {QLatin1String("America/Montevideo"), QLatin1String("Montevideo Standard Time")},
00095     {QLatin1String("Africa/Casablanca"), QLatin1String("Morocco Standard Time")},
00096     {QLatin1String("America/Denver"), QLatin1String("Mountain Standard Time")},
00097     {QLatin1String("America/Chihuahua"), QLatin1String("Mountain Standard Time (Mexico)")},
00098     {QLatin1String("Asia/Rangoon"), QLatin1String("Myanmar Standard Time")},
00099     {QLatin1String("Asia/Novosibirsk"), QLatin1String("N. Central Asia Standard Time")},
00100     {QLatin1String("Africa/Windhoek"), QLatin1String("Namibia Standard Time")},
00101     {QLatin1String("Asia/Katmandu"), QLatin1String("Nepal Standard Time")},
00102     {QLatin1String("Pacific/Auckland"), QLatin1String("New Zealand Standard Time")},
00103     {QLatin1String("America/St_Johns"), QLatin1String("Newfoundland Standard Time")},
00104     {QLatin1String("Asia/Irkutsk"), QLatin1String("North Asia East Standard Time")},
00105     {QLatin1String("Asia/Krasnoyarsk"), QLatin1String("North Asia Standard Time")},
00106     {QLatin1String("America/Santiago"), QLatin1String("Pacific SA Standard Time")},
00107     {QLatin1String("America/Los_Angeles"), QLatin1String("Pacific Standard Time")},
00108     {QLatin1String("America/Tijuana"), QLatin1String("Pacific Standard Time (Mexico)")},
00109     {QLatin1String("Asia/Karachi"), QLatin1String("Pakistan Standard Time")},
00110     {QLatin1String("Europe/Paris"), QLatin1String("Romance Standard Time")},
00111     {QLatin1String("Europe/Moscow"), QLatin1String("Russian Standard Time")},
00112     {QLatin1String("Etc/GMT+3"), QLatin1String("SA Eastern Standard Time")},
00113     {QLatin1String("America/Bogota"), QLatin1String("SA Pacific Standard Time")},
00114     {QLatin1String("America/La_Paz"), QLatin1String("SA Western Standard Time")},
00115     {QLatin1String("Asia/Bangkok"), QLatin1String("SE Asia Standard Time")},
00116     {QLatin1String("Pacific/Apia"), QLatin1String("Samoa Standard Time")},
00117     {QLatin1String("Asia/Singapore"), QLatin1String("Singapore Standard Time")},
00118     {QLatin1String("Africa/Johannesburg"), QLatin1String("South Africa Standard Time")},
00119     {QLatin1String("Asia/Colombo"), QLatin1String("Sri Lanka Standard Time")},
00120     {QLatin1String("Asia/Taipei"), QLatin1String("Taipei Standard Time")},
00121     {QLatin1String("Australia/Hobart"), QLatin1String("Tasmania Standard Time")},
00122     {QLatin1String("Asia/Tokyo"), QLatin1String("Tokyo Standard Time")},
00123     {QLatin1String("Pacific/Tongatapu"), QLatin1String("Tonga Standard Time")},
00124     {QLatin1String("Etc/GMT+5"), QLatin1String("US Eastern Standard Time")},
00125     {QLatin1String("America/Phoenix"), QLatin1String("US Mountain Standard Time")},
00126     {QLatin1String("America/Caracas"), QLatin1String("Venezuela Standard Time")},
00127     {QLatin1String("Asia/Vladivostok"), QLatin1String("Vladivostok Standard Time")},
00128     {QLatin1String("Australia/Perth"), QLatin1String("W. Australia Standard Time")},
00129     {QLatin1String("Africa/Lagos"), QLatin1String("W. Central Africa Standard Time")},
00130     {QLatin1String("Europe/Berlin"), QLatin1String("W. Europe Standard Time")},
00131     {QLatin1String("Asia/Tashkent"), QLatin1String("West Asia Standard Time")},
00132     {QLatin1String("Pacific/Port_Moresby"), QLatin1String("West Pacific Standard Time")},
00133     {QLatin1String("Asia/Yakutsk"), QLatin1String("Yakutsk Standard Time")}
00134 };
00135 
00136 static QString getWinZoneName(const QString &name)
00137 {
00138     for ( int i = 0; i < sizeof(ZoneTbl) / sizeof(ZoneTbl[0]); ++i ) {
00139         if (ZoneTbl[i].zoneOlson == name) {
00140             return ZoneTbl[i].zoneWin;
00141         }
00142     }
00143     
00144     return name;
00145 }
00146 
00147 typedef BOOL (WINAPI *PtrTzSpecificLocalTimeToSystemTime )(LPTIME_ZONE_INFORMATION lpTimeZoneInformation,
00148                                                            LPSYSTEMTIME lpLocalTime,
00149                                                            LPSYSTEMTIME lpUniversalTime
00150 );
00151 static PtrTzSpecificLocalTimeToSystemTime pTzSpecificLocalTimeToSystemTime = 0;
00152 
00153 namespace {
00154     class HKeyCloser {
00155         const HKEY hkey;
00156         Q_DISABLE_COPY( HKeyCloser )
00157     public:
00158         explicit HKeyCloser( HKEY hk ) : hkey( hk ) {}
00159         ~HKeyCloser() { RegCloseKey(  hkey ); }
00160     };
00161 
00162     struct TZI {
00163         LONG Bias;
00164         LONG StandardBias;
00165         LONG DaylightBias;
00166         SYSTEMTIME StandardDate;
00167         SYSTEMTIME DaylightDate;
00168     };
00169 }
00170 
00171 // TCHAR can be either uchar, or wchar_t:
00172 #ifdef UNICODE
00173 
00174 static inline QString tchar_to_qstring( const TCHAR * str ) {
00175     return QString::fromUtf16( reinterpret_cast<const ushort*>( str ) );
00176 }
00177 
00178 static inline const TCHAR * qstring_to_tchar( const QString& str ) {
00179     return reinterpret_cast<const TCHAR*>( str.utf16() );
00180 }
00181 
00182 static inline std::basic_string<TCHAR> qstring_to_tcharstring( const QString& str ) {
00183     return std::basic_string<TCHAR>( qstring_to_tchar(str) );
00184 }
00185 
00186 #else
00187 
00188 static inline QString tchar_to_qstring( const TCHAR * str ) {
00189     return QString::fromLocal8Bit( str );
00190 }
00191 
00192 static inline const TCHAR * qstring_to_tchar( const QString& str ) {
00193     return str.toLocal8Bit().constData();
00194 }
00195 
00196 static inline std::basic_string<TCHAR> qstring_to_tcharstring( const QString& str ) {
00197     return std::basic_string<TCHAR>( qstring_to_tchar(str) );
00198 }
00199 
00200 #endif
00201 
00202 static const TCHAR timeZonesKey[] = TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones");
00203 static inline QDateTime systemtime_to_qdatetime( const SYSTEMTIME & st ) {
00204     return QDateTime( QDate( st.wYear, st.wMonth, st.wDay ),
00205                       QTime( st.wHour, st.wMinute, st.wSecond, st.wMilliseconds ) );
00206 }
00207 
00208 static SYSTEMTIME qdatetime_to_systemtime( const QDateTime & dt ) {
00209     const QDate d = dt.date();
00210     const QTime t = dt.time();
00211     const SYSTEMTIME st = {
00212         d.year(),
00213         d.month(),
00214         d.dayOfWeek() % 7, // 1..7 (Mon..Sun)->0..6(Sun..Sat)
00215         d.day(),
00216         t.hour(),
00217         t.minute(),
00218         t.second(),
00219         t.msec(),
00220     };
00221     return st;
00222 }
00223 
00224 static bool TzSpecificLocalTimeToSystemTime_Portable( TIME_ZONE_INFORMATION* tz,
00225                                                       SYSTEMTIME *i_stLocal,
00226                                                       SYSTEMTIME *o_stUniversal )
00227 {
00228 
00229     // the method below was introduced in XP. If it's there, use it, otherwise
00230     // fall back to doing things manually
00231     if (!pTzSpecificLocalTimeToSystemTime) {
00232         QLibrary kernelLib(QLatin1String("kernel32"));
00233         pTzSpecificLocalTimeToSystemTime  = (PtrTzSpecificLocalTimeToSystemTime)kernelLib.resolve("TzSpecificLocalTimeToSystemTime");
00234     }
00235 
00236     if ( pTzSpecificLocalTimeToSystemTime )
00237         return pTzSpecificLocalTimeToSystemTime( tz, i_stLocal , o_stUniversal ) != 0;
00238     
00239     // the algorithm is:
00240     // - switch to the desired timezone temporarily
00241     // - convert system time to (local) file time in that timezone
00242     // - convert local file time to utc file time
00243     // - convert utc file time to system time
00244     // - reset timezone
00245     FILETIME ft, ft_utc;
00246     int result = 1;
00247     TIME_ZONE_INFORMATION currentTimeZone;
00248     result = GetTimeZoneInformation(&currentTimeZone);
00249     if ( result == TIME_ZONE_ID_INVALID ) {
00250         kWarning(161) << "Getting time zone information failed";
00251         return false;
00252     }
00253     result = SetTimeZoneInformation(tz);
00254     if ( result == 0 ) {
00255         kWarning(161) << "Setting temporary time zone failed";
00256         return false;
00257     }
00258     result = SystemTimeToFileTime(i_stLocal, &ft);
00259     if ( result == 0 ) {
00260         kWarning(161) << "SysteTimeToFileTime failed";
00261         return false;
00262     }
00263     result = LocalFileTimeToFileTime(&ft, &ft_utc);
00264     if ( result == 0 ) {
00265         kWarning(161) << "LocalFileTimeToFileTime failed";
00266         return false;
00267     }
00268     result = FileTimeToSystemTime(&ft_utc,o_stUniversal);
00269     if ( result == 0 ) {
00270         kWarning(161) << "FileTimeToSystemTime failed";
00271         return false;
00272     }
00273     result = SetTimeZoneInformation(&currentTimeZone);
00274     if ( result == 0 ) {
00275         kWarning(161) << "Re-setting time zone information failed";
00276         return false;
00277     }
00278     return true;
00279 }
00280 
00281 
00282 
00283 
00284 static bool get_binary_value( HKEY key, const TCHAR * value, void * data, DWORD numData, DWORD * outNumData=0 ) {
00285     DWORD size = numData;
00286     DWORD type = REG_BINARY;
00287     if ( RegQueryValueEx( key, value, 0, &type, (LPBYTE)data, &size ) != ERROR_SUCCESS )
00288         return false;
00289     assert( type == REG_BINARY );
00290     if (  type != REG_BINARY )
00291         return false;
00292     if ( outNumData )
00293         *outNumData = size;
00294     return true;
00295 }
00296 
00297 static bool get_string_value( HKEY key, const TCHAR * value, TCHAR * dest, DWORD destSizeInBytes ) {
00298     DWORD size = destSizeInBytes;
00299     DWORD type = REG_SZ;
00300     dest[0] = '\0';
00301     if ( RegQueryValueEx( key, value, 0, &type, (LPBYTE)dest, &size ) != ERROR_SUCCESS )
00302         return false;
00303     //dest[ qMin( size, destSizeInBytes - sizeof( WCHAR ) ) / sizeof( WCHAR ) ] = 0;
00304     assert( type == REG_SZ );
00305     if ( type != REG_SZ )
00306         return false;
00307     return true;
00308 }
00309 
00310 //
00311 //
00312 // Backend interface impl:
00313 //
00314 //
00315 
00316 static bool check_prereq( const KTimeZone * caller, const QDateTime & dt, Qt::TimeSpec spec ) {
00317     return caller && caller->isValid() && dt.isValid() && dt.timeSpec() == spec ;
00318 }
00319 
00320 static inline bool check_local( const KTimeZone * caller, const QDateTime & dt ) {
00321     return check_prereq( caller, dt, Qt::LocalTime );
00322 }
00323 
00324 static inline bool check_utc( const KTimeZone * caller, const QDateTime & dt ) {
00325     return check_prereq( caller, dt, Qt::UTC );
00326 }
00327 
00328 static bool has_transition( const TIME_ZONE_INFORMATION & tz ) {
00329     return tz.StandardDate.wMonth != 0 && tz.DaylightDate.wMonth != 0 ;
00330 }
00331 
00332 static int win_dayofweek_to_qt_dayofweek( int wdow ) {
00333     // Sun(0)..Sat(6) -> Mon(1)...Sun(7)
00334     return wdow ? wdow : 7 ;
00335 }
00336 
00337 static int qt_dayofweek_to_win_dayofweek( int qdow ) {
00338     // Mon(1)...Sun(7) -> Sub(0)...Sat(6)
00339     return qdow % 7;
00340 }
00341 
00342 static QDate find_nth_weekday_in_month_of_year( int nth, int dayOfWeek, int month, int year ) {
00343     assert( nth >= 1 );
00344     assert( nth <= 5 );
00345 
00346     const QDate first( year, month, 1 );
00347     const int actualDayOfWeek = first.dayOfWeek();
00348     QDate candidate = first.addDays( ( nth - 1 ) * 7 + dayOfWeek - actualDayOfWeek );
00349     assert( candidate.dayOfWeek() == dayOfWeek );
00350     if ( nth == 5 )
00351         if ( candidate.month() != month )
00352             candidate = candidate.addDays( -7 );
00353     assert( candidate.month() == month );
00354     return candidate;
00355 }
00356 
00357 static QDateTime transition( const SYSTEMTIME & st, int year ) {
00358     assert( st.wYear == 0 );
00359     assert( st.wMonth != 0 );
00360     return QDateTime( find_nth_weekday_in_month_of_year( st.wDay, win_dayofweek_to_qt_dayofweek( st.wDayOfWeek ), st.wMonth, year ),
00361                       QTime( st.wHour, st.wMinute, st.wSecond, st.wMilliseconds ) );
00362 }
00363 
00364 struct Transitions {
00365     QDateTime stdStart, dstStart;
00366 };
00367 
00368 Transitions transitions( const TIME_ZONE_INFORMATION & tz, int year ) {
00369     const Transitions t = {
00370         transition( tz.StandardDate, year ), transition( tz.DaylightDate, year )
00371     };
00372     return t;
00373 }
00374 
00375 
00376 static const int MAX_KEY_LENGTH = 255;
00377 
00378 static QStringList list_key( HKEY key ) {
00379 
00380     DWORD numSubKeys = 0;
00381     QStringList result;
00382 
00383     if ( RegQueryInfoKey( key, 0, 0, 0, &numSubKeys, 0, 0, 0, 0, 0, 0, 0 ) == ERROR_SUCCESS )
00384         for ( DWORD i = 0 ; i < numSubKeys ; ++i ) {
00385             TCHAR name[MAX_KEY_LENGTH+1];
00386             DWORD nameLen = MAX_KEY_LENGTH;
00387             if ( RegEnumKeyEx( key, i, name, &nameLen, 0, 0, 0, 0 ) == ERROR_SUCCESS )
00388                 result.push_back( tchar_to_qstring( name ) );
00389         }
00390 
00391     return result;
00392 }
00393 
00394 static QStringList list_standard_names()
00395 {
00396     QStringList standardNames;
00397     
00398     HKEY timeZones;
00399     QStringList keys;
00400     if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, timeZonesKey, 0, KEY_READ, &timeZones ) == ERROR_SUCCESS )
00401         keys = list_key(timeZones);
00402 
00403     std::basic_string<TCHAR> path( timeZonesKey );
00404     path += TEXT( "\\" );
00405 
00406     const HKeyCloser closer( timeZones );
00407     Q_FOREACH( const QString & keyname, keys ) {
00408     
00409         std::basic_string<TCHAR> keypath(path);
00410         keypath += qstring_to_tcharstring(keyname);
00411     HKEY key;
00412     if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, keypath.c_str(), 0, KEY_READ, &key ) != ERROR_SUCCESS ) {
00413         return standardNames; // FIXME what's the right error handling here?
00414     }
00415 
00416     const HKeyCloser closer( key );
00417 
00418     TIME_ZONE_INFORMATION tz;
00419     get_string_value( key, L"Std", tz.StandardName, sizeof( tz.StandardName ) );
00420 
00421     standardNames << tchar_to_qstring(tz.StandardName);
00422     }
00423     
00424     for ( int i = 0; i < sizeof(ZoneTbl) / sizeof(ZoneTbl[0]); ++i ) {
00425         standardNames << ZoneTbl[i].zoneOlson;
00426     }
00427 
00428     return standardNames;
00429 }
00430 
00431 static std::basic_string<TCHAR> pathFromZoneName(const KTimeZone& zone)
00432 {
00433     std::basic_string<TCHAR> path( timeZonesKey );
00434     path += TEXT( "\\" );
00435     
00436     QString name = zone.name();
00437 
00438     name = getWinZoneName(name);
00439 
00440     HKEY timeZones;
00441     QStringList keys;
00442     if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, timeZonesKey, 0, KEY_READ, &timeZones ) == ERROR_SUCCESS )
00443         keys = list_key(timeZones);
00444 
00445     const HKeyCloser closer( timeZones );
00446     Q_FOREACH( const QString & keyname, keys ) {
00447     
00448         std::basic_string<TCHAR> keypath(path);
00449         keypath += qstring_to_tcharstring(keyname);
00450     HKEY key;
00451     if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, keypath.c_str(), 0, KEY_READ, &key ) != ERROR_SUCCESS ) {
00452         return 0; // FIXME what's the right error handling here?
00453     }
00454 
00455     const HKeyCloser closer( key );
00456 
00457     TIME_ZONE_INFORMATION tz;
00458     get_string_value( key, L"Std", tz.StandardName, sizeof( tz.StandardName ) );
00459 
00460     if ( tchar_to_qstring(tz.StandardName) == name ) {
00461         return keypath;
00462     }
00463     }
00464     Q_ASSERT(false);
00465 
00466     return path;
00467 }
00468 
00469 /******************************************************************************/
00470 
00471 class KSystemTimeZoneSourceWindowsPrivate
00472 {
00473 public:
00474     KSystemTimeZoneSourceWindowsPrivate() {}
00475     ~KSystemTimeZoneSourceWindowsPrivate() {}
00476 };
00477 
00478 
00479 class KSystemTimeZoneBackendWindows : public KTimeZoneBackend
00480 {
00481 public:
00482   KSystemTimeZoneBackendWindows(KTimeZoneSource *source, const QString &name)
00483   : KTimeZoneBackend(source, name) {}
00484 
00485   ~KSystemTimeZoneBackendWindows() {}
00486 
00487   KSystemTimeZoneBackendWindows *clone() const;
00488 
00489   QByteArray type() const;
00490 
00491   int offsetAtZoneTime(const KTimeZone *caller, const QDateTime &zoneDateTime, int *secondOffset) const;
00492   int offsetAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const;
00493   int offset(const KTimeZone *caller, time_t t) const;
00494   bool isDstAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const;
00495   bool isDst(const KTimeZone *caller, time_t t) const;
00496 };
00497 
00498 class KSystemTimeZoneDataWindows : public KTimeZoneData
00499 {
00500 public:
00501   KSystemTimeZoneDataWindows()
00502   :KTimeZoneData()
00503   {
00504 
00505   }
00506   TIME_ZONE_INFORMATION _tzi;
00507   QString displayName;
00508 
00509   const TIME_ZONE_INFORMATION & tzi( int year = 0 ) const { Q_UNUSED( year ); return _tzi; }
00510 };
00511 
00512 KSystemTimeZoneSourceWindows::KSystemTimeZoneSourceWindows()
00513 :d( new KSystemTimeZoneSourceWindowsPrivate )
00514 {
00515 }
00516 
00517 KTimeZoneData* KSystemTimeZoneSourceWindows::parse(const KTimeZone &zone) const
00518 {
00519     KSystemTimeZoneDataWindows* data = new KSystemTimeZoneDataWindows();
00520 
00521     std::basic_string<TCHAR> path = pathFromZoneName(zone);
00522 
00523     HKEY key;
00524     if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, path.c_str(), 0, KEY_READ, &key ) != ERROR_SUCCESS ) {
00525         delete data;
00526         return 0; // FIXME what's the right error handling here?
00527     }
00528 
00529     const HKeyCloser closer( key );
00530 
00531     TZI tzi = { 0 };
00532 
00533     if ( !get_binary_value( key, TEXT( "TZI" ), &tzi, sizeof( TZI ) ) ) {
00534         delete data;
00535         return 0; // ?
00536     }
00537 
00538     get_string_value( key, L"Std", data->_tzi.StandardName, sizeof( data->_tzi.StandardName ) );
00539     get_string_value( key, L"Dlt", data->_tzi.DaylightName, sizeof( data->_tzi.DaylightName ) );
00540 
00541     TCHAR display[512];
00542     get_string_value( key, L"Display", display, sizeof( display ) );
00543     data->displayName = tchar_to_qstring( display );
00544 
00545 #define COPY( name ) data->_tzi.name = tzi.name
00546     COPY( Bias );
00547     COPY( StandardBias );
00548     COPY( StandardDate );
00549     COPY( DaylightBias );
00550     COPY( DaylightDate );
00551 #undef COPY
00552 
00553     return data;
00554 }
00555 
00556 Transitions transitions( const KTimeZone * caller, int year ) {
00557     return transitions( static_cast<const KSystemTimeZoneDataWindows*>( caller->data(true) )->tzi( year ), year );
00558 }
00559 
00560 static bool is_dst( const TIME_ZONE_INFORMATION & tzi, const QDateTime & utc, int year ) {
00561     if ( !has_transition( tzi ) )
00562         return false;
00563     const Transitions trans = transitions( tzi, year );
00564     if ( trans.stdStart < trans.dstStart )
00565         return trans.dstStart <= utc || utc < trans.stdStart ;
00566     else
00567         return trans.dstStart <= utc && utc < trans.stdStart ;
00568 }
00569 
00570 static bool is_dst( const KTimeZone * caller, const QDateTime & utc ) {
00571     assert( caller );
00572     assert( caller->isValid() );
00573     const int year = utc.date().year();
00574     const TIME_ZONE_INFORMATION & tzi = static_cast<const KSystemTimeZoneDataWindows*>( caller->data(true) )->tzi( year );
00575     return is_dst( tzi, utc, year );
00576 }
00577 
00578 static int effective_offset( const TIME_ZONE_INFORMATION& tz, bool isDst ) {
00579     int bias = tz.Bias;
00580     if ( has_transition( tz ) )
00581         if ( isDst )
00582             bias += tz.DaylightBias;
00583         else
00584             bias += tz.StandardBias;
00585     return bias * -60; // min -> secs
00586 }
00587 
00588 static int offset_at_utc( const KTimeZone * caller, const QDateTime & utc ) {
00589     assert( caller );
00590     assert( caller->isValid() );
00591     const int year = utc.date().year();
00592     const TIME_ZONE_INFORMATION & tz = static_cast<const KSystemTimeZoneDataWindows*>( caller->data(true) )->tzi( year );
00593     return effective_offset( tz, is_dst( tz, utc, year ) );
00594 }
00595 
00596 static const int OneHour = 3600; //sec
00597 
00598 static int difference( const SYSTEMTIME & st1, const SYSTEMTIME & st2 ) {
00599     return systemtime_to_qdatetime( st1 ).secsTo( systemtime_to_qdatetime( st2 ) );
00600 }
00601 
00602 static int offset_at_zone_time( const KTimeZone * caller, const SYSTEMTIME & zone, int * secondOffset ) {
00603     assert( caller );
00604     assert( caller->isValid() );
00605     assert(caller->data(true));
00606     const KSystemTimeZoneDataWindows * const data = static_cast<const KSystemTimeZoneDataWindows*>( caller->data(true) );
00607     const TIME_ZONE_INFORMATION & tz = data->tzi( zone.wYear );
00608     SYSTEMTIME utc;
00609     if ( !TzSpecificLocalTimeToSystemTime_Portable( const_cast<LPTIME_ZONE_INFORMATION>( &tz ), const_cast<LPSYSTEMTIME>( &zone ), &utc ) )
00610         return 0;
00611     const bool isDst = is_dst( tz, systemtime_to_qdatetime( utc ), utc.wYear );
00612     int result = effective_offset( tz, isDst );
00613 //FIXME: SystemTimeToTzSpecificLocalTime does not exsit on wince
00614 #ifndef _WIN32_WCE
00615     if ( secondOffset ) {
00616         const SYSTEMTIME utcplus1 = qdatetime_to_systemtime( systemtime_to_qdatetime( utc ).addSecs( OneHour ) );
00617         const SYSTEMTIME utcminus1 = qdatetime_to_systemtime( systemtime_to_qdatetime( utc ).addSecs( -OneHour ) );
00618         SYSTEMTIME zoneplus1, zoneminus1;
00619         if ( !SystemTimeToTzSpecificLocalTime( const_cast<LPTIME_ZONE_INFORMATION>( &tz ), const_cast<LPSYSTEMTIME>( &utcplus1 ), &zoneplus1 ) ||
00620              !SystemTimeToTzSpecificLocalTime( const_cast<LPTIME_ZONE_INFORMATION>( &tz ), const_cast<LPSYSTEMTIME>( &utcminus1 ), &zoneminus1 ) )
00621             return result;
00622         if ( difference( zoneminus1, zone ) != OneHour ||
00623              difference( zone, zoneplus1 ) != OneHour )
00624         {
00625             *secondOffset = effective_offset( tz, !isDst );
00626             if ( result < *secondOffset )
00627                 qSwap( result, *secondOffset );
00628         }
00629     }
00630 #endif
00631     return result;
00632 }
00633 
00634 
00635 
00636 KSystemTimeZoneBackendWindows * KSystemTimeZoneBackendWindows::clone() const
00637 {
00638     return new KSystemTimeZoneBackendWindows(*this);
00639 }
00640 
00641 QByteArray KSystemTimeZoneBackendWindows::type() const
00642 {
00643     return "KSystemTimeZoneWindows";
00644 }
00645 
00646 int KSystemTimeZoneBackendWindows::offsetAtZoneTime(const KTimeZone *caller, const QDateTime &zoneDateTime, int *secondOffset) const
00647 {
00648     if (!caller->isValid()  ||  !zoneDateTime.isValid()  ||  zoneDateTime.timeSpec() != Qt::LocalTime)
00649         return 0;
00650     if ( !check_local( caller, zoneDateTime ) )
00651         return 0;
00652 
00653     return offset_at_zone_time( caller, qdatetime_to_systemtime( zoneDateTime ), secondOffset );
00654 }
00655 
00656 int KSystemTimeZoneBackendWindows::offsetAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const
00657 {
00658     if (!caller->isValid()  ||  !utcDateTime.isValid())
00659         return 0;
00660     if ( !check_utc( caller, utcDateTime ) )
00661         return 0;
00662     return offset_at_utc( caller, utcDateTime );
00663 }
00664 
00665 int KSystemTimeZoneBackendWindows::offset(const KTimeZone *caller, time_t t) const
00666 {
00667     if (!caller->isValid()  ||  t == KTimeZone::InvalidTime_t)
00668         return 0;
00669     return offsetAtUtc( caller, KTimeZone::fromTime_t( t ) );
00670 }
00671 
00672 bool KSystemTimeZoneBackendWindows::isDstAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const
00673 {
00674     return check_utc( caller, utcDateTime ) && is_dst( caller, utcDateTime );
00675 }
00676 
00677 
00678 bool KSystemTimeZoneBackendWindows::isDst(const KTimeZone *caller, time_t t) const
00679 {
00680     return isDstAtUtc( caller, KTimeZone::fromTime_t( t ) );
00681 }
00682 
00683 KSystemTimeZoneWindows::KSystemTimeZoneWindows(KTimeZoneSource *source, const QString &name)
00684 : KTimeZone(new KSystemTimeZoneBackendWindows(source, name))
00685 {}
00686 
00687 QStringList KSystemTimeZoneWindows::listTimeZones() 
00688 {
00689     return list_standard_names();
00690 }
00691 

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal