2003-08-13 05:53:07 +04:00
/*
Unix SMB / CIFS implementation .
time handling functions
2004-04-11 00:18:22 +04:00
Copyright ( C ) Andrew Tridgell 1992 - 2004
2003-08-13 05:53:07 +04:00
Copyright ( C ) Stefan ( metze ) Metzmacher 2002
2011-02-22 09:59:51 +03:00
Copyright ( C ) Jeremy Allison 2007
Copyright ( C ) Andrew Bartlett 2011
2004-04-11 00:18:22 +04:00
2003-08-13 05:53:07 +04:00
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
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2003-08-13 05:53:07 +04:00
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2003-08-13 05:53:07 +04:00
*/
# include "includes.h"
2004-11-02 03:24:21 +03:00
# include "system/time.h"
2003-08-13 05:53:07 +04:00
2006-02-28 16:12:39 +03:00
/**
* @ file
* @ brief time handling functions
*/
2008-10-12 01:57:44 +04:00
# if (SIZEOF_LONG == 8)
# define TIME_FIXUP_CONSTANT_INT 11644473600L
# elif (SIZEOF_LONG_LONG == 8)
# define TIME_FIXUP_CONSTANT_INT 11644473600LL
# endif
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
External access to time_t_min and time_t_max .
2006-02-28 16:12:39 +03:00
* */
2006-03-05 20:15:19 +03:00
_PUBLIC_ time_t get_time_t_max ( void )
2003-08-13 05:53:07 +04:00
{
return TIME_T_MAX ;
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
a gettimeofday wrapper
2006-02-28 16:12:39 +03:00
* */
2006-03-05 20:15:19 +03:00
_PUBLIC_ void GetTimeOfDay ( struct timeval * tval )
2003-08-13 05:53:07 +04:00
{
# ifdef HAVE_GETTIMEOFDAY_TZ
gettimeofday ( tval , NULL ) ;
# else
gettimeofday ( tval ) ;
# endif
}
2010-08-30 14:10:29 +04:00
/**
a wrapper to preferably get the monotonic time
* */
_PUBLIC_ void clock_gettime_mono ( struct timespec * tp )
{
2013-07-03 20:57:57 +04:00
/* prefer a suspend aware monotonic CLOCK_BOOTTIME: */
# ifdef CLOCK_BOOTTIME
if ( clock_gettime ( CLOCK_BOOTTIME , tp ) = = 0 ) {
return ;
2010-08-30 14:10:29 +04:00
}
2013-07-03 20:57:57 +04:00
# 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 ) ;
2010-08-30 14:10:29 +04:00
}
2010-09-06 22:27:24 +04:00
/**
a wrapper to preferably get the monotonic time in seconds
* */
_PUBLIC_ time_t time_mono ( time_t * t )
{
struct timespec tp ;
2013-07-03 20:51:14 +04:00
clock_gettime_mono ( & tp ) ;
2010-09-06 22:27:24 +04:00
if ( t ! = NULL ) {
* t = tp . tv_sec ;
}
return tp . tv_sec ;
}
2003-08-13 05:53:07 +04:00
2004-05-25 17:57:39 +04:00
# define TIME_FIXUP_CONSTANT 11644473600LL
2003-08-13 05:53:07 +04:00
2008-10-12 01:57:44 +04:00
time_t convert_timespec_to_time_t ( struct timespec ts )
2003-08-13 05:53:07 +04:00
{
2010-09-15 01:53:17 +04:00
/* Ensure tv_nsec is less than 1sec. */
while ( ts . tv_nsec > 1000000000 ) {
ts . tv_sec + = 1 ;
ts . tv_nsec - = 1000000000 ;
}
2008-10-12 01:57:44 +04:00
/* 1 ns == 1,000,000,000 - one thousand millionths of a second.
increment if it ' s greater than 500 millionth of a second . */
2010-09-15 01:53:17 +04:00
2008-10-12 01:57:44 +04:00
if ( ts . tv_nsec > 500000000 ) {
return ts . tv_sec + 1 ;
2004-05-26 12:02:20 +04:00
}
2008-10-12 01:57:44 +04:00
return ts . tv_sec ;
}
2003-08-13 05:53:07 +04:00
2008-10-12 01:57:44 +04:00
struct timespec convert_time_t_to_timespec ( time_t t )
{
struct timespec ts ;
ts . tv_sec = t ;
ts . tv_nsec = 0 ;
return ts ;
}
2003-08-13 05:53:07 +04:00
2008-10-12 01:57:44 +04:00
/**
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 )
{
2014-06-18 16:21:06 +04:00
return convert_timespec_to_time_t ( nt_time_to_unix_timespec ( nt ) ) ;
2003-08-13 05:53:07 +04:00
}
2004-04-11 00:18:22 +04:00
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
put a 8 byte filetime from a time_t
2004-04-11 00:18:22 +04:00
This takes GMT as input
2006-02-28 16:12:39 +03:00
* */
2006-03-05 20:15:19 +03:00
_PUBLIC_ void unix_to_nt_time ( NTTIME * nt , time_t t )
2003-08-13 05:53:07 +04:00
{
2004-05-25 17:57:39 +04:00
uint64_t t2 ;
2003-08-13 05:53:07 +04:00
2004-05-25 17:57:39 +04:00
if ( t = = ( time_t ) - 1 ) {
* nt = ( NTTIME ) - 1LL ;
2003-08-13 05:53:07 +04:00
return ;
2008-10-12 01:57:44 +04:00
}
2012-05-07 13:21:10 +04:00
if ( t = = TIME_T_MAX | | t = = INT64_MAX ) {
2008-10-12 01:57:44 +04:00
* nt = 0x7fffffffffffffffLL ;
return ;
}
2004-05-25 17:57:39 +04:00
if ( t = = 0 ) {
* nt = 0 ;
2003-08-13 05:53:07 +04:00
return ;
}
2004-05-25 17:57:39 +04:00
t2 = t ;
2008-10-12 01:57:44 +04:00
t2 + = TIME_FIXUP_CONSTANT_INT ;
2004-05-25 17:57:39 +04:00
t2 * = 1000 * 1000 * 10 ;
2003-08-13 05:53:07 +04:00
2004-05-25 17:57:39 +04:00
* nt = t2 ;
2003-08-13 05:53:07 +04:00
}
2006-02-28 16:12:39 +03:00
/**
2004-10-26 09:35:26 +04:00
check if it ' s a null unix time
2006-02-28 16:12:39 +03:00
* */
2007-08-27 21:21:16 +04:00
_PUBLIC_ bool null_time ( time_t t )
2003-08-13 05:53:07 +04:00
{
2004-10-26 09:35:26 +04:00
return t = = 0 | |
t = = ( time_t ) 0xFFFFFFFF | |
t = = ( time_t ) - 1 ;
2003-08-13 05:53:07 +04:00
}
2005-03-06 01:50:13 +03:00
2006-02-28 16:12:39 +03:00
/**
2005-03-06 01:50:13 +03:00
check if it ' s a null NTTIME
2006-02-28 16:12:39 +03:00
* */
2007-08-27 21:21:16 +04:00
_PUBLIC_ bool null_nttime ( NTTIME t )
2005-03-06 01:50:13 +03:00
{
return t = = 0 | | t = = ( NTTIME ) - 1 ;
}
2003-08-13 05:53:07 +04:00
/*******************************************************************
create a 16 bit dos packed date
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-05-25 21:24:24 +04:00
static uint16_t make_dos_date1 ( struct tm * t )
2003-08-13 05:53:07 +04:00
{
2004-05-25 21:24:24 +04:00
uint16_t ret = 0 ;
2006-05-05 17:02:14 +04:00
ret = ( ( ( unsigned int ) ( t - > tm_mon + 1 ) ) > > 3 ) | ( ( t - > tm_year - 80 ) < < 1 ) ;
2003-08-13 05:53:07 +04:00
ret = ( ( ret & 0xFF ) < < 8 ) | ( t - > tm_mday | ( ( ( t - > tm_mon + 1 ) & 0x7 ) < < 5 ) ) ;
return ret ;
}
/*******************************************************************
create a 16 bit dos packed time
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-05-25 21:24:24 +04:00
static uint16_t make_dos_time1 ( struct tm * t )
2003-08-13 05:53:07 +04:00
{
2004-05-25 21:24:24 +04:00
uint16_t ret = 0 ;
2006-05-05 17:02:14 +04:00
ret = ( ( ( ( unsigned int ) t - > tm_min > > 3 ) & 0x7 ) | ( ( ( unsigned int ) t - > tm_hour ) < < 3 ) ) ;
2003-08-13 05:53:07 +04:00
ret = ( ( ret & 0xFF ) < < 8 ) | ( ( t - > tm_sec / 2 ) | ( ( t - > tm_min & 0x7 ) < < 5 ) ) ;
return ret ;
}
/*******************************************************************
create a 32 bit dos packed date / time from some parameters
This takes a GMT time and returns a packed localtime structure
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-05-25 20:24:13 +04:00
static uint32_t make_dos_date ( time_t unixdate , int zone_offset )
2003-08-13 05:53:07 +04:00
{
struct tm * t ;
2004-05-25 20:24:13 +04:00
uint32_t ret = 0 ;
2003-08-13 05:53:07 +04:00
if ( unixdate = = 0 ) {
return 0 ;
}
2004-04-11 00:18:22 +04:00
unixdate - = zone_offset ;
t = gmtime ( & unixdate ) ;
2003-08-13 05:53:07 +04:00
if ( ! t ) {
return 0xFFFFFFFF ;
}
ret = make_dos_date1 ( t ) ;
ret = ( ( ret & 0xFFFF ) < < 16 ) | make_dos_time1 ( t ) ;
return ret ;
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
put a dos date into a buffer ( time / date format )
This takes GMT time and puts local time in the buffer
2006-02-28 16:12:39 +03:00
* */
2006-03-05 20:15:19 +03:00
_PUBLIC_ void push_dos_date ( uint8_t * buf , int offset , time_t unixdate , int zone_offset )
2003-08-13 05:53:07 +04:00
{
2004-05-25 20:24:13 +04:00
uint32_t x = make_dos_date ( unixdate , zone_offset ) ;
2003-08-13 05:53:07 +04:00
SIVAL ( buf , offset , x ) ;
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
put a dos date into a buffer ( date / time format )
This takes GMT time and puts local time in the buffer
2006-02-28 16:12:39 +03:00
* */
2006-03-05 20:15:19 +03:00
_PUBLIC_ void push_dos_date2 ( uint8_t * buf , int offset , time_t unixdate , int zone_offset )
2003-08-13 05:53:07 +04:00
{
2004-05-25 20:24:13 +04:00
uint32_t x ;
2004-04-11 00:18:22 +04:00
x = make_dos_date ( unixdate , zone_offset ) ;
2003-08-13 05:53:07 +04:00
x = ( ( x & 0xFFFF ) < < 16 ) | ( ( x & 0xFFFF0000 ) > > 16 ) ;
SIVAL ( buf , offset , x ) ;
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
put a dos 32 bit " unix like " date into a buffer . This routine takes
GMT and converts it to LOCAL time before putting it ( most SMBs assume
localtime for this sort of date )
2006-02-28 16:12:39 +03:00
* */
2006-03-05 20:15:19 +03:00
_PUBLIC_ void push_dos_date3 ( uint8_t * buf , int offset , time_t unixdate , int zone_offset )
2003-08-13 05:53:07 +04:00
{
2004-10-26 09:35:26 +04:00
if ( ! null_time ( unixdate ) ) {
2004-04-11 00:18:22 +04:00
unixdate - = zone_offset ;
}
2003-08-13 05:53:07 +04:00
SIVAL ( buf , offset , unixdate ) ;
}
/*******************************************************************
interpret a 32 bit dos packed date / time to some parameters
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-10-12 01:57:44 +04:00
void interpret_dos_date ( uint32_t date , int * year , int * month , int * day , int * hour , int * minute , int * second )
2003-08-13 05:53:07 +04:00
{
2004-05-25 20:24:13 +04:00
uint32_t p0 , p1 , p2 , p3 ;
2003-08-13 05:53:07 +04:00
2004-04-11 00:18:22 +04:00
p0 = date & 0xFF ; p1 = ( ( date & 0xFF00 ) > > 8 ) & 0xFF ;
p2 = ( ( date & 0xFF0000 ) > > 16 ) & 0xFF ; p3 = ( ( date & 0xFF000000 ) > > 24 ) & 0xFF ;
2003-08-13 05:53:07 +04:00
2004-04-11 00:18:22 +04:00
* second = 2 * ( p0 & 0x1F ) ;
* minute = ( ( p0 > > 5 ) & 0xFF ) + ( ( p1 & 0x7 ) < < 3 ) ;
* hour = ( p1 > > 3 ) & 0xFF ;
* day = ( p2 & 0x1F ) ;
* month = ( ( p2 > > 5 ) & 0xFF ) + ( ( p3 & 0x1 ) < < 3 ) - 1 ;
* year = ( ( p3 > > 1 ) & 0xFF ) + 80 ;
2003-08-13 05:53:07 +04:00
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
create a unix date ( int GMT ) from a dos date ( which is actually in
localtime )
2006-02-28 16:12:39 +03:00
* */
2006-03-05 20:15:19 +03:00
_PUBLIC_ time_t pull_dos_date ( const uint8_t * date_ptr , int zone_offset )
2003-08-13 05:53:07 +04:00
{
2004-05-25 20:24:13 +04:00
uint32_t dos_date = 0 ;
2003-08-13 05:53:07 +04:00
struct tm t ;
time_t ret ;
dos_date = IVAL ( date_ptr , 0 ) ;
if ( dos_date = = 0 ) return ( time_t ) 0 ;
interpret_dos_date ( dos_date , & t . tm_year , & t . tm_mon ,
& t . tm_mday , & t . tm_hour , & t . tm_min , & t . tm_sec ) ;
t . tm_isdst = - 1 ;
2004-04-11 00:18:22 +04:00
ret = timegm ( & t ) ;
2003-08-13 05:53:07 +04:00
2004-04-11 00:18:22 +04:00
ret + = zone_offset ;
return ret ;
2003-08-13 05:53:07 +04:00
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
like make_unix_date ( ) but the words are reversed
2006-02-28 16:12:39 +03:00
* */
2006-03-05 20:15:19 +03:00
_PUBLIC_ time_t pull_dos_date2 ( const uint8_t * date_ptr , int zone_offset )
2003-08-13 05:53:07 +04:00
{
2004-05-25 20:24:13 +04:00
uint32_t x , x2 ;
2003-08-13 05:53:07 +04:00
x = IVAL ( date_ptr , 0 ) ;
x2 = ( ( x & 0xFFFF ) < < 16 ) | ( ( x & 0xFFFF0000 ) > > 16 ) ;
SIVAL ( & x , 0 , x2 ) ;
2007-09-07 19:08:14 +04:00
return pull_dos_date ( ( const uint8_t * ) & x , zone_offset ) ;
2003-08-13 05:53:07 +04:00
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
create a unix GMT date from a dos date in 32 bit " unix like " format
these generally arrive as localtimes , with corresponding DST
2006-02-28 16:12:39 +03:00
* */
2006-03-05 20:15:19 +03:00
_PUBLIC_ time_t pull_dos_date3 ( const uint8_t * date_ptr , int zone_offset )
2003-08-13 05:53:07 +04:00
{
time_t t = ( time_t ) IVAL ( date_ptr , 0 ) ;
2004-10-26 09:35:26 +04:00
if ( ! null_time ( t ) ) {
2004-04-11 00:18:22 +04:00
t + = zone_offset ;
}
2003-08-13 05:53:07 +04:00
return t ;
}
2014-07-29 18:43:39 +04:00
char * timeval_str_buf ( const struct timeval * tp , bool hires ,
struct timeval_buf * dst )
{
time_t t ;
struct tm * tm ;
size_t len ;
t = ( time_t ) tp - > tv_sec ;
tm = localtime ( & t ) ;
if ( tm = = NULL ) {
if ( hires ) {
snprintf ( dst - > buf , sizeof ( dst - > buf ) ,
" %ld.%06ld seconds since the Epoch " ,
( long ) tp - > tv_sec , ( long ) tp - > tv_usec ) ;
} else {
snprintf ( dst - > buf , sizeof ( dst - > buf ) ,
" %ld seconds since the Epoch " , ( long ) t ) ;
}
return dst - > buf ;
}
# ifdef HAVE_STRFTIME
len = strftime ( dst - > buf , sizeof ( dst - > buf ) , " %Y/%m/%d %H:%M:%S " , tm ) ;
# else
{
const char * asct = asctime ( tm ) ;
len = strlcpy ( dst - > buf , sizeof ( dst - > buf ) ,
asct ? asct : " unknown " ) ;
}
# endif
if ( hires & & ( len < sizeof ( dst - > buf ) ) ) {
snprintf ( dst - > buf + len , sizeof ( dst - > buf ) - len ,
" .%06ld " , ( long ) tp - > tv_usec ) ;
}
return dst - > buf ;
}
2011-02-22 09:59:51 +03:00
/****************************************************************************
Return the date and time as a string
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * timeval_string ( TALLOC_CTX * ctx , const struct timeval * tp , bool hires )
{
2014-07-29 18:52:42 +04:00
struct timeval_buf tmp ;
char * result ;
2011-02-22 09:59:51 +03:00
2014-07-29 18:52:42 +04:00
result = talloc_strdup ( ctx , timeval_str_buf ( tp , hires , & tmp ) ) ;
if ( result = = NULL ) {
return NULL ;
2011-02-22 09:59:51 +03:00
}
2014-07-29 18:52:42 +04:00
/*
* 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 ;
2011-02-22 09:59:51 +03:00
}
char * current_timestring ( TALLOC_CTX * ctx , bool hires )
{
struct timeval tv ;
GetTimeOfDay ( & tv ) ;
return timeval_string ( ctx , & tv , hires ) ;
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
return a HTTP / 1.0 time string
2006-02-28 16:12:39 +03:00
* */
2006-03-05 20:15:19 +03:00
_PUBLIC_ char * http_timestring ( TALLOC_CTX * mem_ctx , time_t t )
2003-08-13 05:53:07 +04:00
{
2004-04-11 00:18:22 +04:00
char * buf ;
char tempTime [ 60 ] ;
struct tm * tm = localtime ( & t ) ;
2008-10-12 01:57:44 +04:00
if ( t = = TIME_T_MAX ) {
return talloc_strdup ( mem_ctx , " never " ) ;
}
2004-04-11 00:18:22 +04:00
if ( ! tm ) {
return talloc_asprintf ( mem_ctx , " %ld seconds since the Epoch " , ( long ) t ) ;
}
2003-08-13 05:53:07 +04:00
# ifndef HAVE_STRFTIME
2004-04-11 00:18:22 +04:00
buf = talloc_strdup ( mem_ctx , asctime ( tm ) ) ;
if ( buf [ strlen ( buf ) - 1 ] = = ' \n ' ) {
buf [ strlen ( buf ) - 1 ] = 0 ;
}
# else
2003-08-13 05:53:07 +04:00
strftime ( tempTime , sizeof ( tempTime ) - 1 , " %a, %d %b %Y %H:%M:%S %Z " , tm ) ;
2004-04-11 00:18:22 +04:00
buf = talloc_strdup ( mem_ctx , tempTime ) ;
2003-08-13 05:53:07 +04:00
# endif /* !HAVE_STRFTIME */
2004-04-11 00:18:22 +04:00
return buf ;
2003-08-13 05:53:07 +04:00
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
Return the date and time as a string
2006-02-28 16:12:39 +03:00
* */
2006-03-05 20:15:19 +03:00
_PUBLIC_ char * timestring ( TALLOC_CTX * mem_ctx , time_t t )
2003-08-13 05:53:07 +04:00
{
char * TimeBuf ;
2004-04-11 00:18:22 +04:00
char tempTime [ 80 ] ;
2003-08-13 05:53:07 +04:00
struct tm * tm ;
2004-04-11 00:18:22 +04:00
tm = localtime ( & t ) ;
2003-08-13 05:53:07 +04:00
if ( ! tm ) {
2004-04-11 00:18:22 +04:00
return talloc_asprintf ( mem_ctx ,
" %ld seconds since the Epoch " ,
( long ) t ) ;
}
2003-08-13 05:53:07 +04:00
# ifdef HAVE_STRFTIME
2010-12-22 11:53:27 +03:00
/* 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 ) ;
2004-04-11 00:18:22 +04:00
TimeBuf = talloc_strdup ( mem_ctx , tempTime ) ;
2003-08-13 05:53:07 +04:00
# else
2004-04-11 00:18:22 +04:00
TimeBuf = talloc_strdup ( mem_ctx , asctime ( tm ) ) ;
2013-02-13 19:51:54 +04:00
if ( TimeBuf = = NULL ) {
return NULL ;
}
if ( TimeBuf [ 0 ] ! = ' \0 ' ) {
size_t len = strlen ( TimeBuf ) ;
if ( TimeBuf [ len - 1 ] = = ' \n ' ) {
TimeBuf [ len - 1 ] = ' \0 ' ;
}
}
2003-08-13 05:53:07 +04:00
# endif
2004-04-11 00:18:22 +04:00
return TimeBuf ;
2003-08-13 05:53:07 +04:00
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
return a talloced string representing a NTTIME for human consumption
*/
2006-03-05 20:15:19 +03:00
_PUBLIC_ const char * nt_time_string ( TALLOC_CTX * mem_ctx , NTTIME nt )
2003-08-13 05:53:07 +04:00
{
2005-01-29 07:11:04 +03:00
time_t t ;
if ( nt = = 0 ) {
return " NTTIME(0) " ;
}
t = nt_time_to_unix ( nt ) ;
2004-11-13 16:33:45 +03:00
return timestring ( mem_ctx , t ) ;
2004-04-11 00:18:22 +04:00
}
2006-02-28 16:12:39 +03:00
/**
2004-04-11 00:18:22 +04:00
put a NTTIME into a packet
*/
2006-03-05 20:15:19 +03:00
_PUBLIC_ void push_nttime ( uint8_t * base , uint16_t offset , NTTIME t )
2004-04-11 00:18:22 +04:00
{
2004-05-25 17:57:39 +04:00
SBVAL ( base , offset , t ) ;
2004-04-11 00:18:22 +04:00
}
2006-02-28 16:12:39 +03:00
/**
2004-04-11 00:18:22 +04:00
pull a NTTIME from a packet
*/
2006-03-05 20:15:19 +03:00
_PUBLIC_ NTTIME pull_nttime ( uint8_t * base , uint16_t offset )
2004-04-11 00:18:22 +04:00
{
2004-05-25 17:57:39 +04:00
NTTIME ret = BVAL ( base , offset ) ;
2004-05-08 18:42:45 +04:00
return ret ;
}
2004-05-09 13:39:47 +04:00
2006-02-28 16:12:39 +03:00
/**
2004-11-03 13:09:48 +03:00
return ( tv1 - tv2 ) in microseconds
*/
2008-05-20 21:54:45 +04:00
_PUBLIC_ int64_t usec_time_diff ( const struct timeval * tv1 , const struct timeval * tv2 )
2004-11-03 13:09:48 +03:00
{
int64_t sec_diff = tv1 - > tv_sec - tv2 - > tv_sec ;
return ( sec_diff * 1000000 ) + ( int64_t ) ( tv1 - > tv_usec - tv2 - > tv_usec ) ;
}
2010-08-30 19:56:37 +04:00
/**
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 ) ;
}
2004-11-03 13:09:48 +03:00
2006-02-28 16:12:39 +03:00
/**
2004-11-03 13:09:48 +03:00
return a zero timeval
*/
2006-03-05 20:15:19 +03:00
_PUBLIC_ struct timeval timeval_zero ( void )
2004-06-08 23:25:26 +04:00
{
2004-11-03 13:09:48 +03:00
struct timeval tv ;
tv . tv_sec = 0 ;
tv . tv_usec = 0 ;
return tv ;
2004-06-08 23:25:26 +04:00
}
2006-02-28 16:12:39 +03:00
/**
2007-08-27 21:21:16 +04:00
return true if a timeval is zero
2005-01-31 11:18:52 +03:00
*/
2007-08-27 21:21:16 +04:00
_PUBLIC_ bool timeval_is_zero ( const struct timeval * tv )
2005-01-31 11:18:52 +03:00
{
return tv - > tv_sec = = 0 & & tv - > tv_usec = = 0 ;
}
2006-02-28 16:12:39 +03:00
/**
2004-11-03 13:09:48 +03:00
return a timeval for the current time
*/
2006-03-05 20:15:19 +03:00
_PUBLIC_ struct timeval timeval_current ( void )
2004-11-03 13:09:48 +03:00
{
struct timeval tv ;
GetTimeOfDay ( & tv ) ;
return tv ;
}
2006-02-28 16:12:39 +03:00
/**
2004-11-03 13:09:48 +03:00
return a timeval struct with the given elements
*/
2006-03-05 20:15:19 +03:00
_PUBLIC_ struct timeval timeval_set ( uint32_t secs , uint32_t usecs )
2004-11-03 13:09:48 +03:00
{
struct timeval tv ;
tv . tv_sec = secs ;
tv . tv_usec = usecs ;
return tv ;
}
2006-02-28 16:12:39 +03:00
/**
2004-11-03 13:09:48 +03:00
return a timeval ofs microseconds after tv
*/
2006-03-05 20:15:19 +03:00
_PUBLIC_ struct timeval timeval_add ( const struct timeval * tv ,
2005-08-01 20:12:19 +04:00
uint32_t secs , uint32_t usecs )
2004-11-03 13:09:48 +03:00
{
struct timeval tv2 = * tv ;
2006-05-05 17:02:14 +04:00
const unsigned int million = 1000000 ;
2004-11-03 13:09:48 +03:00
tv2 . tv_sec + = secs ;
tv2 . tv_usec + = usecs ;
tv2 . tv_sec + = tv2 . tv_usec / million ;
tv2 . tv_usec = tv2 . tv_usec % million ;
return tv2 ;
}
2006-02-28 16:12:39 +03:00
/**
2004-11-03 13:09:48 +03:00
return the sum of two timeval structures
*/
2005-08-01 20:12:19 +04:00
struct timeval timeval_sum ( const struct timeval * tv1 ,
const struct timeval * tv2 )
2004-11-03 13:09:48 +03:00
{
return timeval_add ( tv1 , tv2 - > tv_sec , tv2 - > tv_usec ) ;
}
2006-02-28 16:12:39 +03:00
/**
2004-11-03 13:09:48 +03:00
return a timeval secs / usecs into the future
*/
2006-03-05 20:15:19 +03:00
_PUBLIC_ struct timeval timeval_current_ofs ( uint32_t secs , uint32_t usecs )
2004-11-03 13:09:48 +03:00
{
struct timeval tv = timeval_current ( ) ;
return timeval_add ( & tv , secs , usecs ) ;
}
2011-06-01 05:51:15 +04:00
/**
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 ) ;
}
2011-06-01 05:54:51 +04:00
/**
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 ) ;
}
2006-02-28 16:12:39 +03:00
/**
2004-11-03 13:09:48 +03:00
compare two timeval structures .
2005-08-01 21:31:40 +04:00
Return - 1 if tv1 < tv2
Return 0 if tv1 = = tv2
Return 1 if tv1 > tv2
2004-11-03 13:09:48 +03:00
*/
2006-03-05 20:15:19 +03:00
_PUBLIC_ int timeval_compare ( const struct timeval * tv1 , const struct timeval * tv2 )
2004-11-03 13:09:48 +03:00
{
2005-08-01 21:31:40 +04:00
if ( tv1 - > tv_sec > tv2 - > tv_sec ) return 1 ;
if ( tv1 - > tv_sec < tv2 - > tv_sec ) return - 1 ;
if ( tv1 - > tv_usec > tv2 - > tv_usec ) return 1 ;
if ( tv1 - > tv_usec < tv2 - > tv_usec ) return - 1 ;
2004-11-03 13:09:48 +03:00
return 0 ;
}
2006-02-28 16:12:39 +03:00
/**
2007-08-27 21:21:16 +04:00
return true if a timer is in the past
2004-11-03 13:09:48 +03:00
*/
2007-08-27 21:21:16 +04:00
_PUBLIC_ bool timeval_expired ( const struct timeval * tv )
2004-11-03 13:09:48 +03:00
{
struct timeval tv2 = timeval_current ( ) ;
2007-08-27 21:21:16 +04:00
if ( tv2 . tv_sec > tv - > tv_sec ) return true ;
if ( tv2 . tv_sec < tv - > tv_sec ) return false ;
2004-11-03 13:09:48 +03:00
return ( tv2 . tv_usec > = tv - > tv_usec ) ;
}
2006-02-28 16:12:39 +03:00
/**
2004-11-26 02:05:43 +03:00
return the number of seconds elapsed between two times
*/
2006-03-05 20:15:19 +03:00
_PUBLIC_ double timeval_elapsed2 ( const struct timeval * tv1 , const struct timeval * tv2 )
2004-11-26 02:05:43 +03:00
{
return ( tv2 - > tv_sec - tv1 - > tv_sec ) +
( tv2 - > tv_usec - tv1 - > tv_usec ) * 1.0e-6 ;
}
2006-02-28 16:12:39 +03:00
/**
2004-11-03 13:09:48 +03:00
return the number of seconds elapsed since a given time
*/
2006-03-05 20:15:19 +03:00
_PUBLIC_ double timeval_elapsed ( const struct timeval * tv )
2004-11-03 13:09:48 +03:00
{
struct timeval tv2 = timeval_current ( ) ;
2004-11-26 02:05:43 +03:00
return timeval_elapsed2 ( tv , & tv2 ) ;
2004-11-03 13:09:48 +03:00
}
2013-11-20 15:00:17 +04:00
/**
* 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 ) ;
}
2004-11-03 13:09:48 +03:00
2006-02-28 16:12:39 +03:00
/**
2004-11-03 13:09:48 +03:00
return the lesser of two timevals
*/
2006-03-05 20:15:19 +03:00
_PUBLIC_ struct timeval timeval_min ( const struct timeval * tv1 ,
2005-08-01 20:12:19 +04:00
const struct timeval * tv2 )
2004-11-03 13:09:48 +03:00
{
if ( tv1 - > tv_sec < tv2 - > tv_sec ) return * tv1 ;
if ( tv1 - > tv_sec > tv2 - > tv_sec ) return * tv2 ;
if ( tv1 - > tv_usec < tv2 - > tv_usec ) return * tv1 ;
return * tv2 ;
}
2006-02-28 16:12:39 +03:00
/**
2004-11-26 02:05:43 +03:00
return the greater of two timevals
*/
2006-03-05 20:15:19 +03:00
_PUBLIC_ struct timeval timeval_max ( const struct timeval * tv1 ,
2005-08-01 20:12:19 +04:00
const struct timeval * tv2 )
2004-11-26 02:05:43 +03:00
{
if ( tv1 - > tv_sec > tv2 - > tv_sec ) return * tv1 ;
if ( tv1 - > tv_sec < tv2 - > tv_sec ) return * tv2 ;
if ( tv1 - > tv_usec > tv2 - > tv_usec ) return * tv1 ;
return * tv2 ;
}
2006-02-28 16:12:39 +03:00
/**
2004-11-03 13:09:48 +03:00
return the difference between two timevals as a timeval
2005-08-01 04:34:39 +04:00
if tv1 comes after tv2 , then return a zero timeval
( this is * tv2 - * tv1 )
2004-11-03 13:09:48 +03:00
*/
2006-03-05 20:15:19 +03:00
_PUBLIC_ struct timeval timeval_until ( const struct timeval * tv1 ,
2005-08-01 20:12:19 +04:00
const struct timeval * tv2 )
2004-11-03 13:09:48 +03:00
{
struct timeval t ;
2005-08-01 21:31:40 +04:00
if ( timeval_compare ( tv1 , tv2 ) > = 0 ) {
2004-11-03 13:09:48 +03:00
return timeval_zero ( ) ;
}
2005-08-01 04:34:39 +04:00
t . tv_sec = tv2 - > tv_sec - tv1 - > tv_sec ;
if ( tv1 - > tv_usec > tv2 - > tv_usec ) {
2004-11-03 13:09:48 +03:00
t . tv_sec - - ;
2005-08-01 04:34:39 +04:00
t . tv_usec = 1000000 - ( tv1 - > tv_usec - tv2 - > tv_usec ) ;
2004-11-03 13:09:48 +03:00
} else {
2005-08-01 04:34:39 +04:00
t . tv_usec = tv2 - > tv_usec - tv1 - > tv_usec ;
2004-11-03 13:09:48 +03:00
}
return t ;
}
2005-01-11 06:07:53 +03:00
2006-02-28 16:12:39 +03:00
/**
2005-01-11 06:07:53 +03:00
convert a timeval to a NTTIME
*/
2006-03-05 20:15:19 +03:00
_PUBLIC_ NTTIME timeval_to_nttime ( const struct timeval * tv )
2005-01-11 06:07:53 +03:00
{
2005-01-11 06:26:26 +03:00
return 10 * ( tv - > tv_usec +
( ( TIME_FIXUP_CONSTANT + ( uint64_t ) tv - > tv_sec ) * 1000000 ) ) ;
2005-01-11 06:07:53 +03:00
}
2005-09-23 04:38:22 +04:00
2006-09-18 21:32:13 +04:00
/**
convert a NTTIME to a timeval
*/
_PUBLIC_ void nttime_to_timeval ( struct timeval * tv , NTTIME t )
{
if ( tv = = NULL ) return ;
t + = 10 / 2 ;
t / = 10 ;
t - = TIME_FIXUP_CONSTANT * 1000 * 1000 ;
tv - > tv_sec = t / 1000000 ;
if ( TIME_T_MIN > tv - > tv_sec | | tv - > tv_sec > TIME_T_MAX ) {
tv - > tv_sec = 0 ;
tv - > tv_usec = 0 ;
return ;
}
tv - > tv_usec = t - tv - > tv_sec * 1000000 ;
}
2005-09-23 04:38:22 +04:00
/*******************************************************************
yield the difference between * A and * B , in seconds , ignoring leap seconds
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int tm_diff ( struct tm * a , struct tm * b )
{
int ay = a - > tm_year + ( 1900 - 1 ) ;
int by = b - > tm_year + ( 1900 - 1 ) ;
int intervening_leap_days =
( ay / 4 - by / 4 ) - ( ay / 100 - by / 100 ) + ( ay / 400 - by / 400 ) ;
int years = ay - by ;
int days = 365 * years + intervening_leap_days + ( a - > tm_yday - b - > tm_yday ) ;
int hours = 24 * days + ( a - > tm_hour - b - > tm_hour ) ;
int minutes = 60 * hours + ( a - > tm_min - b - > tm_min ) ;
int seconds = 60 * minutes + ( a - > tm_sec - b - > tm_sec ) ;
return seconds ;
}
2008-12-24 00:10:34 +03:00
2006-02-28 16:12:39 +03:00
/**
2005-09-23 04:38:22 +04:00
return the UTC offset in seconds west of UTC , or 0 if it cannot be determined
2006-02-28 16:12:39 +03:00
*/
2006-03-05 20:15:19 +03:00
_PUBLIC_ int get_time_zone ( time_t t )
2005-09-23 04:38:22 +04:00
{
struct tm * tm = gmtime ( & t ) ;
struct tm tm_utc ;
if ( ! tm )
return 0 ;
tm_utc = * tm ;
tm = localtime ( & t ) ;
if ( ! tm )
return 0 ;
2011-06-11 03:49:12 +04:00
return tm_diff ( & tm_utc , tm ) ;
2005-09-23 04:38:22 +04:00
}
2008-02-09 16:24:24 +03:00
2014-06-18 16:21:06 +04:00
struct timespec nt_time_to_unix_timespec ( NTTIME nt )
2008-10-12 01:57:44 +04:00
{
int64_t d ;
struct timespec ret ;
2014-06-18 16:21:06 +04:00
if ( nt = = 0 | | nt = = ( int64_t ) - 1 ) {
2008-10-12 01:57:44 +04:00
ret . tv_sec = 0 ;
ret . tv_nsec = 0 ;
return ret ;
}
2014-06-18 16:21:06 +04:00
d = ( int64_t ) nt ;
2008-10-12 01:57:44 +04:00
/* 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 100 ns units to 1 ns 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 ;
}
2008-02-09 16:24:24 +03:00
/**
check if 2 NTTIMEs are equal .
*/
bool nt_time_equal ( NTTIME * t1 , NTTIME * t2 )
{
return * t1 = = * t2 ;
}
2008-10-12 01:57:44 +04:00
/**
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 ;
}
2011-09-22 22:33:22 +04:00
/****************************************************************************
Convert a normalized timeval to a timespec .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-10-12 01:57:44 +04:00
2011-09-22 22:33:22 +04:00
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-11-03 20:22:40 +04:00
_PUBLIC_ struct timespec timespec_current ( void )
2011-09-22 22:33:22 +04:00
{
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-11-03 20:22:40 +04:00
_PUBLIC_ int timespec_compare ( const struct timespec * ts1 , const struct timespec * ts2 )
2011-09-22 22:33:22 +04:00
{
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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-06-18 16:21:06 +04:00
_PUBLIC_ NTTIME unix_timespec_to_nt_time ( struct timespec ts )
2011-09-22 22:33:22 +04:00
{
uint64_t d ;
if ( ts . tv_sec = = 0 & & ts . tv_nsec = = 0 ) {
2014-06-18 16:21:06 +04:00
return 0 ;
2011-09-22 22:33:22 +04:00
}
if ( ts . tv_sec = = TIME_T_MAX ) {
2014-06-18 16:21:06 +04:00
return 0x7fffffffffffffffLL ;
2011-09-22 22:33:22 +04:00
}
if ( ts . tv_sec = = ( time_t ) - 1 ) {
2014-06-18 16:21:06 +04:00
return ( uint64_t ) - 1 ;
2011-09-22 22:33:22 +04:00
}
d = ts . tv_sec ;
d + = TIME_FIXUP_CONSTANT_INT ;
d * = 1000 * 1000 * 10 ;
/* d is now in 100ns units. */
d + = ( ts . tv_nsec / 100 ) ;
2014-06-18 16:21:06 +04:00
return d ;
2011-09-22 22:33:22 +04:00
}