Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 48 additions & 3 deletions std/datetime.d
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ else version(Posix)
{
import core.sys.posix.stdlib;
import core.sys.posix.sys.time;
import core.sys.posix.signal : timespec;
}

version(unittest)
Expand Down Expand Up @@ -2662,6 +2663,50 @@ public:
}


version(StdDdoc)
{
private struct timespec {}
/++
Returns a $(D timespec) which represents this $(LREF SysTime).

$(BLUE This function is Posix-Only.)
+/
timespec toTimeSpec() @safe const pure nothrow;
}
else
version(Posix)
{
timespec toTimeSpec() @safe const pure nothrow
{
immutable tv_sec = toUnixTime!(typeof(timespec.tv_sec))();
immutable fracHNSecs = removeUnitsFromHNSecs!"seconds"(_stdTime - 621_355_968_000_000_000L);
immutable tv_nsec = cast(typeof(timespec.tv_nsec))convert!("hnsecs", "nsecs")(fracHNSecs);
return timespec(tv_sec, tv_nsec);
}

unittest
{
assert(SysTime(DateTime(1970, 1, 1), UTC()).toTimeSpec() == timespec(0, 0));
assert(SysTime(DateTime(1970, 1, 1), hnsecs(9), UTC()).toTimeSpec() == timespec(0, 900));
assert(SysTime(DateTime(1970, 1, 1), hnsecs(10), UTC()).toTimeSpec() == timespec(0, 1000));
assert(SysTime(DateTime(1970, 1, 1), usecs(7), UTC()).toTimeSpec() == timespec(0, 7000));

assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toTimeSpec() == timespec(1, 0));
assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(9), UTC()).toTimeSpec() == timespec(1, 900));
assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(10), UTC()).toTimeSpec() == timespec(1, 1000));
assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), usecs(7), UTC()).toTimeSpec() == timespec(1, 7000));

assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toTimeSpec() == timespec(0, -100));
assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_990), UTC()).toTimeSpec() == timespec(0, -1000));

assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toTimeSpec() == timespec(0, -1_000));
assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999), UTC()).toTimeSpec() == timespec(0, -999_001_000));
assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toTimeSpec() == timespec(0, -1_000_000));
assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toTimeSpec() == timespec(-1, 0));
assert(SysTime(DateTime(1969, 12, 31, 23, 59, 58), usecs(17), UTC()).toTimeSpec() == timespec(-1, -999_983_000));
}
}

/++
Returns a $(D tm) which represents this $(LREF SysTime).
+/
Expand Down Expand Up @@ -27436,7 +27481,7 @@ public:
}

unittest
{
{
assert(LocalTime().stdName !is null);

version(Posix)
Expand Down Expand Up @@ -27507,7 +27552,7 @@ public:
}

unittest
{
{
assert(LocalTime().dstName !is null);

version(Posix)
Expand Down Expand Up @@ -27573,7 +27618,7 @@ public:
}

unittest
{
{
LocalTime().hasDST;

version(Posix)
Expand Down
133 changes: 106 additions & 27 deletions std/file.d
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,28 @@ unittest
}


// Reads a time field from a stat_t with full precision.
version(Posix)
private SysTime statTimeToStdTime(char which)(ref stat_t statbuf)
{
auto unixTime = mixin(`statbuf.st_` ~ which ~ `time`);
long stdTime = unixTimeToStdTime(unixTime);

static if (is(typeof(mixin(`statbuf.st_` ~ which ~ `tim`))))
stdTime += mixin(`statbuf.st_` ~ which ~ `tim.tv_nsec`) / 100;
else
static if (is(typeof(mixin(`statbuf.st_` ~ which ~ `timensec`))))
stdTime += mixin(`statbuf.st_` ~ which ~ `timensec`) / 100;
else
static if (is(typeof(mixin(`statbuf.st_` ~ which ~ `time_nsec`))))
stdTime += mixin(`statbuf.st_` ~ which ~ `time_nsec`) / 100;
else
static if (is(typeof(mixin(`statbuf.__st_` ~ which ~ `timensec`))))
stdTime += mixin(`statbuf.__st_` ~ which ~ `timensec`) / 100;

return SysTime(stdTime);
}

/++
Get the access and modified times of file or folder $(D name).

Expand Down Expand Up @@ -863,8 +885,8 @@ void getTimes(R)(R name,
string names = null;
cenforce(trustedStat(namez, statbuf) == 0, names, namez);

accessTime = SysTime(unixTimeToStdTime(statbuf.st_atime));
modificationTime = SysTime(unixTimeToStdTime(statbuf.st_mtime));
accessTime = statTimeToStdTime!'a'(statbuf);
modificationTime = statTimeToStdTime!'m'(statbuf);
}
}

Expand Down Expand Up @@ -1127,20 +1149,40 @@ void setTimes(R)(R name,
else version(Posix)
{
auto namez = name.tempCString!FSChar();
static auto trustedUtimes(const(FSChar)* namez, const ref timeval[2] times) @trusted
static if (is(typeof(&utimensat)))
{
return utimes(namez, times);
}
timeval[2] t = void;
static auto trustedUtimensat(int fd, const(FSChar)* namez, const ref timespec[2] times, int flags) @trusted
{
return utimensat(fd, namez, times, flags);
}
timespec[2] t = void;

t[0] = accessTime.toTimeVal();
t[1] = modificationTime.toTimeVal();
t[0] = accessTime.toTimeSpec();
t[1] = modificationTime.toTimeSpec();

static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char))
alias names = name;
static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char))
alias names = name;
else
string names = null;
cenforce(trustedUtimensat(AT_FDCWD, namez, t, 0) == 0, names, namez);
}
else
string names = null;
cenforce(trustedUtimes(namez, t) == 0, names, namez);
{
static auto trustedUtimes(const(FSChar)* namez, const ref timeval[2] times) @trusted
{
return utimes(namez, times);
}
timeval[2] t = void;

t[0] = accessTime.toTimeVal();
t[1] = modificationTime.toTimeVal();

static if (isNarrowString!R && is(Unqual!(ElementEncodingType!R) == char))
alias names = name;
else
string names = null;
cenforce(trustedUtimes(namez, t) == 0, names, namez);
}
}
}

Expand All @@ -1154,7 +1196,8 @@ void setTimes(R)(auto ref R name,

@safe unittest
{
static assert(__traits(compiles, setTimes(TestAliasedString("foo"), SysTime.init, SysTime.init)));
if (false) // Test instatiation
setTimes(TestAliasedString("foo"), SysTime.init, SysTime.init);
}

unittest
Expand All @@ -1167,19 +1210,26 @@ unittest
if (!exists(dir)) mkdirRecurse(dir);
{ auto f = File(file, "w"); }

foreach (path; [file, dir]) // test file and dir
void testTimes(int hnsecValue)
{
SysTime atime = SysTime(DateTime(2010, 10, 4, 0, 0, 30));
SysTime mtime = SysTime(DateTime(2011, 10, 4, 0, 0, 30));
setTimes(path, atime, mtime);
foreach (path; [file, dir]) // test file and dir
{
SysTime atime = SysTime(DateTime(2010, 10, 4, 0, 0, 30), hnsecs(hnsecValue));
SysTime mtime = SysTime(DateTime(2011, 10, 4, 0, 0, 30), hnsecs(hnsecValue));
setTimes(path, atime, mtime);

SysTime atime_res;
SysTime mtime_res;
getTimes(path, atime_res, mtime_res);
assert(atime == atime_res);
assert(mtime == mtime_res);
SysTime atime_res;
SysTime mtime_res;
getTimes(path, atime_res, mtime_res);
assert(atime == atime_res);
assert(mtime == mtime_res);
}
}

testTimes(0);
version (linux)
testTimes(123_456_7);

rmdirRecurse(newdir);
}

Expand Down Expand Up @@ -1217,7 +1267,7 @@ SysTime timeLastModified(R)(R name)
string names = null;
cenforce(trustedStat(namez, statbuf) == 0, names, namez);

return SysTime(unixTimeToStdTime(statbuf.st_mtime));
return statTimeToStdTime!'m'(statbuf);
}
}

Expand Down Expand Up @@ -1288,7 +1338,7 @@ SysTime timeLastModified(R)(R name, SysTime returnIfMissing)

return trustedStat(namez, statbuf) != 0 ?
returnIfMissing :
SysTime(unixTimeToStdTime(statbuf.st_mtime));
statTimeToStdTime!'m'(statbuf);
}
}

Expand All @@ -1312,6 +1362,35 @@ unittest
}


// Tests sub-second precision of querying file times.
// Should pass on most modern systems running on modern filesystems.
// Exceptions:
// - FreeBSD, where one would need to first set the
// vfs.timestamp_precision sysctl to a value greater than zero.
// - OS X, where the native filesystem (HFS+) stores filesystem
// timestamps with 1-second precision.
version (FreeBSD) {} else
version (OSX) {} else
unittest
{
import core.thread;

if(exists(deleteme))
remove(deleteme);

SysTime lastTime;
foreach (n; 0..3)
{
write(deleteme, "a");
auto time = timeLastModified(deleteme);
remove(deleteme);
assert(time != lastTime);
lastTime = time;
Thread.sleep(10.msecs);
}
}


/**
* Determine whether the given file (or directory) exists.
* Params:
Expand Down Expand Up @@ -2844,21 +2923,21 @@ else version(Posix)
{
_ensureStatDone();

return SysTime(unixTimeToStdTime(_statBuf.st_ctime));
return statTimeToStdTime!'c'(_statBuf);
}

@property SysTime timeLastAccessed()
{
_ensureStatDone();

return SysTime(unixTimeToStdTime(_statBuf.st_ctime));
return statTimeToStdTime!'a'(_statBuf);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a bug here (ctime instead of atime).

}

@property SysTime timeLastModified()
{
_ensureStatDone();

return SysTime(unixTimeToStdTime(_statBuf.st_mtime));
return statTimeToStdTime!'m'(_statBuf);
}

@property uint attributes()
Expand Down