?
Solved

Bug when reading the mtime of the file that was just set via _utime

Posted on 2014-04-10
5
Medium Priority
?
422 Views
Last Modified: 2014-04-12
Hi,

Writing unit tests, I was surprised by the behaviour described below, and I cannot see where the bug is. I am just calling the _utime() function to set the modification time for the file. When trying to get the modification time back via _stat(), the returned modification time is not the same.

#include <sys/types.h> 
#include <sys/stat.h>
#include <sys/utime.h>

#include <cassert>
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main()
{
    string fname = { "test.data" };

    ofstream f(fname);
    f << "test content";
    f.close();

    // Check the existence of the created file.
    struct _stat stat;
    if (_stat(fname.c_str(), &stat)) {
        cout << "_stat() error";
        return 1;
    }
    assert((stat.st_mode & _S_IFREG) != 0);

    // The time to be used for testing.
    time_t christmas2003_t = 1072263600;   // 2003-12-23 11:00

    // Set the times of the file.
    struct _utimbuf ut;
    ut.actime = christmas2003_t;
    ut.modtime = christmas2003_t;

    if (_utime(fname.c_str(), &ut) == -1) {
        cout << "_utime() error";
        return 1;
    }

    // Get the modification time of the file (back).
    struct _stat stat_struct;
    if (_stat(fname.c_str(), &stat_struct))
    {
        cout << "_stat() error";
        return 1;
    }
    time_t mtime = stat_struct.st_mtime;

    // Compare the two times.
    if (mtime == christmas2003_t)
        cout << "OK\n";
    else
        cout << "failed (" << mtime << " is not equal to " << christmas2003_t << ")\n";
    return 0;
}

Open in new window

It prints
failed (1072260000 is not equal to 1072263600)

Open in new window

It means that the times are off exactly 3600 seconds, that is exactly one hour.

Where is the bug? I thought that both functions work with UTC time, or at least with the same way (with local time). How can I fix it?

I am using Windows 7, Visual Studio C++ 2013, and the file system is NTFS. I am from Czech that should have GMT+1, and Daylight Saving Time is applied.

Thanks,
  Petr
0
Comment
Question by:pepr
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
5 Comments
 
LVL 86

Accepted Solution

by:
jkr earned 2000 total points
ID: 39993062
Stupid question: Since you're on Windows, why don't you use 'SetFileTime()' (http://msdn.microsoft.com/en-us/library/windows/desktop/ms724933(v=vs.85).aspx) instead?
0
 
LVL 29

Author Comment

by:pepr
ID: 39993452
There are several reasons. The code was actually cut from a library that wraps the time functions. This is because I want to make it portable.

Another reason is that for the file, the function should return comparable value both on Unix and Windows.

So, the question remains. Why do I observe the one hour difference? Is the bug in my code or is it on Windows side?

I would almost swear that the unit test passed earlier. I know it was last tested before switching to DST this year. Because of that I suspect that I should make a correction when DST is used. But this is just a blind guess.
0
 
LVL 29

Author Comment

by:pepr
ID: 39993687
The same code with simplified testing (asserts only; should be more readable) and the corrected comment:
#include <cassert>
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main()
{
    string fname = { "test.data" };

    ofstream f(fname);
    f << "test content";
    f.close();

    // Check the existence of the created file.
    struct _stat stat;
    int result = _stat(fname.c_str(), &stat);
    assert(result == 0);
    assert((stat.st_mode & _S_IFREG) != 0);

    // The time to be used for testing.
    time_t christmas2003_t = 1072263600;   // 2003-12-24 11:00

    // Set the times of the file.
    struct _utimbuf ut;
    ut.actime = christmas2003_t;
    ut.modtime = christmas2003_t;

    result = _utime(fname.c_str(), &ut);
    assert(result != -1);

    // Get the modification time of the file (back).
    result = _stat(fname.c_str(), &stat);
    assert(result == 0);
    time_t mtime = stat.st_mtime;

    // Compare the two times.
    if (mtime == christmas2003_t)
        cout << "OK\n";
    else
        cout << "failed (" << mtime << " is not equal to " << christmas2003_t << ")\n";
    return 0;
}

Open in new window

It returns the same
failed (1072260000 is not equal to 1072263600)

Open in new window

0
 
LVL 29

Author Comment

by:pepr
ID: 39993908
Apparently, I am not the only one that has problems with the interpretation. See the captured screens. The cmd and Total Commander think differently about the time for the test.data file. However, the a.bak that was created manuall via an editor just now shows the same time. And it is a local time! (It was exactly 14:00 of the local time -- 00 minutes is only a pure coincidence. It really was tha time, and it is GMT + 2 because of the DST.)
Different times for test.data in cmd and TotalCommander, the same for a.bak.
0
 
LVL 29

Author Comment

by:pepr
ID: 39995941
@jkr: Thanks.

I have reimplemented my os::utime() function using the SetFileTime() function.

    void utime(const std::string & path, time_t actime, time_t modtime)
    {
        FILETIME ftLastAccessTime;
        timet_to_filetime(actime, ftLastAccessTime);

        FILETIME ftLastWriteTime;
        timet_to_filetime(actime, ftLastWriteTime);

        HANDLE hFile = CreateFile(path.c_str(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ,
            nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);

        if (hFile == INVALID_HANDLE_VALUE) {
            ostringstream ostr;
            ostr << __FUNCTION__ "(): CreateFile failed with " << GetLastError() << "\n";
            throw runtime_error(ostr.str());
        }

        if (!SetFileTime(hFile, nullptr, &ftLastAccessTime, &ftLastWriteTime)) {
            ostringstream ostr;
            ostr << __FUNCTION__ "(): SetFileTime failed with " << GetLastError() << "\n";
            CloseHandle(hFile);
            throw runtime_error(ostr.str());
        }

        CloseHandle(hFile);
    }

Open in new window

The timet_to_filetime() conversion function was found elsewhere:
    void timet_to_filetime(time_t t, FILETIME& ft)
    {
        LONGLONG ll = Int32x32To64(t, 10000000) + 116444736000000000;
        ft.dwLowDateTime = (DWORD) ll;
        ft.dwHighDateTime = ll >> 32;
    }

Open in new window

It seems that the problem was fixed. I will see a half year later when Daylight Saving Time is switched again.

If the implementation is correct, then Total commander shows a correct local time for the file (a it whas Christmas, the time was GMT+1). The dir utility shows wrong local time 13:00 instead of 12:00. Well, it depends on how we look at the problem.
0

Featured Post

Are You Using the Best Web Development Editor?

The worlds of web hosting and web development are constantly evolving. Every year we see design trends change, coding standards adapt and new frameworks/CMS created. With such a quick pace of change it’s easy to get lost trying to keep up.

See if your editor made the list.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

When asking a question in a forum or creating documentation, screenshots are vital tools that can convey a lot more information and save you and your reader a lot of time
In this post we will be converting StringData saved within a text file into a hash table. This can be further used in a PowerShell script for replacing settings that are dynamic in nature from environment to environment.
The Task Scheduler is a powerful tool that is built into Windows. It allows you to schedule tasks (actions) on a recurring basis, such as hourly, daily, weekly, monthly, at log on, at startup, on idle, etc. This video Micro Tutorial is a brief intro…
In this video, viewers will be given step by step instructions on adjusting mouse, pointer and cursor visibility in Microsoft Windows 10. The video seeks to educate those who are struggling with the new Windows 10 Graphical User Interface. Change Cu…

777 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question