]> git.saurik.com Git - wxWidgets.git/commitdiff
Fix FILETIME <-> wxDateTime conversions while DST is in effect in wxMSW.
authorVadim Zeitlin <vadim@wxwidgets.org>
Sat, 6 Jul 2013 18:21:10 +0000 (18:21 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sat, 6 Jul 2013 18:21:10 +0000 (18:21 +0000)
The result was (consistently, so the tests still passed) off by an hour when
the program was ran while DST was in effect. Fix this by avoiding the use of
FileTimeToLocalFileTime() and LocalFileTimeToFileTime() and just directly
converting FILETIME values to wxDateTime. Not only this is more correct but
it's also simpler and more efficient as well.

Also add a unit test for wxFileName::SetTimes() too.

Closes #13098.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74423 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/changes.txt
src/common/filename.cpp
tests/filename/filenametest.cpp

index d29c67521dadcb52000ff6e0a55d8312c4a20ef2..c6f93d88487c076ceadeec11148dd83dcd69a575 100644 (file)
@@ -711,6 +711,7 @@ wxMSW:
 - Fix filter checks in wxDir::FindFirst/Next() (Catalin Raceanu).
 - Add support for wxICON_AUTH_NEEDED to wxMessageDialog (Chris Spencer).
 - Fix printing too many copies of the document in some cases (John Roberts).
+- Fix DST confusion in wxFileName::{Set,Get}Times().
 
 wxOSX/Cocoa:
 
index d6d68aeeb6c2a3d731d9675779d4829012edef9e..44b47f0719c4de65ece27034be2284c8e3e5f424 100644 (file)
@@ -93,6 +93,7 @@
 #include "wx/config.h"          // for wxExpandEnvVars
 #include "wx/dynlib.h"
 #include "wx/dir.h"
+#include "wx/longlong.h"
 
 #if defined(__WIN32__) && defined(__MINGW32__)
     #include "wx/msw/gccpriv.h"
@@ -231,49 +232,30 @@ private:
 
 #if wxUSE_DATETIME && defined(__WIN32__) && !defined(__WXMICROWIN__)
 
-// convert between wxDateTime and FILETIME which is a 64-bit value representing
-// the number of 100-nanosecond intervals since January 1, 1601.
+// Convert between wxDateTime and FILETIME which is a 64-bit value representing
+// the number of 100-nanosecond intervals since January 1, 1601 UTC.
+//
+// This is the offset between FILETIME epoch and the Unix/wxDateTime Epoch.
+static wxInt64 EPOCH_OFFSET_IN_MSEC = wxLL(11644473600000);
 
 static void ConvertFileTimeToWx(wxDateTime *dt, const FILETIME &ft)
 {
-    FILETIME ftcopy = ft;
-    FILETIME ftLocal;
-    if ( !::FileTimeToLocalFileTime(&ftcopy, &ftLocal) )
-    {
-        wxLogLastError(wxT("FileTimeToLocalFileTime"));
-    }
-
-    SYSTEMTIME st;
-    if ( !::FileTimeToSystemTime(&ftLocal, &st) )
-    {
-        wxLogLastError(wxT("FileTimeToSystemTime"));
-    }
+    wxLongLong t(ft.dwHighDateTime, ft.dwLowDateTime);
+    t /= 10000; // Convert hundreds of nanoseconds to milliseconds.
+    t -= EPOCH_OFFSET_IN_MSEC;
 
-    dt->Set(st.wDay, wxDateTime::Month(st.wMonth - 1), st.wYear,
-            st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
+    *dt = wxDateTime(t);
 }
 
 static void ConvertWxToFileTime(FILETIME *ft, const wxDateTime& dt)
 {
-    SYSTEMTIME st;
-    st.wDay = dt.GetDay();
-    st.wMonth = (WORD)(dt.GetMonth() + 1);
-    st.wYear = (WORD)dt.GetYear();
-    st.wHour = dt.GetHour();
-    st.wMinute = dt.GetMinute();
-    st.wSecond = dt.GetSecond();
-    st.wMilliseconds = dt.GetMillisecond();
+    // Undo the conversions above.
+    wxLongLong t(dt.GetValue());
+    t += EPOCH_OFFSET_IN_MSEC;
+    t *= 10000;
 
-    FILETIME ftLocal;
-    if ( !::SystemTimeToFileTime(&st, &ftLocal) )
-    {
-        wxLogLastError(wxT("SystemTimeToFileTime"));
-    }
-
-    if ( !::LocalFileTimeToFileTime(&ftLocal, ft) )
-    {
-        wxLogLastError(wxT("LocalFileTimeToFileTime"));
-    }
+    ft->dwHighDateTime = t.GetHi();
+    ft->dwLowDateTime = t.GetLo();
 }
 
 #endif // wxUSE_DATETIME && __WIN32__
index 10ef920f39a018e345def4cf7073ca51d9f07881..3117760f1382de90a3f6bf6a2bad61f847a47be5 100644 (file)
@@ -35,6 +35,7 @@
 #endif // __UNIX__
 
 #include "testfile.h"
+#include "testdate.h"
 
 // ----------------------------------------------------------------------------
 // test data
@@ -139,6 +140,7 @@ private:
         CPPUNIT_TEST( TestVolumeUniqueName );
         CPPUNIT_TEST( TestCreateTempFileName );
         CPPUNIT_TEST( TestGetTimes );
+        CPPUNIT_TEST( TestSetTimes );
         CPPUNIT_TEST( TestExists );
         CPPUNIT_TEST( TestIsSame );
 #if defined(__UNIX__)
@@ -161,6 +163,7 @@ private:
     void TestVolumeUniqueName();
     void TestCreateTempFileName();
     void TestGetTimes();
+    void TestSetTimes();
     void TestExists();
     void TestIsSame();
 #if defined(__UNIX__)
@@ -664,6 +667,27 @@ void FileNameTestCase::TestGetTimes()
     CPPUNIT_ASSERT(dtAccess.IsEqualUpTo(wxDateTime::Now(), wxTimeSpan(0,1)));
 }
 
+void FileNameTestCase::TestSetTimes()
+{
+    wxFileName fn(wxFileName::CreateTempFileName("filenametest"));
+    CPPUNIT_ASSERT( fn.IsOk() );
+    wxON_BLOCK_EXIT1( wxRemoveFile, fn.GetFullPath() );
+
+    const wxDateTime dtAccess(1, wxDateTime::Jan, 2013);
+    const wxDateTime dtModify(1, wxDateTime::Feb, 2013);
+    const wxDateTime dtCreate(1, wxDateTime::Mar, 2013);
+
+    CPPUNIT_ASSERT( fn.SetTimes(&dtAccess, &dtModify, &dtCreate) );
+
+    wxDateTime dtAccess2,
+               dtModify2,
+               dtCreate2;
+    CPPUNIT_ASSERT( fn.GetTimes(&dtAccess2, &dtModify2, &dtCreate2) );
+    CPPUNIT_ASSERT_EQUAL( dtAccess, dtAccess2 );
+    CPPUNIT_ASSERT_EQUAL( dtModify, dtModify2 );
+    CPPUNIT_ASSERT_EQUAL( dtCreate, dtCreate2 );
+}
+
 void FileNameTestCase::TestExists()
 {
     wxFileName fn(wxFileName::CreateTempFileName("filenametest"));