Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/811198/?format=api
{ "id": 811198, "url": "http://patchwork.ozlabs.org/api/patches/811198/?format=api", "web_url": "http://patchwork.ozlabs.org/project/glibc/patch/20170907224219.12483-5-albert.aribaud@3adev.fr/", "project": { "id": 41, "url": "http://patchwork.ozlabs.org/api/projects/41/?format=api", "name": "GNU C Library", "link_name": "glibc", "list_id": "libc-alpha.sourceware.org", "list_email": "libc-alpha@sourceware.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20170907224219.12483-5-albert.aribaud@3adev.fr>", "list_archive_url": null, "date": "2017-09-07T22:41:31", "name": "[RFC,04/52] Y2038: add function __mktime64 (and timelocal)", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "77fc7b9df653605ac352698c60ee10983de30252", "submitter": { "id": 65557, "url": "http://patchwork.ozlabs.org/api/people/65557/?format=api", "name": "Albert ARIBAUD (3ADEV)", "email": "albert.aribaud@3adev.fr" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/glibc/patch/20170907224219.12483-5-albert.aribaud@3adev.fr/mbox/", "series": [ { "id": 2074, "url": "http://patchwork.ozlabs.org/api/series/2074/?format=api", "web_url": "http://patchwork.ozlabs.org/project/glibc/list/?series=2074", "date": "2017-09-07T22:41:27", "name": "Make GLIBC Y2038-proof", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/2074/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/811198/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/811198/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<libc-alpha-return-84322-incoming=patchwork.ozlabs.org@sourceware.org>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": [ "patchwork-incoming@bilbo.ozlabs.org", "mailing list libc-alpha@sourceware.org" ], "Authentication-Results": [ "ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=sourceware.org\n\t(client-ip=209.132.180.131; helo=sourceware.org;\n\tenvelope-from=libc-alpha-return-84322-incoming=patchwork.ozlabs.org@sourceware.org;\n\treceiver=<UNKNOWN>)", "ozlabs.org; dkim=pass (1024-bit key;\n\tsecure) header.d=sourceware.org header.i=@sourceware.org\n\theader.b=\"aJbo+r+k\"; dkim-atps=neutral", "sourceware.org; auth=none" ], "Received": [ "from sourceware.org (server1.sourceware.org [209.132.180.131])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xpFpq6VzGz9sDB\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 8 Sep 2017 08:43:15 +1000 (AEST)", "(qmail 60826 invoked by alias); 7 Sep 2017 22:42:50 -0000", "(qmail 60619 invoked by uid 89); 7 Sep 2017 22:42:49 -0000" ], "DomainKey-Signature": "a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id\n\t:list-unsubscribe:list-subscribe:list-archive:list-post\n\t:list-help:sender:from:to:cc:subject:date:message-id:in-reply-to\n\t:references; q=dns; s=default; b=IWEOvCfJ7y6GZN5D3FGWRUqmJY17yMA\n\tlJSwh7Ldk7qFebRwO6oPjGxly5MO9OnfuzlJJVzX3XVvbGApz6KmeIAO/R5tzXck\n\tMPyvtGuVMK/vmlGjqTeRNImc6sk4XJuxz3v3XKv4Dryjml6mN74uqsu+kBhCEv2k\n\tMn0yTuByyRF0=", "DKIM-Signature": "v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id\n\t:list-unsubscribe:list-subscribe:list-archive:list-post\n\t:list-help:sender:from:to:cc:subject:date:message-id:in-reply-to\n\t:references; s=default; bh=II0UXmXCihw2dlq3payigheTRUM=; b=aJbo+\n\tr+kYi+G/O00J1Ug8PljC+YWJ1YSCY6K7LRqbTXQ6Mv+0vtGykelTZ04b/zoHYCTY\n\tkfHv5plahPYYlsOaewf+cmV7LVZVA2miaO0N01pYd23JhuvibS3lQnUPb34pOr4j\n\tUWrnN1H7V+sGnJnw0lvyOi+TPsSe49PWaENu5Y=", "Mailing-List": "contact libc-alpha-help@sourceware.org; run by ezmlm", "Precedence": "bulk", "List-Id": "<libc-alpha.sourceware.org>", "List-Unsubscribe": "<mailto:libc-alpha-unsubscribe-incoming=patchwork.ozlabs.org@sourceware.org>", "List-Subscribe": "<mailto:libc-alpha-subscribe@sourceware.org>", "List-Archive": "<http://sourceware.org/ml/libc-alpha/>", "List-Post": "<mailto:libc-alpha@sourceware.org>", "List-Help": "<mailto:libc-alpha-help@sourceware.org>,\n\t<http://sourceware.org/ml/#faqs>", "Sender": "libc-alpha-owner@sourceware.org", "X-Virus-Found": "No", "X-Spam-SWARE-Status": "No, score=-26.6 required=5.0 tests=BAYES_00, GIT_PATCH_0,\n\tGIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3,\n\tKAM_LAZY_DOMAIN_SECURITY,\n\tRCVD_IN_DNSWL_LOW autolearn=ham version=3.3.2 spammy=periods,\n\trepair, b100, africa", "X-HELO": "smtp6-g21.free.fr", "From": "\"Albert ARIBAUD (3ADEV)\" <albert.aribaud@3adev.fr>", "To": "libc-alpha@sourceware.org", "Cc": "\"Albert ARIBAUD (3ADEV)\" <albert.aribaud@3adev.fr>", "Subject": "[RFC PATCH 04/52] Y2038: add function __mktime64 (and timelocal)", "Date": "Fri, 8 Sep 2017 00:41:31 +0200", "Message-Id": "<20170907224219.12483-5-albert.aribaud@3adev.fr>", "In-Reply-To": "<20170907224219.12483-4-albert.aribaud@3adev.fr>", "References": "<20170907224219.12483-1-albert.aribaud@3adev.fr>\n\t<20170907224219.12483-2-albert.aribaud@3adev.fr>\n\t<20170907224219.12483-3-albert.aribaud@3adev.fr>\n\t<20170907224219.12483-4-albert.aribaud@3adev.fr>" }, "content": "__mktime64 is designed similar to mktime, including checks on (64-bit)\ninteger limits, and respects the same Posix requirements as __mktime does,\ni.e. calls tzset().\n\ntimelocal is a macro which evaluates to mktime, so when APIs are enabled,\nboth mktime and timelocal will become Y2038-proof\n\nAlso, the implementation does not require a Y2038-proof kernel.\n\nSigned-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>\n---\n include/time.h | 9 +\n sysdeps/unix/sysv/linux/arm/Versions | 1 +\n time/mktime.c | 403 +++++++++++++++++++++++++++++++++++\n 3 files changed, 413 insertions(+)", "diff": "diff --git a/include/time.h b/include/time.h\nindex d2b1080fd6..79ab6ab6a1 100644\n--- a/include/time.h\n+++ b/include/time.h\n@@ -57,6 +57,15 @@ extern time_t __mktime_internal (struct tm *__tp,\n \t\t\t\t struct tm *(*__func) (const time_t *,\n \t\t\t\t\t\t struct tm *),\n \t\t\t\t time_t *__offset);\n+\n+/* Subroutine of `__mktime64'. Return the `__time64_t' representation of TP and\n+ normalize TP, given that a `struct tm *' maps to a `__time64_t' as performed\n+ by FUNC. Keep track of next guess for __time64_t offset in *OFFSET. */\n+extern __time64_t __mktime64_internal (struct tm *__tp,\n+\t\t\t\t struct tm *(*__func) (const __time64_t *,\n+\t\t\t\t\t\t struct tm *),\n+\t\t\t\t __time64_t *__offset);\n+\n extern struct tm *__localtime_r (const time_t *__timer,\n \t\t\t\t struct tm *__tp) attribute_hidden;\n \ndiff --git a/sysdeps/unix/sysv/linux/arm/Versions b/sysdeps/unix/sysv/linux/arm/Versions\nindex dd6a160c75..546d7c60ee 100644\n--- a/sysdeps/unix/sysv/linux/arm/Versions\n+++ b/sysdeps/unix/sysv/linux/arm/Versions\n@@ -25,5 +25,6 @@ libc {\n __ctime64; __ctime64_r;\n __gmtime64; __gmtime64_r;\n __localtime64; __localtime64_r;\n+ __mktime64; __timelocal64_r;\n }\n }\ndiff --git a/time/mktime.c b/time/mktime.c\nindex 4c48d358a1..c0ba4e5761 100644\n--- a/time/mktime.c\n+++ b/time/mktime.c\n@@ -599,6 +599,409 @@ weak_alias (mktime, timelocal)\n libc_hidden_def (mktime)\n libc_hidden_weak (timelocal)\n #endif\n+\n+/* Return an integer value measuring (YEAR1-YDAY1 HOUR1:MIN1:SEC1) -\n+ (YEAR0-YDAY0 HOUR0:MIN0:SEC0) in seconds, assuming that the clocks\n+ were not adjusted between the time stamps.\n+\n+ The YEAR values uses the same numbering as TP->tm_year. Values\n+ need not be in the usual range. However, YEAR1 must not be less\n+ than 2 * INT_MIN or greater than 2 * INT_MAX.\n+\n+ The result may overflow. It is the caller's responsibility to\n+ detect overflow. */\n+\n+static __time64_t\n+ydhms64_diff (long_int year1, long_int yday1, int hour1, int min1, int sec1,\n+\t int year0, int yday0, int hour0, int min0, int sec0)\n+{\n+ verify (C99_integer_division, -1 / 2 == 0);\n+\n+ /* Compute intervening leap days correctly even if year is negative.\n+ Take care to avoid integer overflow here. */\n+ int a4 = SHR (year1, 2) + SHR (TM_YEAR_BASE, 2) - ! (year1 & 3);\n+ int b4 = SHR (year0, 2) + SHR (TM_YEAR_BASE, 2) - ! (year0 & 3);\n+ int a100 = a4 / 25 - (a4 % 25 < 0);\n+ int b100 = b4 / 25 - (b4 % 25 < 0);\n+ int a400 = SHR (a100, 2);\n+ int b400 = SHR (b100, 2);\n+ int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);\n+\n+ /* Compute the desired time in __time64_t precision. Overflow might\n+ occur here. */\n+ __time64_t tyear1 = year1;\n+ __time64_t years = tyear1 - year0;\n+ __time64_t days = 365 * years + yday1 - yday0 + intervening_leap_days;\n+ __time64_t hours = 24 * days + hour1 - hour0;\n+ __time64_t minutes = 60 * hours + min1 - min0;\n+ __time64_t seconds = 60 * minutes + sec1 - sec0;\n+ return seconds;\n+}\n+\n+/* Return the average of A and B, even if A + B would overflow. */\n+static __time64_t\n+time64_t_avg (__time64_t a, __time64_t b)\n+{\n+ return SHR (a, 1) + SHR (b, 1) + (a & b & 1);\n+}\n+\n+/* Return 1 if A + B does not overflow. If __time64_t is unsigned and if\n+ B's top bit is set, assume that the sum represents A - -B, and\n+ return 1 if the subtraction does not wrap around. */\n+static int\n+time64_t_add_ok (__time64_t a, __time64_t b)\n+{\n+ if (! TYPE_SIGNED (__time64_t))\n+ {\n+ __time64_t sum = a + b;\n+ return (sum < a) == (TIME_T_MIDPOINT <= b);\n+ }\n+ else if (WRAPV)\n+ {\n+ __time64_t sum = a + b;\n+ return (sum < a) == (b < 0);\n+ }\n+ else\n+ {\n+ __time64_t avg = time64_t_avg (a, b);\n+ return TIME_T_MIN / 2 <= avg && avg <= TIME_T_MAX / 2;\n+ }\n+}\n+\n+/* Return 1 if A + B does not overflow. */\n+static int\n+time64_t_int_add_ok (__time64_t a, int b)\n+{\n+ verify (int_no_wider_than_time64_t, INT_MAX <= TIME_T_MAX);\n+ if (WRAPV)\n+ {\n+ __time64_t sum = a + b;\n+ return (sum < a) == (b < 0);\n+ }\n+ else\n+ {\n+ int a_odd = a & 1;\n+ __time64_t avg = SHR (a, 1) + (SHR (b, 1) + (a_odd & b));\n+ return TIME_T_MIN / 2 <= avg && avg <= TIME_T_MAX / 2;\n+ }\n+}\n+\n+/* Return a __time64_t value corresponding to (YEAR-YDAY HOUR:MIN:SEC),\n+ assuming that *T corresponds to *TP and that no clock adjustments\n+ occurred between *TP and the desired time.\n+ If TP is null, return a value not equal to *T; this avoids false matches.\n+ If overflow occurs, yield the minimal or maximal value, except do not\n+ yield a value equal to *T. */\n+static __time64_t\n+guess_time64_tm (long_int year, long_int yday, int hour, int min, int sec,\n+\t const __time64_t *t, const struct tm *tp)\n+{\n+ if (tp)\n+ {\n+ __time64_t d = ydhms64_diff (year, yday, hour, min, sec,\n+\t\t\t tp->tm_year, tp->tm_yday,\n+\t\t\t tp->tm_hour, tp->tm_min, tp->tm_sec);\n+ if (time64_t_add_ok (*t, d))\n+\treturn *t + d;\n+ }\n+\n+ /* Overflow occurred one way or another. Return the nearest result\n+ that is actually in range, except don't report a zero difference\n+ if the actual difference is nonzero, as that would cause a false\n+ match; and don't oscillate between two values, as that would\n+ confuse the spring-forward gap detector. */\n+ return (*t < TIME_T_MIDPOINT\n+\t ? (*t <= TIME_T_MIN + 1 ? *t + 1 : TIME_T_MIN)\n+\t : (TIME_T_MAX - 1 <= *t ? *t - 1 : TIME_T_MAX));\n+}\n+\n+/* Use CONVERT to convert *T to a broken down time in *TP.\n+ If *T is out of range for conversion, adjust it so that\n+ it is the nearest in-range value and then convert that. */\n+static struct tm *\n+ranged64_convert (struct tm *(*convert) (const __time64_t *, struct tm *),\n+\t\t__time64_t *t, struct tm *tp)\n+{\n+ struct tm *r = convert (t, tp);\n+\n+ if (!r && *t)\n+ {\n+ __time64_t bad = *t;\n+ __time64_t ok = 0;\n+\n+ /* BAD is a known unconvertible __time64_t, and OK is a known good one.\n+\t Use binary search to narrow the range between BAD and OK until\n+\t they differ by 1. */\n+ while (bad != ok + (bad < 0 ? -1 : 1))\n+\t{\n+\t __time64_t mid = *t = time64_t_avg (ok, bad);\n+\t r = convert (t, tp);\n+\t if (r)\n+\t ok = mid;\n+\t else\n+\t bad = mid;\n+\t}\n+\n+ if (!r && ok)\n+\t{\n+\t /* The last conversion attempt failed;\n+\t revert to the most recent successful attempt. */\n+\t *t = ok;\n+\t r = convert (t, tp);\n+\t}\n+ }\n+\n+ return r;\n+}\n+\n+\n+/* Convert *TP to a __time64_t value, inverting\n+ the monotonic and mostly-unit-linear conversion function CONVERT.\n+ Use *OFFSET to keep track of a guess at the offset of the result,\n+ compared to what the result would be for UTC without leap seconds.\n+ If *OFFSET's guess is correct, only one CONVERT call is needed.\n+ This function is external because it is used also by timegm.c. */\n+__time64_t\n+__mktime64_internal (struct tm *tp,\n+\t\t struct tm *(*convert) (const __time64_t *, struct tm *),\n+\t\t __time64_t *offset)\n+{\n+ __time64_t t, gt, t0, t1, t2;\n+ struct tm tm;\n+\n+ /* The maximum number of probes (calls to CONVERT) should be enough\n+ to handle any combinations of time zone rule changes, solar time,\n+ leap seconds, and oscillations around a spring-forward gap.\n+ POSIX.1 prohibits leap seconds, but some hosts have them anyway. */\n+ int remaining_probes = 6;\n+\n+ /* Time requested. Copy it in case CONVERT modifies *TP; this can\n+ occur if TP is localtime's returned value and CONVERT is localtime. */\n+ int sec = tp->tm_sec;\n+ int min = tp->tm_min;\n+ int hour = tp->tm_hour;\n+ int mday = tp->tm_mday;\n+ int mon = tp->tm_mon;\n+ int year_requested = tp->tm_year;\n+ int isdst = tp->tm_isdst;\n+\n+ /* 1 if the previous probe was DST. */\n+ int dst2;\n+\n+ /* Ensure that mon is in range, and set year accordingly. */\n+ int mon_remainder = mon % 12;\n+ int negative_mon_remainder = mon_remainder < 0;\n+ int mon_years = mon / 12 - negative_mon_remainder;\n+ long_int lyear_requested = year_requested;\n+ long_int year = lyear_requested + mon_years;\n+\n+ /* The other values need not be in range:\n+ the remaining code handles minor overflows correctly,\n+ assuming int and __time64_t arithmetic wraps around.\n+ Major overflows are caught at the end. */\n+\n+ /* Calculate day of year from year, month, and day of month.\n+ The result need not be in range. */\n+ int mon_yday = ((__mon_yday[leapyear (year)]\n+\t\t [mon_remainder + 12 * negative_mon_remainder])\n+\t\t - 1);\n+ long_int lmday = mday;\n+ long_int yday = mon_yday + lmday;\n+\n+ __time64_t guessed_offset = *offset;\n+\n+ int sec_requested = sec;\n+\n+ if (LEAP_SECONDS_POSSIBLE)\n+ {\n+ /* Handle out-of-range seconds specially,\n+\t since ydhms_tm_diff assumes every minute has 60 seconds. */\n+ if (sec < 0)\n+\tsec = 0;\n+ if (59 < sec)\n+\tsec = 59;\n+ }\n+\n+ /* Invert CONVERT by probing. First assume the same offset as last\n+ time. */\n+\n+ t0 = ydhms64_diff (year, yday, hour, min, sec,\n+\t\t EPOCH_YEAR - TM_YEAR_BASE, 0, 0, 0, - guessed_offset);\n+\n+ if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)\n+ {\n+ /* __time64_t isn't large enough to rule out overflows, so check\n+\t for major overflows. A gross check suffices, since if t0\n+\t has overflowed, it is off by a multiple of TIME_T_MAX -\n+\t TIME_T_MIN + 1. So ignore any component of the difference\n+\t that is bounded by a small value. */\n+\n+ /* Approximate log base 2 of the number of time units per\n+\t biennium. A biennium is 2 years; use this unit instead of\n+\t years to avoid integer overflow. For example, 2 average\n+\t Gregorian years are 2 * 365.2425 * 24 * 60 * 60 seconds,\n+\t which is 63113904 seconds, and rint (log2 (63113904)) is\n+\t 26. */\n+ int ALOG2_SECONDS_PER_BIENNIUM = 26;\n+ int ALOG2_MINUTES_PER_BIENNIUM = 20;\n+ int ALOG2_HOURS_PER_BIENNIUM = 14;\n+ int ALOG2_DAYS_PER_BIENNIUM = 10;\n+ int LOG2_YEARS_PER_BIENNIUM = 1;\n+\n+ int approx_requested_biennia =\n+\t(SHR (year_requested, LOG2_YEARS_PER_BIENNIUM)\n+\t - SHR (EPOCH_YEAR - TM_YEAR_BASE, LOG2_YEARS_PER_BIENNIUM)\n+\t + SHR (mday, ALOG2_DAYS_PER_BIENNIUM)\n+\t + SHR (hour, ALOG2_HOURS_PER_BIENNIUM)\n+\t + SHR (min, ALOG2_MINUTES_PER_BIENNIUM)\n+\t + (LEAP_SECONDS_POSSIBLE\n+\t ? 0\n+\t : SHR (sec, ALOG2_SECONDS_PER_BIENNIUM)));\n+\n+ int approx_biennia = SHR (t0, ALOG2_SECONDS_PER_BIENNIUM);\n+ int diff = approx_biennia - approx_requested_biennia;\n+ int approx_abs_diff = diff < 0 ? -1 - diff : diff;\n+\n+ /* IRIX 4.0.5 cc miscalculates TIME_T_MIN / 3: it erroneously\n+\t gives a positive value of 715827882. Setting a variable\n+\t first then doing math on it seems to work.\n+\t (ghazi@caip.rutgers.edu) */\n+ __time64_t time64_t_max = TIME_T_MAX;\n+ __time64_t time64_t_min = TIME_T_MIN;\n+ __time64_t overflow_threshold =\n+\t(time64_t_max / 3 - time64_t_min / 3) >> ALOG2_SECONDS_PER_BIENNIUM;\n+\n+ if (overflow_threshold < approx_abs_diff)\n+\t{\n+\t /* Overflow occurred. Try repairing it; this might work if\n+\t the time zone offset is enough to undo the overflow. */\n+\t __time64_t repaired_t0 = -1 - t0;\n+\t approx_biennia = SHR (repaired_t0, ALOG2_SECONDS_PER_BIENNIUM);\n+\t diff = approx_biennia - approx_requested_biennia;\n+\t approx_abs_diff = diff < 0 ? -1 - diff : diff;\n+\t if (overflow_threshold < approx_abs_diff)\n+\t return -1;\n+\t guessed_offset += repaired_t0 - t0;\n+\t t0 = repaired_t0;\n+\t}\n+ }\n+\n+ /* Repeatedly use the error to improve the guess. */\n+\n+ for (t = t1 = t2 = t0, dst2 = 0;\n+ (gt = guess_time64_tm (year, yday, hour, min, sec, &t,\n+\t\t\t ranged64_convert (convert, &t, &tm)),\n+\tt != gt);\n+ t1 = t2, t2 = t, t = gt, dst2 = tm.tm_isdst != 0)\n+ if (t == t1 && t != t2\n+\t&& (tm.tm_isdst < 0\n+\t || (isdst < 0\n+\t\t? dst2 <= (tm.tm_isdst != 0)\n+\t\t: (isdst != 0) != (tm.tm_isdst != 0))))\n+ /* We can't possibly find a match, as we are oscillating\n+\t between two values. The requested time probably falls\n+\t within a spring-forward gap of size GT - T. Follow the common\n+\t practice in this case, which is to return a time that is GT - T\n+\t away from the requested time, preferring a time whose\n+\t tm_isdst differs from the requested value. (If no tm_isdst\n+\t was requested and only one of the two values has a nonzero\n+\t tm_isdst, prefer that value.) In practice, this is more\n+\t useful than returning -1. */\n+ goto offset_found;\n+ else if (--remaining_probes == 0)\n+ return -1;\n+\n+ /* We have a match. Check whether tm.tm_isdst has the requested\n+ value, if any. */\n+ if (isdst_differ (isdst, tm.tm_isdst))\n+ {\n+ /* tm.tm_isdst has the wrong value. Look for a neighboring\n+\t time with the right value, and use its UTC offset.\n+\n+\t Heuristic: probe the adjacent timestamps in both directions,\n+\t looking for the desired isdst. This should work for all real\n+\t time zone histories in the tz database. */\n+\n+ /* Distance between probes when looking for a DST boundary. In\n+\t tzdata2003a, the shortest period of DST is 601200 seconds\n+\t (e.g., America/Recife starting 2000-10-08 01:00), and the\n+\t shortest period of non-DST surrounded by DST is 694800\n+\t seconds (Africa/Tunis starting 1943-04-17 01:00). Use the\n+\t minimum of these two values, so we don't miss these short\n+\t periods when probing. */\n+ int stride = 601200;\n+\n+ /* The longest period of DST in tzdata2003a is 536454000 seconds\n+\t (e.g., America/Jujuy starting 1946-10-01 01:00). The longest\n+\t period of non-DST is much longer, but it makes no real sense\n+\t to search for more than a year of non-DST, so use the DST\n+\t max. */\n+ int duration_max = 536454000;\n+\n+ /* Search in both directions, so the maximum distance is half\n+\t the duration; add the stride to avoid off-by-1 problems. */\n+ int delta_bound = duration_max / 2 + stride;\n+\n+ int delta, direction;\n+\n+ for (delta = stride; delta < delta_bound; delta += stride)\n+\tfor (direction = -1; direction <= 1; direction += 2)\n+\t if (time64_t_int_add_ok (t, delta * direction))\n+\t {\n+\t __time64_t ot = t + delta * direction;\n+\t struct tm otm;\n+\t ranged64_convert (convert, &ot, &otm);\n+\t if (! isdst_differ (isdst, otm.tm_isdst))\n+\t\t{\n+\t\t /* We found the desired tm_isdst.\n+\t\t Extrapolate back to the desired time. */\n+\t\t t = guess_time64_tm (year, yday, hour, min, sec, &ot, &otm);\n+\t\t ranged64_convert (convert, &t, &tm);\n+\t\t goto offset_found;\n+\t\t}\n+\t }\n+ }\n+\n+ offset_found:\n+ *offset = guessed_offset + t - t0;\n+\n+ if (LEAP_SECONDS_POSSIBLE && sec_requested != tm.tm_sec)\n+ {\n+ /* Adjust time to reflect the tm_sec requested, not the normalized value.\n+\t Also, repair any damage from a false match due to a leap second. */\n+ int sec_adjustment = (sec == 0 && tm.tm_sec == 60) - sec;\n+ if (! time64_t_int_add_ok (t, sec_requested))\n+\treturn -1;\n+ t1 = t + sec_requested;\n+ if (! time64_t_int_add_ok (t1, sec_adjustment))\n+\treturn -1;\n+ t2 = t1 + sec_adjustment;\n+ if (! convert (&t2, &tm))\n+\treturn -1;\n+ t = t2;\n+ }\n+\n+ *tp = tm;\n+ return t;\n+}\n+\n+\n+/* This uses a signed type wide enough to hold any UTC offset in seconds. */\n+static __time64_t localtime64_offset;\n+\n+/* Convert *TP to a __time64_t value. */\n+__time64_t\n+__mktime64 (struct tm *tp)\n+{\n+#ifdef _LIBC\n+ /* POSIX.1 8.1.1 requires that whenever mktime() is called, the\n+ time zone names contained in the external variable 'tzname' shall\n+ be set as if the tzset() function had been called. */\n+ __tzset ();\n+#endif\n+\n+ return __mktime64_internal (tp, __localtime64_r, &localtime64_offset);\n+}\n \f\n #if defined DEBUG_MKTIME && DEBUG_MKTIME\n \n", "prefixes": [ "RFC", "04/52" ] }