Add the timegm Gnulib module

This commit is contained in:
Thomas Guyot-Sionnest 2009-03-20 02:48:40 -04:00
parent d36c976129
commit 3fa3707b57
12 changed files with 1322 additions and 2 deletions

1
.gitignore vendored
View file

@ -66,6 +66,7 @@ NP-VERSION-FILE
/gl/stdio.h
/gl/string.h
/gl/sys_socket.h
/gl/time.h
/gl/unistd.h
/gl/wchar.h
/gl/wctype.h

View file

@ -9,7 +9,7 @@
# the same distribution terms as the rest of that program.
#
# Generated by gnulib-tool.
# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --no-libtool --macro-prefix=gl base64 dirname floorf fsusage getaddrinfo gethostname getloadavg getopt gettext mountlist regex vasprintf vsnprintf
# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --no-libtool --macro-prefix=gl base64 dirname floorf fsusage getaddrinfo gethostname getloadavg getopt gettext mountlist regex timegm vasprintf vsnprintf
AUTOMAKE_OPTIONS = 1.5 gnits
@ -589,6 +589,15 @@ EXTRA_libgnu_a_SOURCES += mbsinit.c
## end gnulib module mbsinit
## begin gnulib module mktime
EXTRA_DIST += mktime.c
EXTRA_libgnu_a_SOURCES += mktime.c
## end gnulib module mktime
## begin gnulib module mountlist
@ -1056,6 +1065,51 @@ EXTRA_DIST += sys_socket.in.h
## end gnulib module sys_socket
## begin gnulib module time
BUILT_SOURCES += time.h
# We need the following in order to create <time.h> when the system
# doesn't have one that works with the given compiler.
time.h: time.in.h
rm -f $@-t $@
{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \
sed -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
-e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
-e 's|@NEXT_TIME_H''@|$(NEXT_TIME_H)|g' \
-e 's|@REPLACE_LOCALTIME_R''@|$(REPLACE_LOCALTIME_R)|g' \
-e 's|@REPLACE_NANOSLEEP''@|$(REPLACE_NANOSLEEP)|g' \
-e 's|@REPLACE_STRPTIME''@|$(REPLACE_STRPTIME)|g' \
-e 's|@REPLACE_TIMEGM''@|$(REPLACE_TIMEGM)|g' \
-e 's|@SYS_TIME_H_DEFINES_STRUCT_TIMESPEC''@|$(SYS_TIME_H_DEFINES_STRUCT_TIMESPEC)|g' \
-e 's|@TIME_H_DEFINES_STRUCT_TIMESPEC''@|$(TIME_H_DEFINES_STRUCT_TIMESPEC)|g' \
< $(srcdir)/time.in.h; \
} > $@-t
mv $@-t $@
MOSTLYCLEANFILES += time.h time.h-t
EXTRA_DIST += time.in.h
## end gnulib module time
## begin gnulib module time_r
EXTRA_DIST += time_r.c
EXTRA_libgnu_a_SOURCES += time_r.c
## end gnulib module time_r
## begin gnulib module timegm
EXTRA_DIST += timegm.c
EXTRA_libgnu_a_SOURCES += timegm.c
## end gnulib module timegm
## begin gnulib module unistd
BUILT_SOURCES += unistd.h

View file

@ -15,7 +15,7 @@
# Specification in the form of a command-line invocation:
# gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --no-libtool --macro-prefix=gl base64 dirname floorf fsusage getaddrinfo gethostname getloadavg getopt gettext mountlist regex vasprintf vsnprintf
# gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --no-libtool --macro-prefix=gl base64 dirname floorf fsusage getaddrinfo gethostname getloadavg getopt gettext mountlist regex timegm vasprintf vsnprintf
# Specification in the form of a few gnulib-tool.m4 macro invocations:
gl_LOCAL_DIR([])
@ -31,6 +31,7 @@ gl_MODULES([
gettext
mountlist
regex
timegm
vasprintf
vsnprintf
])

View file

@ -94,6 +94,7 @@ AC_DEFUN([gl_INIT],
gl_WCHAR_MODULE_INDICATOR([mbrtowc])
gl_FUNC_MBSINIT
gl_WCHAR_MODULE_INDICATOR([mbsinit])
gl_FUNC_MKTIME
gl_MOUNTLIST
gl_MULTIARCH
gl_HEADER_NETDB
@ -125,6 +126,9 @@ AC_DEFUN([gl_INIT],
gl_HEADER_SYS_SOCKET
gl_MODULE_INDICATOR([sys_socket])
AC_PROG_MKDIR_P
gl_HEADER_TIME_H
gl_TIME_R
gl_FUNC_TIMEGM
gl_UNISTD_H
gl_UNISTD_SAFER
gl_FUNC_VASNPRINTF
@ -332,6 +336,7 @@ AC_DEFUN([gl_FILE_LIST], [
lib/math.in.h
lib/mbrtowc.c
lib/mbsinit.c
lib/mktime.c
lib/mountlist.c
lib/mountlist.h
lib/netdb.in.h
@ -369,6 +374,9 @@ AC_DEFUN([gl_FILE_LIST], [
lib/strndup.c
lib/strnlen.c
lib/sys_socket.in.h
lib/time.in.h
lib/time_r.c
lib/timegm.c
lib/unistd--.h
lib/unistd-safer.h
lib/unistd.in.h
@ -444,6 +452,7 @@ AC_DEFUN([gl_FILE_LIST], [
m4/mbrtowc.m4
m4/mbsinit.m4
m4/mbstate_t.m4
m4/mktime.m4
m4/mountlist.m4
m4/multiarch.m4
m4/netdb_h.m4
@ -475,6 +484,9 @@ AC_DEFUN([gl_FILE_LIST], [
m4/strnlen.m4
m4/sys_socket_h.m4
m4/threadlib.m4
m4/time_h.m4
m4/time_r.m4
m4/timegm.m4
m4/uintmax_t.m4
m4/unistd-safer.m4
m4/unistd_h.m4

224
gl/m4/mktime.m4 Normal file
View file

@ -0,0 +1,224 @@
# serial 14
dnl Copyright (C) 2002-2003, 2005-2007, 2009 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
dnl From Jim Meyering.
# Redefine AC_FUNC_MKTIME, to fix a bug in Autoconf 2.61a and earlier.
# This redefinition can be removed once a new version of Autoconf is assumed.
# The redefinition is taken from
# <http://cvs.sv.gnu.org/viewcvs/*checkout*/autoconf/autoconf/lib/autoconf/functions.m4?rev=1.119>.
# AC_FUNC_MKTIME
# --------------
AC_DEFUN([AC_FUNC_MKTIME],
[AC_CHECK_HEADERS_ONCE([unistd.h])
AC_CHECK_FUNCS_ONCE([alarm])
AC_CACHE_CHECK([for working mktime], [ac_cv_func_working_mktime],
[AC_RUN_IFELSE([AC_LANG_SOURCE(
[[/* Test program from Paul Eggert and Tony Leneis. */
#include <limits.h>
#include <stdlib.h>
#include <time.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifndef HAVE_ALARM
# define alarm(X) /* empty */
#endif
/* Work around redefinition to rpl_putenv by other config tests. */
#undef putenv
static time_t time_t_max;
static time_t time_t_min;
/* Values we'll use to set the TZ environment variable. */
static char *tz_strings[] = {
(char *) 0, "TZ=GMT0", "TZ=JST-9",
"TZ=EST+3EDT+2,M10.1.0/00:00:00,M2.3.0/00:00:00"
};
#define N_STRINGS (sizeof (tz_strings) / sizeof (tz_strings[0]))
/* Return 0 if mktime fails to convert a date in the spring-forward gap.
Based on a problem report from Andreas Jaeger. */
static int
spring_forward_gap ()
{
/* glibc (up to about 1998-10-07) failed this test. */
struct tm tm;
/* Use the portable POSIX.1 specification "TZ=PST8PDT,M4.1.0,M10.5.0"
instead of "TZ=America/Vancouver" in order to detect the bug even
on systems that don't support the Olson extension, or don't have the
full zoneinfo tables installed. */
putenv ("TZ=PST8PDT,M4.1.0,M10.5.0");
tm.tm_year = 98;
tm.tm_mon = 3;
tm.tm_mday = 5;
tm.tm_hour = 2;
tm.tm_min = 0;
tm.tm_sec = 0;
tm.tm_isdst = -1;
return mktime (&tm) != (time_t) -1;
}
static int
mktime_test1 (time_t now)
{
struct tm *lt;
return ! (lt = localtime (&now)) || mktime (lt) == now;
}
static int
mktime_test (time_t now)
{
return (mktime_test1 (now)
&& mktime_test1 ((time_t) (time_t_max - now))
&& mktime_test1 ((time_t) (time_t_min + now)));
}
static int
irix_6_4_bug ()
{
/* Based on code from Ariel Faigon. */
struct tm tm;
tm.tm_year = 96;
tm.tm_mon = 3;
tm.tm_mday = 0;
tm.tm_hour = 0;
tm.tm_min = 0;
tm.tm_sec = 0;
tm.tm_isdst = -1;
mktime (&tm);
return tm.tm_mon == 2 && tm.tm_mday == 31;
}
static int
bigtime_test (int j)
{
struct tm tm;
time_t now;
tm.tm_year = tm.tm_mon = tm.tm_mday = tm.tm_hour = tm.tm_min = tm.tm_sec = j;
now = mktime (&tm);
if (now != (time_t) -1)
{
struct tm *lt = localtime (&now);
if (! (lt
&& lt->tm_year == tm.tm_year
&& lt->tm_mon == tm.tm_mon
&& lt->tm_mday == tm.tm_mday
&& lt->tm_hour == tm.tm_hour
&& lt->tm_min == tm.tm_min
&& lt->tm_sec == tm.tm_sec
&& lt->tm_yday == tm.tm_yday
&& lt->tm_wday == tm.tm_wday
&& ((lt->tm_isdst < 0 ? -1 : 0 < lt->tm_isdst)
== (tm.tm_isdst < 0 ? -1 : 0 < tm.tm_isdst))))
return 0;
}
return 1;
}
static int
year_2050_test ()
{
/* The correct answer for 2050-02-01 00:00:00 in Pacific time,
ignoring leap seconds. */
unsigned long int answer = 2527315200UL;
struct tm tm;
time_t t;
tm.tm_year = 2050 - 1900;
tm.tm_mon = 2 - 1;
tm.tm_mday = 1;
tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
tm.tm_isdst = -1;
/* Use the portable POSIX.1 specification "TZ=PST8PDT,M4.1.0,M10.5.0"
instead of "TZ=America/Vancouver" in order to detect the bug even
on systems that don't support the Olson extension, or don't have the
full zoneinfo tables installed. */
putenv ("TZ=PST8PDT,M4.1.0,M10.5.0");
t = mktime (&tm);
/* Check that the result is either a failure, or close enough
to the correct answer that we can assume the discrepancy is
due to leap seconds. */
return (t == (time_t) -1
|| (0 < t && answer - 120 <= t && t <= answer + 120));
}
int
main ()
{
time_t t, delta;
int i, j;
/* This test makes some buggy mktime implementations loop.
Give up after 60 seconds; a mktime slower than that
isn't worth using anyway. */
alarm (60);
for (;;)
{
t = (time_t_max << 1) + 1;
if (t <= time_t_max)
break;
time_t_max = t;
}
time_t_min = - ((time_t) ~ (time_t) 0 == (time_t) -1) - time_t_max;
delta = time_t_max / 997; /* a suitable prime number */
for (i = 0; i < N_STRINGS; i++)
{
if (tz_strings[i])
putenv (tz_strings[i]);
for (t = 0; t <= time_t_max - delta; t += delta)
if (! mktime_test (t))
return 1;
if (! (mktime_test ((time_t) 1)
&& mktime_test ((time_t) (60 * 60))
&& mktime_test ((time_t) (60 * 60 * 24))))
return 1;
for (j = 1; ; j <<= 1)
if (! bigtime_test (j))
return 1;
else if (INT_MAX / 2 < j)
break;
if (! bigtime_test (INT_MAX))
return 1;
}
return ! (irix_6_4_bug () && spring_forward_gap () && year_2050_test ());
}]])],
[ac_cv_func_working_mktime=yes],
[ac_cv_func_working_mktime=no],
[ac_cv_func_working_mktime=no])])
if test $ac_cv_func_working_mktime = no; then
AC_LIBOBJ([mktime])
fi
])# AC_FUNC_MKTIME
AC_DEFUN([gl_FUNC_MKTIME],
[
AC_FUNC_MKTIME
dnl Note: AC_FUNC_MKTIME does AC_LIBOBJ([mktime]).
if test $ac_cv_func_working_mktime = no; then
AC_DEFINE([mktime], [rpl_mktime],
[Define to rpl_mktime if the replacement function should be used.])
gl_PREREQ_MKTIME
fi
])
# Prerequisites of lib/mktime.c.
AC_DEFUN([gl_PREREQ_MKTIME],
[
AC_REQUIRE([AC_C_INLINE])
])

74
gl/m4/time_h.m4 Normal file
View file

@ -0,0 +1,74 @@
# Configure a more-standard replacement for <time.h>.
# Copyright (C) 2000, 2001, 2003, 2004, 2005, 2006, 2007 Free Software
# Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# Written by Paul Eggert and Jim Meyering.
AC_DEFUN([gl_HEADER_TIME_H],
[
dnl Use AC_REQUIRE here, so that the default behavior below is expanded
dnl once only, before all statements that occur in other macros.
AC_REQUIRE([gl_HEADER_TIME_H_BODY])
])
AC_DEFUN([gl_HEADER_TIME_H_BODY],
[
AC_REQUIRE([AC_C_RESTRICT])
AC_REQUIRE([gl_HEADER_TIME_H_DEFAULTS])
gl_CHECK_NEXT_HEADERS([time.h])
AC_REQUIRE([gl_CHECK_TYPE_STRUCT_TIMESPEC])
])
AC_DEFUN([gl_HEADER_TIME_H_DEFAULTS],
[
dnl If another module says to replace or to not replace, do that.
dnl Otherwise, replace only if someone compiles with -DGNULIB_PORTCHECK;
dnl this lets maintainers check for portability.
REPLACE_LOCALTIME_R=GNULIB_PORTCHECK; AC_SUBST([REPLACE_LOCALTIME_R])
REPLACE_NANOSLEEP=GNULIB_PORTCHECK; AC_SUBST([REPLACE_NANOSLEEP])
REPLACE_STRPTIME=GNULIB_PORTCHECK; AC_SUBST([REPLACE_STRPTIME])
REPLACE_TIMEGM=GNULIB_PORTCHECK; AC_SUBST([REPLACE_TIMEGM])
])
dnl Define HAVE_STRUCT_TIMESPEC if `struct timespec' is declared
dnl in time.h or sys/time.h.
AC_DEFUN([gl_CHECK_TYPE_STRUCT_TIMESPEC],
[
AC_CHECK_HEADERS_ONCE([sys/time.h])
AC_CACHE_CHECK([for struct timespec in <time.h>],
[gl_cv_sys_struct_timespec_in_time_h],
[AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[[#include <time.h>
]],
[[static struct timespec x; x.tv_sec = x.tv_nsec;]])],
[gl_cv_sys_struct_timespec_in_time_h=yes],
[gl_cv_sys_struct_timespec_in_time_h=no])])
TIME_H_DEFINES_STRUCT_TIMESPEC=0
SYS_TIME_H_DEFINES_STRUCT_TIMESPEC=0
if test $gl_cv_sys_struct_timespec_in_time_h = yes; then
TIME_H_DEFINES_STRUCT_TIMESPEC=1
else
AC_CACHE_CHECK([for struct timespec in <sys/time.h>],
[gl_cv_sys_struct_timespec_in_sys_time_h],
[AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[[#include <sys/time.h>
]],
[[static struct timespec x; x.tv_sec = x.tv_nsec;]])],
[gl_cv_sys_struct_timespec_in_sys_time_h=yes],
[gl_cv_sys_struct_timespec_in_sys_time_h=no])])
if test $gl_cv_sys_struct_timespec_in_sys_time_h = yes; then
SYS_TIME_H_DEFINES_STRUCT_TIMESPEC=1
fi
fi
AC_SUBST([TIME_H_DEFINES_STRUCT_TIMESPEC])
AC_SUBST([SYS_TIME_H_DEFINES_STRUCT_TIMESPEC])
])

43
gl/m4/time_r.m4 Normal file
View file

@ -0,0 +1,43 @@
dnl Reentrant time functions like localtime_r.
dnl Copyright (C) 2003, 2006, 2007, 2008 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
dnl Written by Paul Eggert.
AC_DEFUN([gl_TIME_R],
[
dnl Persuade glibc and Solaris <time.h> to declare localtime_r.
AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
AC_REQUIRE([gl_HEADER_TIME_H_DEFAULTS])
AC_REQUIRE([AC_C_RESTRICT])
AC_CACHE_CHECK([whether localtime_r is compatible with its POSIX signature],
[gl_cv_time_r_posix],
[AC_TRY_COMPILE(
[#include <time.h>],
[/* We don't need to append 'restrict's to the argument types,
even though the POSIX signature has the 'restrict's,
since C99 says they can't affect type compatibility. */
struct tm * (*ptr) (time_t const *, struct tm *) = localtime_r;
if (ptr) return 0;
/* Check the return type is a pointer. On HP-UX 10 it is 'int'. */
*localtime_r (0, 0);],
[gl_cv_time_r_posix=yes],
[gl_cv_time_r_posix=no])])
if test $gl_cv_time_r_posix = yes; then
REPLACE_LOCALTIME_R=0
else
REPLACE_LOCALTIME_R=1
AC_LIBOBJ([time_r])
gl_PREREQ_TIME_R
fi
])
# Prerequisites of lib/time_r.c.
AC_DEFUN([gl_PREREQ_TIME_R], [
:
])

40
gl/m4/timegm.m4 Normal file
View file

@ -0,0 +1,40 @@
# timegm.m4 serial 6
dnl Copyright (C) 2003, 2007, 2009 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
AC_DEFUN([gl_FUNC_TIMEGM],
[
AC_REQUIRE([gl_HEADER_TIME_H_DEFAULTS])
AC_REQUIRE([gl_FUNC_MKTIME])
if test $ac_cv_func_working_mktime = no; then
# Assume that timegm is buggy if mktime is.
AC_LIBOBJ([timegm])
ac_cv_func_timegm=no
else
AC_REPLACE_FUNCS([timegm])
fi
REPLACE_TIMEGM=1
if test $ac_cv_func_timegm = yes; then
AC_CHECK_DECLS([timegm], [REPLACE_TIMEGM=0], [], [#include <time.h>])
fi
if test $REPLACE_TIMEGM = 1; then
gl_PREREQ_TIMEGM
fi
])
# Prerequisites of lib/timegm.c.
AC_DEFUN([gl_PREREQ_TIMEGM], [
AC_REQUIRE([gl_TIME_R])
AC_REQUIRE([gl_FUNC_MKTIME])
if test $ac_cv_func_working_mktime = yes; then
AC_CHECK_FUNC([__mktime_internal], ,
[# mktime works but it doesn't export __mktime_internal,
# so we need to substitute our own mktime implementation.
AC_LIBOBJ([mktime])
AC_DEFINE([mktime], [rpl_mktime],
[Define to rpl_mktime if the replacement function should be used.])
gl_PREREQ_MKTIME])
fi
])

665
gl/mktime.c Normal file
View file

@ -0,0 +1,665 @@
/* Convert a `struct tm' to a time_t value.
Copyright (C) 1993-1999, 2002-2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Paul Eggert <eggert@twinsun.com>.
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
the Free Software Foundation; either version 3, or (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 along
with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* Define this to have a standalone program to test this implementation of
mktime. */
/* #define DEBUG 1 */
#ifndef _LIBC
# include <config.h>
#endif
/* Assume that leap seconds are possible, unless told otherwise.
If the host has a `zic' command with a `-L leapsecondfilename' option,
then it supports leap seconds; otherwise it probably doesn't. */
#ifndef LEAP_SECONDS_POSSIBLE
# define LEAP_SECONDS_POSSIBLE 1
#endif
#include <time.h>
#include <limits.h>
#include <string.h> /* For the real memcpy prototype. */
#if DEBUG
# include <stdio.h>
# include <stdlib.h>
/* Make it work even if the system's libc has its own mktime routine. */
# define mktime my_mktime
#endif /* DEBUG */
/* Shift A right by B bits portably, by dividing A by 2**B and
truncating towards minus infinity. A and B should be free of side
effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
INT_BITS is the number of useful bits in an int. GNU code can
assume that INT_BITS is at least 32.
ISO C99 says that A >> B is implementation-defined if A < 0. Some
implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
right in the usual way when A < 0, so SHR falls back on division if
ordinary A >> B doesn't seem to be the usual signed shift. */
#define SHR(a, b) \
(-1 >> 1 == -1 \
? (a) >> (b) \
: (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
/* The extra casts in the following macros work around compiler bugs,
e.g., in Cray C 5.0.3.0. */
/* True if the arithmetic type T is an integer type. bool counts as
an integer. */
#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
/* True if negative values of the signed integer type T use two's
complement, ones' complement, or signed magnitude representation,
respectively. Much GNU code assumes two's complement, but some
people like to be portable to all possible C hosts. */
#define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1)
#define TYPE_ONES_COMPLEMENT(t) ((t) ~ (t) 0 == 0)
#define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1)
/* True if the arithmetic type T is signed. */
#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
/* The maximum and minimum values for the integer type T. These
macros have undefined behavior if T is signed and has padding bits.
If this is a problem for you, please let us know how to fix it for
your host. */
#define TYPE_MINIMUM(t) \
((t) (! TYPE_SIGNED (t) \
? (t) 0 \
: TYPE_SIGNED_MAGNITUDE (t) \
? ~ (t) 0 \
: ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)))
#define TYPE_MAXIMUM(t) \
((t) (! TYPE_SIGNED (t) \
? (t) -1 \
: ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))))
#ifndef TIME_T_MIN
# define TIME_T_MIN TYPE_MINIMUM (time_t)
#endif
#ifndef TIME_T_MAX
# define TIME_T_MAX TYPE_MAXIMUM (time_t)
#endif
#define TIME_T_MIDPOINT (SHR (TIME_T_MIN + TIME_T_MAX, 1) + 1)
/* Verify a requirement at compile-time (unlike assert, which is runtime). */
#define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; }
verify (time_t_is_integer, TYPE_IS_INTEGER (time_t));
verify (twos_complement_arithmetic, TYPE_TWOS_COMPLEMENT (int));
/* The code also assumes that signed integer overflow silently wraps
around, but this assumption can't be stated without causing a
diagnostic on some hosts. */
#define EPOCH_YEAR 1970
#define TM_YEAR_BASE 1900
verify (base_year_is_a_multiple_of_100, TM_YEAR_BASE % 100 == 0);
/* Return 1 if YEAR + TM_YEAR_BASE is a leap year. */
static inline int
leapyear (long int year)
{
/* Don't add YEAR to TM_YEAR_BASE, as that might overflow.
Also, work even if YEAR is negative. */
return
((year & 3) == 0
&& (year % 100 != 0
|| ((year / 100) & 3) == (- (TM_YEAR_BASE / 100) & 3)));
}
/* How many days come before each month (0-12). */
#ifndef _LIBC
static
#endif
const unsigned short int __mon_yday[2][13] =
{
/* Normal years. */
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
/* Leap years. */
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
};
#ifndef _LIBC
/* Portable standalone applications should supply a <time.h> that
declares a POSIX-compliant localtime_r, for the benefit of older
implementations that lack localtime_r or have a nonstandard one.
See the gnulib time_r module for one way to implement this. */
# undef __localtime_r
# define __localtime_r localtime_r
# define __mktime_internal mktime_internal
#endif
/* Return an integer value measuring (YEAR1-YDAY1 HOUR1:MIN1:SEC1) -
(YEAR0-YDAY0 HOUR0:MIN0:SEC0) in seconds, assuming that the clocks
were not adjusted between the time stamps.
The YEAR values uses the same numbering as TP->tm_year. Values
need not be in the usual range. However, YEAR1 must not be less
than 2 * INT_MIN or greater than 2 * INT_MAX.
The result may overflow. It is the caller's responsibility to
detect overflow. */
static inline time_t
ydhms_diff (long int year1, long int yday1, int hour1, int min1, int sec1,
int year0, int yday0, int hour0, int min0, int sec0)
{
verify (C99_integer_division, -1 / 2 == 0);
verify (long_int_year_and_yday_are_wide_enough,
INT_MAX <= LONG_MAX / 2 || TIME_T_MAX <= UINT_MAX);
/* Compute intervening leap days correctly even if year is negative.
Take care to avoid integer overflow here. */
int a4 = SHR (year1, 2) + SHR (TM_YEAR_BASE, 2) - ! (year1 & 3);
int b4 = SHR (year0, 2) + SHR (TM_YEAR_BASE, 2) - ! (year0 & 3);
int a100 = a4 / 25 - (a4 % 25 < 0);
int b100 = b4 / 25 - (b4 % 25 < 0);
int a400 = SHR (a100, 2);
int b400 = SHR (b100, 2);
int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
/* Compute the desired time in time_t precision. Overflow might
occur here. */
time_t tyear1 = year1;
time_t years = tyear1 - year0;
time_t days = 365 * years + yday1 - yday0 + intervening_leap_days;
time_t hours = 24 * days + hour1 - hour0;
time_t minutes = 60 * hours + min1 - min0;
time_t seconds = 60 * minutes + sec1 - sec0;
return seconds;
}
/* Return a time_t value corresponding to (YEAR-YDAY HOUR:MIN:SEC),
assuming that *T corresponds to *TP and that no clock adjustments
occurred between *TP and the desired time.
If TP is null, return a value not equal to *T; this avoids false matches.
If overflow occurs, yield the minimal or maximal value, except do not
yield a value equal to *T. */
static time_t
guess_time_tm (long int year, long int yday, int hour, int min, int sec,
const time_t *t, const struct tm *tp)
{
if (tp)
{
time_t d = ydhms_diff (year, yday, hour, min, sec,
tp->tm_year, tp->tm_yday,
tp->tm_hour, tp->tm_min, tp->tm_sec);
time_t t1 = *t + d;
if ((t1 < *t) == (TYPE_SIGNED (time_t) ? d < 0 : TIME_T_MAX / 2 < d))
return t1;
}
/* Overflow occurred one way or another. Return the nearest result
that is actually in range, except don't report a zero difference
if the actual difference is nonzero, as that would cause a false
match; and don't oscillate between two values, as that would
confuse the spring-forward gap detector. */
return (*t < TIME_T_MIDPOINT
? (*t <= TIME_T_MIN + 1 ? *t + 1 : TIME_T_MIN)
: (TIME_T_MAX - 1 <= *t ? *t - 1 : TIME_T_MAX));
}
/* Use CONVERT to convert *T to a broken down time in *TP.
If *T is out of range for conversion, adjust it so that
it is the nearest in-range value and then convert that. */
static struct tm *
ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
time_t *t, struct tm *tp)
{
struct tm *r = convert (t, tp);
if (!r && *t)
{
time_t bad = *t;
time_t ok = 0;
/* BAD is a known unconvertible time_t, and OK is a known good one.
Use binary search to narrow the range between BAD and OK until
they differ by 1. */
while (bad != ok + (bad < 0 ? -1 : 1))
{
time_t mid = *t = (bad < 0
? bad + ((ok - bad) >> 1)
: ok + ((bad - ok) >> 1));
r = convert (t, tp);
if (r)
ok = mid;
else
bad = mid;
}
if (!r && ok)
{
/* The last conversion attempt failed;
revert to the most recent successful attempt. */
*t = ok;
r = convert (t, tp);
}
}
return r;
}
/* Convert *TP to a time_t value, inverting
the monotonic and mostly-unit-linear conversion function CONVERT.
Use *OFFSET to keep track of a guess at the offset of the result,
compared to what the result would be for UTC without leap seconds.
If *OFFSET's guess is correct, only one CONVERT call is needed.
This function is external because it is used also by timegm.c. */
time_t
__mktime_internal (struct tm *tp,
struct tm *(*convert) (const time_t *, struct tm *),
time_t *offset)
{
time_t t, gt, t0, t1, t2;
struct tm tm;
/* The maximum number of probes (calls to CONVERT) should be enough
to handle any combinations of time zone rule changes, solar time,
leap seconds, and oscillations around a spring-forward gap.
POSIX.1 prohibits leap seconds, but some hosts have them anyway. */
int remaining_probes = 6;
/* Time requested. Copy it in case CONVERT modifies *TP; this can
occur if TP is localtime's returned value and CONVERT is localtime. */
int sec = tp->tm_sec;
int min = tp->tm_min;
int hour = tp->tm_hour;
int mday = tp->tm_mday;
int mon = tp->tm_mon;
int year_requested = tp->tm_year;
/* Normalize the value. */
int isdst = ((tp->tm_isdst >> (8 * sizeof (tp->tm_isdst) - 1))
| (tp->tm_isdst != 0));
/* 1 if the previous probe was DST. */
int dst2;
/* Ensure that mon is in range, and set year accordingly. */
int mon_remainder = mon % 12;
int negative_mon_remainder = mon_remainder < 0;
int mon_years = mon / 12 - negative_mon_remainder;
long int lyear_requested = year_requested;
long int year = lyear_requested + mon_years;
/* The other values need not be in range:
the remaining code handles minor overflows correctly,
assuming int and time_t arithmetic wraps around.
Major overflows are caught at the end. */
/* Calculate day of year from year, month, and day of month.
The result need not be in range. */
int mon_yday = ((__mon_yday[leapyear (year)]
[mon_remainder + 12 * negative_mon_remainder])
- 1);
long int lmday = mday;
long int yday = mon_yday + lmday;
time_t guessed_offset = *offset;
int sec_requested = sec;
if (LEAP_SECONDS_POSSIBLE)
{
/* Handle out-of-range seconds specially,
since ydhms_tm_diff assumes every minute has 60 seconds. */
if (sec < 0)
sec = 0;
if (59 < sec)
sec = 59;
}
/* Invert CONVERT by probing. First assume the same offset as last
time. */
t0 = ydhms_diff (year, yday, hour, min, sec,
EPOCH_YEAR - TM_YEAR_BASE, 0, 0, 0, - guessed_offset);
if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
{
/* time_t isn't large enough to rule out overflows, so check
for major overflows. A gross check suffices, since if t0
has overflowed, it is off by a multiple of TIME_T_MAX -
TIME_T_MIN + 1. So ignore any component of the difference
that is bounded by a small value. */
/* Approximate log base 2 of the number of time units per
biennium. A biennium is 2 years; use this unit instead of
years to avoid integer overflow. For example, 2 average
Gregorian years are 2 * 365.2425 * 24 * 60 * 60 seconds,
which is 63113904 seconds, and rint (log2 (63113904)) is
26. */
int ALOG2_SECONDS_PER_BIENNIUM = 26;
int ALOG2_MINUTES_PER_BIENNIUM = 20;
int ALOG2_HOURS_PER_BIENNIUM = 14;
int ALOG2_DAYS_PER_BIENNIUM = 10;
int LOG2_YEARS_PER_BIENNIUM = 1;
int approx_requested_biennia =
(SHR (year_requested, LOG2_YEARS_PER_BIENNIUM)
- SHR (EPOCH_YEAR - TM_YEAR_BASE, LOG2_YEARS_PER_BIENNIUM)
+ SHR (mday, ALOG2_DAYS_PER_BIENNIUM)
+ SHR (hour, ALOG2_HOURS_PER_BIENNIUM)
+ SHR (min, ALOG2_MINUTES_PER_BIENNIUM)
+ (LEAP_SECONDS_POSSIBLE
? 0
: SHR (sec, ALOG2_SECONDS_PER_BIENNIUM)));
int approx_biennia = SHR (t0, ALOG2_SECONDS_PER_BIENNIUM);
int diff = approx_biennia - approx_requested_biennia;
int abs_diff = diff < 0 ? - diff : diff;
/* IRIX 4.0.5 cc miscaculates TIME_T_MIN / 3: it erroneously
gives a positive value of 715827882. Setting a variable
first then doing math on it seems to work.
(ghazi@caip.rutgers.edu) */
time_t time_t_max = TIME_T_MAX;
time_t time_t_min = TIME_T_MIN;
time_t overflow_threshold =
(time_t_max / 3 - time_t_min / 3) >> ALOG2_SECONDS_PER_BIENNIUM;
if (overflow_threshold < abs_diff)
{
/* Overflow occurred. Try repairing it; this might work if
the time zone offset is enough to undo the overflow. */
time_t repaired_t0 = -1 - t0;
approx_biennia = SHR (repaired_t0, ALOG2_SECONDS_PER_BIENNIUM);
diff = approx_biennia - approx_requested_biennia;
abs_diff = diff < 0 ? - diff : diff;
if (overflow_threshold < abs_diff)
return -1;
guessed_offset += repaired_t0 - t0;
t0 = repaired_t0;
}
}
/* Repeatedly use the error to improve the guess. */
for (t = t1 = t2 = t0, dst2 = 0;
(gt = guess_time_tm (year, yday, hour, min, sec, &t,
ranged_convert (convert, &t, &tm)),
t != gt);
t1 = t2, t2 = t, t = gt, dst2 = tm.tm_isdst != 0)
if (t == t1 && t != t2
&& (tm.tm_isdst < 0
|| (isdst < 0
? dst2 <= (tm.tm_isdst != 0)
: (isdst != 0) != (tm.tm_isdst != 0))))
/* We can't possibly find a match, as we are oscillating
between two values. The requested time probably falls
within a spring-forward gap of size GT - T. Follow the common
practice in this case, which is to return a time that is GT - T
away from the requested time, preferring a time whose
tm_isdst differs from the requested value. (If no tm_isdst
was requested and only one of the two values has a nonzero
tm_isdst, prefer that value.) In practice, this is more
useful than returning -1. */
goto offset_found;
else if (--remaining_probes == 0)
return -1;
/* We have a match. Check whether tm.tm_isdst has the requested
value, if any. */
if (isdst != tm.tm_isdst && 0 <= isdst && 0 <= tm.tm_isdst)
{
/* tm.tm_isdst has the wrong value. Look for a neighboring
time with the right value, and use its UTC offset.
Heuristic: probe the adjacent timestamps in both directions,
looking for the desired isdst. This should work for all real
time zone histories in the tz database. */
/* Distance between probes when looking for a DST boundary. In
tzdata2003a, the shortest period of DST is 601200 seconds
(e.g., America/Recife starting 2000-10-08 01:00), and the
shortest period of non-DST surrounded by DST is 694800
seconds (Africa/Tunis starting 1943-04-17 01:00). Use the
minimum of these two values, so we don't miss these short
periods when probing. */
int stride = 601200;
/* The longest period of DST in tzdata2003a is 536454000 seconds
(e.g., America/Jujuy starting 1946-10-01 01:00). The longest
period of non-DST is much longer, but it makes no real sense
to search for more than a year of non-DST, so use the DST
max. */
int duration_max = 536454000;
/* Search in both directions, so the maximum distance is half
the duration; add the stride to avoid off-by-1 problems. */
int delta_bound = duration_max / 2 + stride;
int delta, direction;
for (delta = stride; delta < delta_bound; delta += stride)
for (direction = -1; direction <= 1; direction += 2)
{
time_t ot = t + delta * direction;
if ((ot < t) == (direction < 0))
{
struct tm otm;
ranged_convert (convert, &ot, &otm);
if (otm.tm_isdst == isdst)
{
/* We found the desired tm_isdst.
Extrapolate back to the desired time. */
t = guess_time_tm (year, yday, hour, min, sec, &ot, &otm);
ranged_convert (convert, &t, &tm);
goto offset_found;
}
}
}
}
offset_found:
*offset = guessed_offset + t - t0;
if (LEAP_SECONDS_POSSIBLE && sec_requested != tm.tm_sec)
{
/* Adjust time to reflect the tm_sec requested, not the normalized value.
Also, repair any damage from a false match due to a leap second. */
int sec_adjustment = (sec == 0 && tm.tm_sec == 60) - sec;
t1 = t + sec_requested;
t2 = t1 + sec_adjustment;
if (((t1 < t) != (sec_requested < 0))
| ((t2 < t1) != (sec_adjustment < 0))
| ! convert (&t2, &tm))
return -1;
t = t2;
}
*tp = tm;
return t;
}
/* FIXME: This should use a signed type wide enough to hold any UTC
offset in seconds. 'int' should be good enough for GNU code. We
can't fix this unilaterally though, as other modules invoke
__mktime_internal. */
static time_t localtime_offset;
/* Convert *TP to a time_t value. */
time_t
mktime (struct tm *tp)
{
#ifdef _LIBC
/* POSIX.1 8.1.1 requires that whenever mktime() is called, the
time zone names contained in the external variable `tzname' shall
be set as if the tzset() function had been called. */
__tzset ();
#endif
return __mktime_internal (tp, __localtime_r, &localtime_offset);
}
#ifdef weak_alias
weak_alias (mktime, timelocal)
#endif
#ifdef _LIBC
libc_hidden_def (mktime)
libc_hidden_weak (timelocal)
#endif
#if DEBUG
static int
not_equal_tm (const struct tm *a, const struct tm *b)
{
return ((a->tm_sec ^ b->tm_sec)
| (a->tm_min ^ b->tm_min)
| (a->tm_hour ^ b->tm_hour)
| (a->tm_mday ^ b->tm_mday)
| (a->tm_mon ^ b->tm_mon)
| (a->tm_year ^ b->tm_year)
| (a->tm_yday ^ b->tm_yday)
| (a->tm_isdst ^ b->tm_isdst));
}
static void
print_tm (const struct tm *tp)
{
if (tp)
printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
tp->tm_hour, tp->tm_min, tp->tm_sec,
tp->tm_yday, tp->tm_wday, tp->tm_isdst);
else
printf ("0");
}
static int
check_result (time_t tk, struct tm tmk, time_t tl, const struct tm *lt)
{
if (tk != tl || !lt || not_equal_tm (&tmk, lt))
{
printf ("mktime (");
print_tm (lt);
printf (")\nyields (");
print_tm (&tmk);
printf (") == %ld, should be %ld\n", (long int) tk, (long int) tl);
return 1;
}
return 0;
}
int
main (int argc, char **argv)
{
int status = 0;
struct tm tm, tmk, tml;
struct tm *lt;
time_t tk, tl, tl1;
char trailer;
if ((argc == 3 || argc == 4)
&& (sscanf (argv[1], "%d-%d-%d%c",
&tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
== 3)
&& (sscanf (argv[2], "%d:%d:%d%c",
&tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
== 3))
{
tm.tm_year -= TM_YEAR_BASE;
tm.tm_mon--;
tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
tmk = tm;
tl = mktime (&tmk);
lt = localtime (&tl);
if (lt)
{
tml = *lt;
lt = &tml;
}
printf ("mktime returns %ld == ", (long int) tl);
print_tm (&tmk);
printf ("\n");
status = check_result (tl, tmk, tl, lt);
}
else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
{
time_t from = atol (argv[1]);
time_t by = atol (argv[2]);
time_t to = atol (argv[3]);
if (argc == 4)
for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1)
{
lt = localtime (&tl);
if (lt)
{
tmk = tml = *lt;
tk = mktime (&tmk);
status |= check_result (tk, tmk, tl, &tml);
}
else
{
printf ("localtime (%ld) yields 0\n", (long int) tl);
status = 1;
}
tl1 = tl + by;
if ((tl1 < tl) != (by < 0))
break;
}
else
for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1)
{
/* Null benchmark. */
lt = localtime (&tl);
if (lt)
{
tmk = tml = *lt;
tk = tl;
status |= check_result (tk, tmk, tl, &tml);
}
else
{
printf ("localtime (%ld) yields 0\n", (long int) tl);
status = 1;
}
tl1 = tl + by;
if ((tl1 < tl) != (by < 0))
break;
}
}
else
printf ("Usage:\
\t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
\t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
\t%s FROM BY TO - # Do not test those values (for benchmark).\n",
argv[0], argv[0], argv[0]);
return status;
}
#endif /* DEBUG */
/*
Local Variables:
compile-command: "gcc -DDEBUG -Wall -W -O -g mktime.c -o mktime"
End:
*/

118
gl/time.in.h Normal file
View file

@ -0,0 +1,118 @@
/* A more-standard <time.h>.
Copyright (C) 2007-2008 Free Software Foundation, Inc.
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
the Free Software Foundation; either version 3, or (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
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#if __GNUC__ >= 3
@PRAGMA_SYSTEM_HEADER@
#endif
/* Don't get in the way of glibc when it includes time.h merely to
declare a few standard symbols, rather than to declare all the
symbols. Also, Solaris 8 <time.h> eventually includes itself
recursively; if that is happening, just include the system <time.h>
without adding our own declarations. */
#if (defined __need_time_t || defined __need_clock_t \
|| defined __need_timespec \
|| defined _GL_TIME_H)
# @INCLUDE_NEXT@ @NEXT_TIME_H@
#else
# define _GL_TIME_H
# @INCLUDE_NEXT@ @NEXT_TIME_H@
# ifdef __cplusplus
extern "C" {
# endif
/* Some systems don't define struct timespec (e.g., AIX 4.1, Ultrix 4.3).
Or they define it with the wrong member names or define it in <sys/time.h>
(e.g., FreeBSD circa 1997). */
# if ! @TIME_H_DEFINES_STRUCT_TIMESPEC@
# if @SYS_TIME_H_DEFINES_STRUCT_TIMESPEC@
# include <sys/time.h>
# else
# undef timespec
# define timespec rpl_timespec
struct timespec
{
time_t tv_sec;
long int tv_nsec;
};
# endif
# endif
/* Sleep for at least RQTP seconds unless interrupted, If interrupted,
return -1 and store the remaining time into RMTP. See
<http://www.opengroup.org/susv3xsh/nanosleep.html>. */
# if @REPLACE_NANOSLEEP@
# define nanosleep rpl_nanosleep
int nanosleep (struct timespec const *__rqtp, struct timespec *__rmtp);
# endif
/* Convert TIMER to RESULT, assuming local time and UTC respectively. See
<http://www.opengroup.org/susv3xsh/localtime_r.html> and
<http://www.opengroup.org/susv3xsh/gmtime_r.html>. */
# if @REPLACE_LOCALTIME_R@
# undef localtime_r
# define localtime_r rpl_localtime_r
# undef gmtime_r
# define gmtime_r rpl_gmtime_r
struct tm *localtime_r (time_t const *restrict __timer,
struct tm *restrict __result);
struct tm *gmtime_r (time_t const *restrict __timer,
struct tm *restrict __result);
# endif
/* Parse BUF as a time stamp, assuming FORMAT specifies its layout, and store
the resulting broken-down time into TM. See
<http://www.opengroup.org/susv3xsh/strptime.html>. */
# if @REPLACE_STRPTIME@
# undef strptime
# define strptime rpl_strptime
char *strptime (char const *restrict __buf, char const *restrict __format,
struct tm *restrict __tm);
# endif
/* Convert TM to a time_t value, assuming UTC. */
# if @REPLACE_TIMEGM@
# undef timegm
# define timegm rpl_timegm
time_t timegm (struct tm *__tm);
# endif
/* Encourage applications to avoid unsafe functions that can overrun
buffers when given outlandish struct tm values. Portable
applications should use strftime (or even sprintf) instead. */
# if GNULIB_PORTCHECK
# undef asctime
# define asctime eschew_asctime
# undef asctime_r
# define asctime_r eschew_asctime_r
# undef ctime
# define ctime eschew_ctime
# undef ctime_r
# define ctime_r eschew_ctime_r
# endif
# ifdef __cplusplus
}
# endif
#endif

47
gl/time_r.c Normal file
View file

@ -0,0 +1,47 @@
/* Reentrant time functions like localtime_r.
Copyright (C) 2003, 2006, 2007 Free Software Foundation, Inc.
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
the Free Software Foundation; either version 3, or (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 along
with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* Written by Paul Eggert. */
#include <config.h>
#include <time.h>
#include <string.h>
static struct tm *
copy_tm_result (struct tm *dest, struct tm const *src)
{
if (! src)
return 0;
*dest = *src;
return dest;
}
struct tm *
gmtime_r (time_t const * restrict t, struct tm * restrict tp)
{
return copy_tm_result (tp, gmtime (t));
}
struct tm *
localtime_r (time_t const * restrict t, struct tm * restrict tp)
{
return copy_tm_result (tp, localtime (t));
}

41
gl/timegm.c Normal file
View file

@ -0,0 +1,41 @@
/* Convert UTC calendar time to simple time. Like mktime but assumes UTC.
Copyright (C) 1994, 1997, 2003, 2004, 2006, 2007 Free Software
Foundation, Inc. This file is part of the GNU C Library.
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
the Free Software Foundation; either version 3, or (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
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#ifndef _LIBC
# include <config.h>
#endif
#include <time.h>
#ifndef _LIBC
# undef __gmtime_r
# define __gmtime_r gmtime_r
# define __mktime_internal mktime_internal
time_t __mktime_internal (struct tm *,
struct tm * (*) (time_t const *, struct tm *),
time_t *);
#endif
time_t
timegm (struct tm *tmp)
{
static time_t gmtime_offset;
tmp->tm_isdst = 0;
return __mktime_internal (tmp, __gmtime_r, &gmtime_offset);
}