+ /* Invert CONVERT by probing. First assume the same offset as last time.
+ Then repeatedly use the error to improve the guess. */
+
+ tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
+ tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+ t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
+
+ for (t = t1 = t2 = t0 + *offset;
+ (dt = ydhms_tm_diff (year, yday, hour, min, sec,
+ ranged_convert (convert, &t, &tm)));
+ t1 = t2, t2 = t, t += dt)
+ if (t == t1 && t != t2
+ && (isdst < 0 || 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 DT. Follow the common
+ practice in this case, which is to return a time that is DT
+ away from the requested time, preferring a time whose
+ tm_isdst differs from the requested value. In practice,
+ this is more useful than returning -1. */
+ break;
+ else if (--remaining_probes == 0)
+ return -1;
+
+ /* If we have a match, check whether tm.tm_isdst has the requested
+ value, if any. */
+ if (dt == 0 && 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 previous three calendar quarters (approximately),
+ looking for the desired isdst. This isn't perfect,
+ but it's good enough in practice. */
+ int quarter = 7889238; /* seconds per average 1/4 Gregorian year */
+ int i;
+
+ /* If we're too close to the time_t limit, look in future quarters. */
+ if (t < TIME_T_MIN + 3 * quarter)
+ quarter = -quarter;
+
+ for (i = 1; i <= 3; i++)
+ {
+ time_t ot = t - i * quarter;
+ 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 = ot + ydhms_tm_diff (year, yday, hour, min, sec, &otm);
+ ranged_convert (convert, &t, &tm);
+ break;
+ }
+ }
+ }