2000-02-18 03:39:52 +08:00
|
|
|
/*
|
|
|
|
* mktime.c
|
|
|
|
* Original Author: G. Haley
|
|
|
|
*
|
|
|
|
* Converts the broken-down time, expressed as local time, in the structure
|
|
|
|
* pointed to by tim_p into a calendar time value. The original values of the
|
|
|
|
* tm_wday and tm_yday fields of the structure are ignored, and the original
|
|
|
|
* values of the other fields have no restrictions. On successful completion
|
|
|
|
* the fields of the structure are set to represent the specified calendar
|
|
|
|
* time. Returns the specified calendar time. If the calendar time can not be
|
|
|
|
* represented, returns the value (time_t) -1.
|
2008-08-29 02:18:12 +08:00
|
|
|
*
|
|
|
|
* Modifications: Fixed tm_isdst usage - 27 August 2008 Craig Howland.
|
2000-02-18 03:39:52 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
FUNCTION
|
|
|
|
<<mktime>>---convert time to arithmetic representation
|
|
|
|
|
|
|
|
INDEX
|
|
|
|
mktime
|
|
|
|
|
|
|
|
ANSI_SYNOPSIS
|
|
|
|
#include <time.h>
|
|
|
|
time_t mktime(struct tm *<[timp]>);
|
|
|
|
|
|
|
|
TRAD_SYNOPSIS
|
|
|
|
#include <time.h>
|
|
|
|
time_t mktime(<[timp]>)
|
|
|
|
struct tm *<[timp]>;
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
<<mktime>> assumes the time at <[timp]> is a local time, and converts
|
|
|
|
its representation from the traditional representation defined by
|
|
|
|
<<struct tm>> into a representation suitable for arithmetic.
|
|
|
|
|
|
|
|
<<localtime>> is the inverse of <<mktime>>.
|
|
|
|
|
|
|
|
RETURNS
|
|
|
|
If the contents of the structure at <[timp]> do not form a valid
|
|
|
|
calendar time representation, the result is <<-1>>. Otherwise, the
|
|
|
|
result is the time, converted to a <<time_t>> value.
|
|
|
|
|
|
|
|
PORTABILITY
|
|
|
|
ANSI C requires <<mktime>>.
|
|
|
|
|
|
|
|
<<mktime>> requires no supporting OS subroutines.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <time.h>
|
2002-04-18 05:23:31 +08:00
|
|
|
#include "local.h"
|
2000-02-18 03:39:52 +08:00
|
|
|
|
2001-03-06 05:07:20 +08:00
|
|
|
#define _SEC_IN_MINUTE 60L
|
|
|
|
#define _SEC_IN_HOUR 3600L
|
|
|
|
#define _SEC_IN_DAY 86400L
|
2000-02-18 03:39:52 +08:00
|
|
|
|
|
|
|
static _CONST int DAYS_IN_MONTH[12] =
|
|
|
|
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
|
|
|
|
|
|
|
#define _DAYS_IN_MONTH(x) ((x == 1) ? days_in_feb : DAYS_IN_MONTH[x])
|
|
|
|
|
|
|
|
static _CONST int _DAYS_BEFORE_MONTH[12] =
|
|
|
|
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
|
|
|
|
|
|
|
|
#define _ISLEAP(y) (((y) % 4) == 0 && (((y) % 100) != 0 || (((y)+1900) % 400) == 0))
|
|
|
|
#define _DAYS_IN_YEAR(year) (_ISLEAP(year) ? 366 : 365)
|
|
|
|
|
|
|
|
static void
|
2008-12-11 Craig Howland <howland@LGSInnovations.com>
* libc/include/sys/lock.h: Add void cast to avoid "statement has no
effect" warnings from gcc.
* libc/include/sys/stdio.h: Ditto.
* libc/include/sys/time.h: Correct gettimeofday() prototype.
* libc/stdlib/__exp10.c: Add #include "std.h" for function prototype.
* libc/stdlib/__ten_mu.c: Ditto.
* libc/stdlib/std.h: Correct __exp10's ANSI prototype.
* libc/stdlib/ldtoa.c: Change eiisinf definition to ANSI form. (Are
already others in file without _ansi method, so did not bother.)
* libc/stdlib/system.c: Use _ansi forms for function prototypes and
definitions.
* libc/time/mktime.c: Ditto.
* libc/misc/__dprintf.c: Ditto.
* libc/include/stdio.h: Add function prototypes for _fgetc_r,
_fgetpos_r, _fsetpos_r, _freopen_r, _rewind_r, freopen64, _freopen64_r,
_funopen_r, and _fopencookie_r.
* libc/include/reent.h: Add function prototype for _stat64_r, align
_execve_r prototype with POSIX definition for execve.
* libc/reent/execr.c: Align function prototype with POSIX definition.
* libc/stdio/asniprintf.c: Add #include "local.h".
* libc/stdio/vasniprintf.c: Ditto.
* libc/stdio/fread.c: Remove unused variable newcount.
* libc/stdio/local.h: Add function prototype for __sccl.
* libc/stdio/open_memstream.c: Remove unused variable flags.
* libc/stdio/vfscanf.c: Proper prototyping for ccfn, remove prototype
for __sccl since now in local.h.
* libc/string/memcpy.c: Add #include <string.h> (for real and for
traditional synopsis), remove extraneous stddef.h and limits.h.
* libc/syscalls/sysclose.c: Add #include <unistd.h>.
* libc/syscalls/sysfork.c: Ditto.
* libc/syscalls/sysgetpid.c: Ditto.
* libc/syscalls/sysexecve.c: Add #include <unistd.h>, align function
prototype with POSIX definition.
* libc/syscalls/sysfstat.c: Add #include <sys/stat.h>.
* libc/syscalls/sysgettod.c: Correct sys/times.h to sys/time.h.
* libc/syscalls/syskill.c: Add #include <signal.h>.
* libc/syscalls/syslink.c: Add #include <unistd.h>, fix prototype.
* libc/syscalls/sysunlink.c: Ditto.
* libc/syscalls/sysstat.c: Add #include <sys/stat.h>, fix prototype.
* libc/syscalls/syswait.c: Add #include <sys/wait.h>, fix prototype.
2008-12-12 01:27:56 +08:00
|
|
|
_DEFUN(validate_structure, (tim_p),
|
|
|
|
struct tm *tim_p)
|
2000-02-18 03:39:52 +08:00
|
|
|
{
|
|
|
|
div_t res;
|
|
|
|
int days_in_feb = 28;
|
|
|
|
|
|
|
|
/* calculate time & date to account for out of range values */
|
|
|
|
if (tim_p->tm_sec < 0 || tim_p->tm_sec > 59)
|
|
|
|
{
|
|
|
|
res = div (tim_p->tm_sec, 60);
|
|
|
|
tim_p->tm_min += res.quot;
|
|
|
|
if ((tim_p->tm_sec = res.rem) < 0)
|
|
|
|
{
|
|
|
|
tim_p->tm_sec += 60;
|
|
|
|
--tim_p->tm_min;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tim_p->tm_min < 0 || tim_p->tm_min > 59)
|
|
|
|
{
|
|
|
|
res = div (tim_p->tm_min, 60);
|
|
|
|
tim_p->tm_hour += res.quot;
|
|
|
|
if ((tim_p->tm_min = res.rem) < 0)
|
|
|
|
{
|
|
|
|
tim_p->tm_min += 60;
|
|
|
|
--tim_p->tm_hour;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tim_p->tm_hour < 0 || tim_p->tm_hour > 23)
|
|
|
|
{
|
|
|
|
res = div (tim_p->tm_hour, 24);
|
|
|
|
tim_p->tm_mday += res.quot;
|
|
|
|
if ((tim_p->tm_hour = res.rem) < 0)
|
|
|
|
{
|
|
|
|
tim_p->tm_hour += 24;
|
|
|
|
--tim_p->tm_mday;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-19 22:14:18 +08:00
|
|
|
if (tim_p->tm_mon < 0 || tim_p->tm_mon > 11)
|
2000-02-18 03:39:52 +08:00
|
|
|
{
|
|
|
|
res = div (tim_p->tm_mon, 12);
|
|
|
|
tim_p->tm_year += res.quot;
|
|
|
|
if ((tim_p->tm_mon = res.rem) < 0)
|
|
|
|
{
|
|
|
|
tim_p->tm_mon += 12;
|
|
|
|
--tim_p->tm_year;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_DAYS_IN_YEAR (tim_p->tm_year) == 366)
|
|
|
|
days_in_feb = 29;
|
|
|
|
|
|
|
|
if (tim_p->tm_mday <= 0)
|
|
|
|
{
|
|
|
|
while (tim_p->tm_mday <= 0)
|
|
|
|
{
|
|
|
|
if (--tim_p->tm_mon == -1)
|
|
|
|
{
|
|
|
|
tim_p->tm_year--;
|
|
|
|
tim_p->tm_mon = 11;
|
|
|
|
days_in_feb =
|
|
|
|
((_DAYS_IN_YEAR (tim_p->tm_year) == 366) ?
|
|
|
|
29 : 28);
|
|
|
|
}
|
|
|
|
tim_p->tm_mday += _DAYS_IN_MONTH (tim_p->tm_mon);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while (tim_p->tm_mday > _DAYS_IN_MONTH (tim_p->tm_mon))
|
|
|
|
{
|
|
|
|
tim_p->tm_mday -= _DAYS_IN_MONTH (tim_p->tm_mon);
|
|
|
|
if (++tim_p->tm_mon == 12)
|
|
|
|
{
|
|
|
|
tim_p->tm_year++;
|
|
|
|
tim_p->tm_mon = 0;
|
|
|
|
days_in_feb =
|
|
|
|
((_DAYS_IN_YEAR (tim_p->tm_year) == 366) ?
|
|
|
|
29 : 28);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
time_t
|
2008-12-11 Craig Howland <howland@LGSInnovations.com>
* libc/include/sys/lock.h: Add void cast to avoid "statement has no
effect" warnings from gcc.
* libc/include/sys/stdio.h: Ditto.
* libc/include/sys/time.h: Correct gettimeofday() prototype.
* libc/stdlib/__exp10.c: Add #include "std.h" for function prototype.
* libc/stdlib/__ten_mu.c: Ditto.
* libc/stdlib/std.h: Correct __exp10's ANSI prototype.
* libc/stdlib/ldtoa.c: Change eiisinf definition to ANSI form. (Are
already others in file without _ansi method, so did not bother.)
* libc/stdlib/system.c: Use _ansi forms for function prototypes and
definitions.
* libc/time/mktime.c: Ditto.
* libc/misc/__dprintf.c: Ditto.
* libc/include/stdio.h: Add function prototypes for _fgetc_r,
_fgetpos_r, _fsetpos_r, _freopen_r, _rewind_r, freopen64, _freopen64_r,
_funopen_r, and _fopencookie_r.
* libc/include/reent.h: Add function prototype for _stat64_r, align
_execve_r prototype with POSIX definition for execve.
* libc/reent/execr.c: Align function prototype with POSIX definition.
* libc/stdio/asniprintf.c: Add #include "local.h".
* libc/stdio/vasniprintf.c: Ditto.
* libc/stdio/fread.c: Remove unused variable newcount.
* libc/stdio/local.h: Add function prototype for __sccl.
* libc/stdio/open_memstream.c: Remove unused variable flags.
* libc/stdio/vfscanf.c: Proper prototyping for ccfn, remove prototype
for __sccl since now in local.h.
* libc/string/memcpy.c: Add #include <string.h> (for real and for
traditional synopsis), remove extraneous stddef.h and limits.h.
* libc/syscalls/sysclose.c: Add #include <unistd.h>.
* libc/syscalls/sysfork.c: Ditto.
* libc/syscalls/sysgetpid.c: Ditto.
* libc/syscalls/sysexecve.c: Add #include <unistd.h>, align function
prototype with POSIX definition.
* libc/syscalls/sysfstat.c: Add #include <sys/stat.h>.
* libc/syscalls/sysgettod.c: Correct sys/times.h to sys/time.h.
* libc/syscalls/syskill.c: Add #include <signal.h>.
* libc/syscalls/syslink.c: Add #include <unistd.h>, fix prototype.
* libc/syscalls/sysunlink.c: Ditto.
* libc/syscalls/sysstat.c: Add #include <sys/stat.h>, fix prototype.
* libc/syscalls/syswait.c: Add #include <sys/wait.h>, fix prototype.
2008-12-12 01:27:56 +08:00
|
|
|
_DEFUN(mktime, (tim_p),
|
|
|
|
struct tm *tim_p)
|
2000-02-18 03:39:52 +08:00
|
|
|
{
|
|
|
|
time_t tim = 0;
|
|
|
|
long days = 0;
|
2011-08-19 22:14:18 +08:00
|
|
|
int year, isdst=0;
|
2005-02-24 03:08:58 +08:00
|
|
|
__tzinfo_type *tz = __gettzinfo ();
|
2000-02-18 03:39:52 +08:00
|
|
|
|
|
|
|
/* validate structure */
|
|
|
|
validate_structure (tim_p);
|
|
|
|
|
|
|
|
/* compute hours, minutes, seconds */
|
|
|
|
tim += tim_p->tm_sec + (tim_p->tm_min * _SEC_IN_MINUTE) +
|
|
|
|
(tim_p->tm_hour * _SEC_IN_HOUR);
|
|
|
|
|
|
|
|
/* compute days in year */
|
|
|
|
days += tim_p->tm_mday - 1;
|
|
|
|
days += _DAYS_BEFORE_MONTH[tim_p->tm_mon];
|
|
|
|
if (tim_p->tm_mon > 1 && _DAYS_IN_YEAR (tim_p->tm_year) == 366)
|
|
|
|
days++;
|
|
|
|
|
|
|
|
/* compute day of the year */
|
|
|
|
tim_p->tm_yday = days;
|
|
|
|
|
2011-10-11 19:28:05 +08:00
|
|
|
if (tim_p->tm_year > 10000 || tim_p->tm_year < -10000)
|
2000-02-18 03:39:52 +08:00
|
|
|
return (time_t) -1;
|
|
|
|
|
|
|
|
/* compute days in other years */
|
2011-10-11 19:28:05 +08:00
|
|
|
if ((year = tim_p->tm_year) > 70)
|
2000-02-18 03:39:52 +08:00
|
|
|
{
|
|
|
|
for (year = 70; year < tim_p->tm_year; year++)
|
|
|
|
days += _DAYS_IN_YEAR (year);
|
|
|
|
}
|
2011-10-11 19:28:05 +08:00
|
|
|
else if (year < 70)
|
2000-02-18 03:39:52 +08:00
|
|
|
{
|
|
|
|
for (year = 69; year > tim_p->tm_year; year--)
|
|
|
|
days -= _DAYS_IN_YEAR (year);
|
|
|
|
days -= _DAYS_IN_YEAR (year);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* compute total seconds */
|
|
|
|
tim += (days * _SEC_IN_DAY);
|
|
|
|
|
2011-06-27 18:13:11 +08:00
|
|
|
TZ_LOCK;
|
|
|
|
|
2015-03-31 17:22:50 +08:00
|
|
|
_tzset_unlocked ();
|
|
|
|
|
2002-04-18 05:23:31 +08:00
|
|
|
if (_daylight)
|
|
|
|
{
|
2011-08-19 22:14:18 +08:00
|
|
|
int tm_isdst;
|
2002-04-18 05:23:31 +08:00
|
|
|
int y = tim_p->tm_year + YEAR_BASE;
|
2011-08-19 22:14:18 +08:00
|
|
|
/* Convert user positive into 1 */
|
|
|
|
tm_isdst = tim_p->tm_isdst > 0 ? 1 : tim_p->tm_isdst;
|
|
|
|
isdst = tm_isdst;
|
|
|
|
|
2005-02-24 03:08:58 +08:00
|
|
|
if (y == tz->__tzyear || __tzcalc_limits (y))
|
2002-04-18 05:23:31 +08:00
|
|
|
{
|
|
|
|
/* calculate start of dst in dst local time and
|
|
|
|
start of std in both std local time and dst local time */
|
2005-02-26 06:31:21 +08:00
|
|
|
time_t startdst_dst = tz->__tzrule[0].change
|
|
|
|
- (time_t) tz->__tzrule[1].offset;
|
|
|
|
time_t startstd_dst = tz->__tzrule[1].change
|
|
|
|
- (time_t) tz->__tzrule[1].offset;
|
|
|
|
time_t startstd_std = tz->__tzrule[1].change
|
|
|
|
- (time_t) tz->__tzrule[0].offset;
|
2002-04-18 05:23:31 +08:00
|
|
|
/* if the time is in the overlap between dst and std local times */
|
|
|
|
if (tim >= startstd_std && tim < startstd_dst)
|
|
|
|
; /* we let user decide or leave as -1 */
|
|
|
|
else
|
|
|
|
{
|
2005-02-24 03:08:58 +08:00
|
|
|
isdst = (tz->__tznorth
|
2002-04-18 05:23:31 +08:00
|
|
|
? (tim >= startdst_dst && tim < startstd_std)
|
|
|
|
: (tim >= startdst_dst || tim < startstd_std));
|
2008-08-29 02:18:12 +08:00
|
|
|
/* if user committed and was wrong, perform correction, but not
|
|
|
|
* if the user has given a negative value (which
|
|
|
|
* asks mktime() to determine if DST is in effect or not) */
|
|
|
|
if (tm_isdst >= 0 && (isdst ^ tm_isdst) == 1)
|
2002-04-18 05:23:31 +08:00
|
|
|
{
|
|
|
|
/* we either subtract or add the difference between
|
2005-02-26 06:31:21 +08:00
|
|
|
time zone offsets, depending on which way the user got it
|
|
|
|
wrong. The diff is typically one hour, or 3600 seconds,
|
|
|
|
and should fit in a 16-bit int, even though offset
|
|
|
|
is a long to accomodate 12 hours. */
|
|
|
|
int diff = (int) (tz->__tzrule[0].offset
|
|
|
|
- tz->__tzrule[1].offset);
|
2002-04-18 05:23:31 +08:00
|
|
|
if (!isdst)
|
|
|
|
diff = -diff;
|
|
|
|
tim_p->tm_sec += diff;
|
|
|
|
tim += diff; /* we also need to correct our current time calculation */
|
2011-10-11 19:28:05 +08:00
|
|
|
int mday = tim_p->tm_mday;
|
|
|
|
validate_structure (tim_p);
|
|
|
|
mday = tim_p->tm_mday - mday;
|
|
|
|
/* roll over occurred */
|
|
|
|
if (mday) {
|
|
|
|
/* compensate for month roll overs */
|
|
|
|
if (mday > 1)
|
|
|
|
mday = -1;
|
|
|
|
else if (mday < -1)
|
|
|
|
mday = 1;
|
|
|
|
/* update days for wday calculation */
|
|
|
|
days += mday;
|
|
|
|
/* handle yday */
|
|
|
|
if ((tim_p->tm_yday += mday) < 0) {
|
|
|
|
--year;
|
|
|
|
tim_p->tm_yday = _DAYS_IN_YEAR(year) - 1;
|
|
|
|
} else {
|
|
|
|
mday = _DAYS_IN_YEAR(year);
|
|
|
|
if (tim_p->tm_yday > (mday - 1))
|
|
|
|
tim_p->tm_yday -= mday;
|
|
|
|
}
|
|
|
|
}
|
2002-04-18 05:23:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add appropriate offset to put time in gmt format */
|
|
|
|
if (isdst == 1)
|
2005-02-26 06:31:21 +08:00
|
|
|
tim += (time_t) tz->__tzrule[1].offset;
|
2002-04-18 05:23:31 +08:00
|
|
|
else /* otherwise assume std time */
|
2005-02-26 06:31:21 +08:00
|
|
|
tim += (time_t) tz->__tzrule[0].offset;
|
2002-04-18 05:23:31 +08:00
|
|
|
|
2011-06-27 18:13:11 +08:00
|
|
|
TZ_UNLOCK;
|
|
|
|
|
2002-04-18 05:23:31 +08:00
|
|
|
/* reset isdst flag to what we have calculated */
|
|
|
|
tim_p->tm_isdst = isdst;
|
|
|
|
|
2011-10-11 19:28:05 +08:00
|
|
|
/* compute day of the week */
|
|
|
|
if ((tim_p->tm_wday = (days + 4) % 7) < 0)
|
|
|
|
tim_p->tm_wday += 7;
|
|
|
|
|
2000-02-18 03:39:52 +08:00
|
|
|
return tim;
|
|
|
|
}
|