|
|
@@ -0,0 +1,173 @@ |
|
|
|
module yitter.core.DateTimeHelper; |
|
|
|
|
|
|
|
import core.stdc.time; |
|
|
|
import std.datetime : convert; |
|
|
|
import std.string; |
|
|
|
|
|
|
|
enum TimeUnit : string { |
|
|
|
Year = "years", |
|
|
|
Month = "months", |
|
|
|
Week = "weeks", |
|
|
|
Day = "days", |
|
|
|
Hour = "hours", |
|
|
|
Second = "seconds", |
|
|
|
Millisecond = "msecs", |
|
|
|
Microsecond = "usecs", |
|
|
|
HectoNanosecond = "hnsecs", |
|
|
|
Nanosecond = "nsecs" |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* |
|
|
|
*/ |
|
|
|
class DateTimeHelper { |
|
|
|
/** |
|
|
|
* Returns the current time in milliseconds. Note that |
|
|
|
* while the unit of time of the return value is a millisecond, |
|
|
|
* the granularity of the value depends on the underlying |
|
|
|
* operating system and may be larger. For example, many |
|
|
|
* operating systems measure time in units of tens of |
|
|
|
* milliseconds. |
|
|
|
* |
|
|
|
* <p> See the description of the class {@code Date} for |
|
|
|
* a discussion of slight discrepancies that may arise between |
|
|
|
* "computer time" and coordinated universal time (UTC). |
|
|
|
* |
|
|
|
* @return the difference, measured in milliseconds, between |
|
|
|
* the current time and midnight, January 1, 1970 UTC. |
|
|
|
*/ |
|
|
|
static long currentTimeMillis() @trusted @property { |
|
|
|
return currentTime!(TimeUnit.Millisecond)(); |
|
|
|
} |
|
|
|
|
|
|
|
static long currentTimeNsecs() @trusted @property { |
|
|
|
return currentTime!(TimeUnit.Nanosecond)(); |
|
|
|
} |
|
|
|
|
|
|
|
static long currentUnixTime() @trusted @property { |
|
|
|
return currentTime!(TimeUnit.Second)(); |
|
|
|
} |
|
|
|
|
|
|
|
alias currentTimeSecond = currentUnixTime; |
|
|
|
|
|
|
|
/** |
|
|
|
* |
|
|
|
*/ |
|
|
|
static long currentTime(TimeUnit targetUnit)() @trusted @property { |
|
|
|
version (Windows) { |
|
|
|
import core.sys.windows.winbase; |
|
|
|
import core.sys.windows.winnt; |
|
|
|
|
|
|
|
/** |
|
|
|
http://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/ |
|
|
|
https://stackoverflow.com/questions/10849717/what-is-the-significance-of-january-1-1601 |
|
|
|
https://stackoverflow.com/questions/1090869/why-is-1-1-1970-the-epoch-time |
|
|
|
https://www.unixtimestamp.com/ |
|
|
|
*/ |
|
|
|
FILETIME fileTime; |
|
|
|
GetSystemTimeAsFileTime(&fileTime); |
|
|
|
ULARGE_INTEGER date, adjust; |
|
|
|
date.HighPart = fileTime.dwHighDateTime; |
|
|
|
date.LowPart = fileTime.dwLowDateTime; |
|
|
|
|
|
|
|
// 100-nanoseconds = milliseconds * 10000 |
|
|
|
adjust.QuadPart = 11644473600000 * 10000; |
|
|
|
|
|
|
|
// removes the diff between 1970 and 1601 |
|
|
|
date.QuadPart -= adjust.QuadPart; |
|
|
|
|
|
|
|
// converts back from 100-nanoseconds to milliseconds |
|
|
|
return convert!(TimeUnit.HectoNanosecond, targetUnit)(date.QuadPart); |
|
|
|
|
|
|
|
} else version (Posix) { |
|
|
|
import core.sys.posix.signal : timespec; |
|
|
|
version (OSX) { |
|
|
|
import core.sys.posix.sys.time : gettimeofday, timeval; |
|
|
|
|
|
|
|
timeval tv = void; |
|
|
|
// Posix gettimeofday called with a valid timeval address |
|
|
|
// and a null second parameter doesn't fail. |
|
|
|
gettimeofday(&tv, null); |
|
|
|
return convert!(TimeUnit.Second, targetUnit)(tv.tv_sec) + |
|
|
|
convert!(TimeUnit.Microsecond, targetUnit)(tv.tv_usec); |
|
|
|
|
|
|
|
} else version (linux) { |
|
|
|
import core.sys.linux.time : CLOCK_REALTIME_COARSE; |
|
|
|
import core.sys.posix.time : clock_gettime, CLOCK_REALTIME; |
|
|
|
|
|
|
|
timespec ts = void; |
|
|
|
immutable error = clock_gettime(CLOCK_REALTIME, &ts); |
|
|
|
// Posix clock_gettime called with a valid address and valid clock_id is only |
|
|
|
// permitted to fail if the number of seconds does not fit in time_t. If tv_sec |
|
|
|
// is long or larger overflow won't happen before 292 billion years A.D. |
|
|
|
static if (ts.tv_sec.max < long.max) { |
|
|
|
if (error) |
|
|
|
throw new TimeException("Call to clock_gettime() failed"); |
|
|
|
} |
|
|
|
return convert!(TimeUnit.Second, targetUnit)(ts.tv_sec) + |
|
|
|
convert!(TimeUnit.Nanosecond, targetUnit)(ts.tv_nsec); |
|
|
|
|
|
|
|
} else version (FreeBSD) { |
|
|
|
import core.sys.freebsd.time : clock_gettime, CLOCK_REALTIME; |
|
|
|
|
|
|
|
timespec ts = void; |
|
|
|
immutable error = clock_gettime(CLOCK_REALTIME, &ts); |
|
|
|
// Posix clock_gettime called with a valid address and valid clock_id is only |
|
|
|
// permitted to fail if the number of seconds does not fit in time_t. If tv_sec |
|
|
|
// is long or larger overflow won't happen before 292 billion years A.D. |
|
|
|
static if (ts.tv_sec.max < long.max) { |
|
|
|
if (error) |
|
|
|
throw new TimeException("Call to clock_gettime() failed"); |
|
|
|
} |
|
|
|
return convert!(TimeUnit.Second, targetUnit)(ts.tv_sec) + |
|
|
|
convert!(TimeUnit.Nanosecond, targetUnit)(ts.tv_nsec); |
|
|
|
} else version (NetBSD) { |
|
|
|
import core.sys.netbsd.time : clock_gettime, CLOCK_REALTIME; |
|
|
|
|
|
|
|
timespec ts = void; |
|
|
|
immutable error = clock_gettime(CLOCK_REALTIME, &ts); |
|
|
|
// Posix clock_gettime called with a valid address and valid clock_id is only |
|
|
|
// permitted to fail if the number of seconds does not fit in time_t. If tv_sec |
|
|
|
// is long or larger overflow won't happen before 292 billion years A.D. |
|
|
|
static if (ts.tv_sec.max < long.max) { |
|
|
|
if (error) |
|
|
|
throw new TimeException("Call to clock_gettime() failed"); |
|
|
|
} |
|
|
|
return convert!(TimeUnit.Second, targetUnit)(ts.tv_sec) + |
|
|
|
convert!(TimeUnit.Nanosecond, targetUnit)(ts.tv_nsec); |
|
|
|
} else version (DragonFlyBSD) { |
|
|
|
import core.sys.dragonflybsd.time : clock_gettime, CLOCK_REALTIME; |
|
|
|
|
|
|
|
timespec ts = void; |
|
|
|
immutable error = clock_gettime(CLOCK_REALTIME, &ts); |
|
|
|
// Posix clock_gettime called with a valid address and valid clock_id is only |
|
|
|
// permitted to fail if the number of seconds does not fit in time_t. If tv_sec |
|
|
|
// is long or larger overflow won't happen before 292 billion years A.D. |
|
|
|
static if (ts.tv_sec.max < long.max) { |
|
|
|
if (error) |
|
|
|
throw new TimeException("Call to clock_gettime() failed"); |
|
|
|
} |
|
|
|
return convert!(TimeUnit.Second, targetUnit)(ts.tv_sec) + |
|
|
|
convert!(TimeUnit.Nanosecond, targetUnit)(ts.tv_nsec); |
|
|
|
} else version (Solaris) { |
|
|
|
import core.sys.solaris.time : clock_gettime, CLOCK_REALTIME; |
|
|
|
|
|
|
|
timespec ts = void; |
|
|
|
immutable error = clock_gettime(CLOCK_REALTIME, &ts); |
|
|
|
// Posix clock_gettime called with a valid address and valid clock_id is only |
|
|
|
// permitted to fail if the number of seconds does not fit in time_t. If tv_sec |
|
|
|
// is long or larger overflow won't happen before 292 billion years A.D. |
|
|
|
static if (ts.tv_sec.max < long.max) { |
|
|
|
if (error) |
|
|
|
throw new TimeException("Call to clock_gettime() failed"); |
|
|
|
} |
|
|
|
return convert!(TimeUnit.Second, targetUnit)(ts.tv_sec) + |
|
|
|
convert!(TimeUnit.Nanosecond, targetUnit)(ts.tv_nsec); |
|
|
|
} else |
|
|
|
static assert(0, "Unsupported OS"); |
|
|
|
} else |
|
|
|
static assert(0, "Unsupported OS"); |
|
|
|
} |
|
|
|
|
|
|
|
} |