Copyright (C) Andrew Tridgell 1992-2004
Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Jeremy Allison 2007
+ Copyright (C) Andrew Bartlett 2011
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "includes.h"
+#include "replace.h"
#include "system/time.h"
+#include "byteorder.h"
+#include "time_basic.h"
+#include "lib/util/time.h" /* Avoid /usr/include/time.h */
/**
* @file
* @brief time handling functions
*/
-#ifndef TIME_T_MIN
-/* we use 0 here, because (time_t)-1 means error */
-#define TIME_T_MIN 0
+#if (SIZEOF_LONG == 8)
+#define TIME_FIXUP_CONSTANT_INT 11644473600L
+#elif (SIZEOF_LONG_LONG == 8)
+#define TIME_FIXUP_CONSTANT_INT 11644473600LL
#endif
-/*
- * we use the INT32_MAX here as on 64 bit systems,
- * gmtime() fails with INT64_MAX
- */
-#ifndef TIME_T_MAX
-#define TIME_T_MAX MIN(INT32_MAX,_TYPE_MAXIMUM(time_t))
-#endif
/**
External access to time_t_min and time_t_max.
}
/**
-a gettimeofday wrapper
+a wrapper to preferably get the monotonic time
**/
-_PUBLIC_ void GetTimeOfDay(struct timeval *tval)
+_PUBLIC_ void clock_gettime_mono(struct timespec *tp)
{
-#ifdef HAVE_GETTIMEOFDAY_TZ
- gettimeofday(tval,NULL);
-#else
- gettimeofday(tval);
+/* prefer a suspend aware monotonic CLOCK_BOOTTIME: */
+#ifdef CLOCK_BOOTTIME
+ if (clock_gettime(CLOCK_BOOTTIME,tp) == 0) {
+ return;
+ }
#endif
+/* then try the monotonic clock: */
+#if CUSTOM_CLOCK_MONOTONIC != CLOCK_REALTIME
+ if (clock_gettime(CUSTOM_CLOCK_MONOTONIC,tp) == 0) {
+ return;
+ }
+#endif
+ clock_gettime(CLOCK_REALTIME,tp);
}
-
-#define TIME_FIXUP_CONSTANT 11644473600LL
-
/**
-interpret an 8 byte "filetime" structure to a time_t
-It's originally in "100ns units since jan 1st 1601"
+a wrapper to preferably get the monotonic time in seconds
**/
-_PUBLIC_ time_t nt_time_to_unix(NTTIME nt)
+_PUBLIC_ time_t time_mono(time_t *t)
{
- if (nt == 0) {
- return 0;
+ struct timespec tp;
+
+ clock_gettime_mono(&tp);
+ if (t != NULL) {
+ *t = tp.tv_sec;
}
- if (nt == -1LL) {
- return (time_t)-1;
+ return tp.tv_sec;
+}
+
+
+#define TIME_FIXUP_CONSTANT 11644473600LL
+
+time_t convert_timespec_to_time_t(struct timespec ts)
+{
+ /* Ensure tv_nsec is less than 1sec. */
+ while (ts.tv_nsec > 1000000000) {
+ ts.tv_sec += 1;
+ ts.tv_nsec -= 1000000000;
}
- nt += 1000*1000*10/2;
- nt /= 1000*1000*10;
- nt -= TIME_FIXUP_CONSTANT;
- if (TIME_T_MIN > nt || nt > TIME_T_MAX) {
- return 0;
+ /* 1 ns == 1,000,000,000 - one thousand millionths of a second.
+ increment if it's greater than 500 millionth of a second. */
+
+ if (ts.tv_nsec > 500000000) {
+ return ts.tv_sec + 1;
}
+ return ts.tv_sec;
+}
- return (time_t)nt;
+struct timespec convert_time_t_to_timespec(time_t t)
+{
+ struct timespec ts;
+ ts.tv_sec = t;
+ ts.tv_nsec = 0;
+ return ts;
+}
+
+
+
+/**
+ Interpret an 8 byte "filetime" structure to a time_t
+ It's originally in "100ns units since jan 1st 1601"
+
+ An 8 byte value of 0xffffffffffffffff will be returned as a timespec of
+
+ tv_sec = 0
+ tv_nsec = 0;
+
+ Returns GMT.
+**/
+time_t nt_time_to_unix(NTTIME nt)
+{
+ return convert_timespec_to_time_t(nt_time_to_unix_timespec(nt));
}
if (t == (time_t)-1) {
*nt = (NTTIME)-1LL;
return;
- }
+ }
+
+ if (t == TIME_T_MAX || t == INT64_MAX) {
+ *nt = 0x7fffffffffffffffLL;
+ return;
+ }
+
if (t == 0) {
*nt = 0;
return;
}
t2 = t;
- t2 += TIME_FIXUP_CONSTANT;
+ t2 += TIME_FIXUP_CONSTANT_INT;
t2 *= 1000*1000*10;
*nt = t2;
/*******************************************************************
interpret a 32 bit dos packed date/time to some parameters
********************************************************************/
-static void interpret_dos_date(uint32_t date,int *year,int *month,int *day,int *hour,int *minute,int *second)
+void interpret_dos_date(uint32_t date,int *year,int *month,int *day,int *hour,int *minute,int *second)
{
uint32_t p0,p1,p2,p3;
return t;
}
+/****************************************************************************
+ Return the date and time as a string
+****************************************************************************/
+
+char *timeval_string(TALLOC_CTX *ctx, const struct timeval *tp, bool hires)
+{
+ struct timeval_buf tmp;
+ char *result;
+
+ result = talloc_strdup(ctx, timeval_str_buf(tp, hires, &tmp));
+ if (result == NULL) {
+ return NULL;
+ }
+
+ /*
+ * beautify the talloc_report output
+ *
+ * This is not just cosmetics. A C compiler might in theory make the
+ * talloc_strdup call above a tail call with the tail call
+ * optimization. This would render "tmp" invalid while talloc_strdup
+ * tries to duplicate it. The talloc_set_name_const call below puts
+ * the talloc_strdup call into non-tail position.
+ */
+ talloc_set_name_const(result, result);
+ return result;
+}
+
+char *current_timestring(TALLOC_CTX *ctx, bool hires)
+{
+ struct timeval tv;
+
+ GetTimeOfDay(&tv);
+ return timeval_string(ctx, &tv, hires);
+}
+
/**
return a HTTP/1.0 time string
char tempTime[60];
struct tm *tm = localtime(&t);
+ if (t == TIME_T_MAX) {
+ return talloc_strdup(mem_ctx, "never");
+ }
+
if (!tm) {
return talloc_asprintf(mem_ctx,"%ld seconds since the Epoch",(long)t);
}
}
#ifdef HAVE_STRFTIME
- /* some versions of gcc complain about using %c. This is a bug
- in the gcc warning, not a bug in this code. See a recent
- strftime() manual page for details.
- */
- strftime(tempTime,sizeof(tempTime)-1,"%c %Z",tm);
+ /* Some versions of gcc complain about using some special format
+ * specifiers. This is a bug in gcc, not a bug in this code. See a
+ * recent strftime() manual page for details. */
+ strftime(tempTime,sizeof(tempTime)-1,"%a %b %e %X %Y %Z",tm);
TimeBuf = talloc_strdup(mem_ctx, tempTime);
#else
TimeBuf = talloc_strdup(mem_ctx, asctime(tm));
+ if (TimeBuf == NULL) {
+ return NULL;
+ }
+ if (TimeBuf[0] != '\0') {
+ size_t len = strlen(TimeBuf);
+ if (TimeBuf[len - 1] == '\n') {
+ TimeBuf[len - 1] = '\0';
+ }
+ }
#endif
return TimeBuf;
return (sec_diff * 1000000) + (int64_t)(tv1->tv_usec - tv2->tv_usec);
}
+/**
+ return (tp1 - tp2) in microseconds
+*/
+_PUBLIC_ int64_t nsec_time_diff(const struct timespec *tp1, const struct timespec *tp2)
+{
+ int64_t sec_diff = tp1->tv_sec - tp2->tv_sec;
+ return (sec_diff * 1000000000) + (int64_t)(tp1->tv_nsec - tp2->tv_nsec);
+}
+
/**
return a zero timeval
return timeval_add(&tv, secs, usecs);
}
+/**
+ return a timeval milliseconds into the future
+*/
+_PUBLIC_ struct timeval timeval_current_ofs_msec(uint32_t msecs)
+{
+ struct timeval tv = timeval_current();
+ return timeval_add(&tv, msecs / 1000, (msecs % 1000) * 1000);
+}
+
+/**
+ return a timeval microseconds into the future
+*/
+_PUBLIC_ struct timeval timeval_current_ofs_usec(uint32_t usecs)
+{
+ struct timeval tv = timeval_current();
+ return timeval_add(&tv, usecs / 1000000, usecs % 1000000);
+}
+
/**
compare two timeval structures.
Return -1 if tv1 < tv2
struct timeval tv2 = timeval_current();
return timeval_elapsed2(tv, &tv2);
}
+/**
+ * return the number of seconds elapsed between two times
+ **/
+_PUBLIC_ double timespec_elapsed2(const struct timespec *ts1,
+ const struct timespec *ts2)
+{
+ return (ts2->tv_sec - ts1->tv_sec) +
+ (ts2->tv_nsec - ts1->tv_nsec)*1.0e-9;
+}
+
+/**
+ * return the number of seconds elapsed since a given time
+ */
+_PUBLIC_ double timespec_elapsed(const struct timespec *ts)
+{
+ struct timespec ts2 = timespec_current();
+ return timespec_elapsed2(ts, &ts2);
+}
/**
return the lesser of two timevals
return seconds;
}
+
/**
return the UTC offset in seconds west of UTC, or 0 if it cannot be determined
*/
return tm_diff(&tm_utc,tm);
}
+struct timespec nt_time_to_unix_timespec(NTTIME nt)
+{
+ int64_t d;
+ struct timespec ret;
+
+ if (nt == 0 || nt == (int64_t)-1) {
+ ret.tv_sec = 0;
+ ret.tv_nsec = 0;
+ return ret;
+ }
+
+ d = (int64_t)nt;
+ /* d is now in 100ns units, since jan 1st 1601".
+ Save off the ns fraction. */
+
+ /*
+ * Take the last seven decimal digits and multiply by 100.
+ * to convert from 100ns units to 1ns units.
+ */
+ ret.tv_nsec = (long) ((d % (1000 * 1000 * 10)) * 100);
+
+ /* Convert to seconds */
+ d /= 1000*1000*10;
+
+ /* Now adjust by 369 years to make the secs since 1970 */
+ d -= TIME_FIXUP_CONSTANT_INT;
+
+ if (d <= (int64_t)TIME_T_MIN) {
+ ret.tv_sec = TIME_T_MIN;
+ ret.tv_nsec = 0;
+ return ret;
+ }
+
+ if (d >= (int64_t)TIME_T_MAX) {
+ ret.tv_sec = TIME_T_MAX;
+ ret.tv_nsec = 0;
+ return ret;
+ }
+
+ ret.tv_sec = (time_t)d;
+ return ret;
+}
+
+
/**
check if 2 NTTIMEs are equal.
*/
{
return *t1 == *t2;
}
+
+/**
+ Check if it's a null timespec.
+**/
+
+bool null_timespec(struct timespec ts)
+{
+ return ts.tv_sec == 0 ||
+ ts.tv_sec == (time_t)0xFFFFFFFF ||
+ ts.tv_sec == (time_t)-1;
+}
+
+/****************************************************************************
+ Convert a normalized timeval to a timespec.
+****************************************************************************/
+
+struct timespec convert_timeval_to_timespec(const struct timeval tv)
+{
+ struct timespec ts;
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = tv.tv_usec * 1000;
+ return ts;
+}
+
+/****************************************************************************
+ Convert a normalized timespec to a timeval.
+****************************************************************************/
+
+struct timeval convert_timespec_to_timeval(const struct timespec ts)
+{
+ struct timeval tv;
+ tv.tv_sec = ts.tv_sec;
+ tv.tv_usec = ts.tv_nsec / 1000;
+ return tv;
+}
+
+/****************************************************************************
+ Return a timespec for the current time
+****************************************************************************/
+
+_PUBLIC_ struct timespec timespec_current(void)
+{
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ return ts;
+}
+
+/****************************************************************************
+ Return the lesser of two timespecs.
+****************************************************************************/
+
+struct timespec timespec_min(const struct timespec *ts1,
+ const struct timespec *ts2)
+{
+ if (ts1->tv_sec < ts2->tv_sec) return *ts1;
+ if (ts1->tv_sec > ts2->tv_sec) return *ts2;
+ if (ts1->tv_nsec < ts2->tv_nsec) return *ts1;
+ return *ts2;
+}
+
+/****************************************************************************
+ compare two timespec structures.
+ Return -1 if ts1 < ts2
+ Return 0 if ts1 == ts2
+ Return 1 if ts1 > ts2
+****************************************************************************/
+
+_PUBLIC_ int timespec_compare(const struct timespec *ts1, const struct timespec *ts2)
+{
+ if (ts1->tv_sec > ts2->tv_sec) return 1;
+ if (ts1->tv_sec < ts2->tv_sec) return -1;
+ if (ts1->tv_nsec > ts2->tv_nsec) return 1;
+ if (ts1->tv_nsec < ts2->tv_nsec) return -1;
+ return 0;
+}
+
+/****************************************************************************
+ Round up a timespec if nsec > 500000000, round down if lower,
+ then zero nsec.
+****************************************************************************/
+
+void round_timespec_to_sec(struct timespec *ts)
+{
+ ts->tv_sec = convert_timespec_to_time_t(*ts);
+ ts->tv_nsec = 0;
+}
+
+/****************************************************************************
+ Round a timespec to usec value.
+****************************************************************************/
+
+void round_timespec_to_usec(struct timespec *ts)
+{
+ struct timeval tv = convert_timespec_to_timeval(*ts);
+ *ts = convert_timeval_to_timespec(tv);
+ while (ts->tv_nsec > 1000000000) {
+ ts->tv_sec += 1;
+ ts->tv_nsec -= 1000000000;
+ }
+}
+
+/****************************************************************************
+ Put a 8 byte filetime from a struct timespec. Uses GMT.
+****************************************************************************/
+
+_PUBLIC_ NTTIME unix_timespec_to_nt_time(struct timespec ts)
+{
+ uint64_t d;
+
+ if (ts.tv_sec ==0 && ts.tv_nsec == 0) {
+ return 0;
+ }
+ if (ts.tv_sec == TIME_T_MAX) {
+ return 0x7fffffffffffffffLL;
+ }
+ if (ts.tv_sec == (time_t)-1) {
+ return (uint64_t)-1;
+ }
+
+ d = ts.tv_sec;
+ d += TIME_FIXUP_CONSTANT_INT;
+ d *= 1000*1000*10;
+ /* d is now in 100ns units. */
+ d += (ts.tv_nsec / 100);
+
+ return d;
+}