📄 mktime.c
字号:
/* Convert a `struct tm' to a time_t value. Copyright (C) 1993-1999, 2002-2005, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Paul Eggert <eggert@twinsun.com>. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *//* Define this to have a standalone program to test this implementation of mktime. *//* #define DEBUG 1 */#ifdef HAVE_CONFIG_H# 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 <sys/types.h> /* Some systems define `time_t' here. */#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 1900verify (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 intleapyear (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 _LIBCstatic#endifconst 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_r.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. */# include "time_r.h"# 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_tydhms_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_tguess_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; int isdst = tp->tm_isdst; /* 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -