Correctly implement 'time-of-the-time' daylight savings semantics

(Scott L. Burson)

This change contains Scott's original DST patch reapplied correctly.

Fixes <http://abcl.org/trac/ticket/443>.
parent 7906e481
......@@ -519,7 +519,6 @@ public class Autoload extends Function
autoload(PACKAGE_EXT, "file-directory-p", "probe_file", true);
autoload(PACKAGE_EXT, "gc", "gc", true);
autoload(PACKAGE_EXT, "get-floating-point-modes", "FloatFunctions", true);
autoload(PACKAGE_EXT, "get-time-zone", "Time", true);
autoload(PACKAGE_EXT, "make-slime-input-stream", "SlimeInputStream", true);
autoload(PACKAGE_EXT, "make-slime-output-stream", "SlimeOutputStream", true);
autoload(PACKAGE_EXT, "probe-directory", "probe_file", true);
......@@ -628,6 +627,7 @@ public class Autoload extends Function
autoload(PACKAGE_SYS, "function-info", "function_info");
autoload(PACKAGE_SYS, "get-cached-emf", "EMFCache", true);
autoload(PACKAGE_SYS, "get-function-info-value", "function_info");
autoload(PACKAGE_SYS, "get-time-zone", "Time");
autoload(PACKAGE_SYS, "hash-table-entries", "HashTableFunctions");
autoload(PACKAGE_SYS, "hash-table-entries", "HashTableFunctions");
autoload(PACKAGE_SYS, "layout-class", "Layout", true);
......
......@@ -111,47 +111,40 @@ public final class Time
};
// ### default-time-zone => offset daylight-p
public static final Primitive DEFAULT_TIME_ZONE = new pf_default_time_zone();
@DocString(name="default-time-zone",
args="",
returns="offset daylight-p",
doc="Returns the OFFSET of the default time zone for this instance of the implementation, and as a second value the state of the DAYLIGHT-P predicate.")
public static final class pf_default_time_zone extends Primitive {
pf_default_time_zone() {
super("default-time-zone", PACKAGE_SYS, true);
}
public LispObject execute()
private static final Primitive DEFAULT_TIME_ZONE =
new Primitive("default-time-zone", PACKAGE_SYS, false)
{
return GET_TIME_ZONE.execute(LispInteger.getInstance(System.currentTimeMillis()));
}
};
@Override
public LispObject execute()
{
return getTimeZone(System.currentTimeMillis());
}
};
// ### get-time-zone time-in-millis => time-zone-difference-in-hours
public static final Primitive GET_TIME_ZONE = new pf_get_time_zone();
@DocString(name="get-time-zone",
args="time-in-millis",
returns="timezone",
doc="Return the timezone difference in hours for TIME-IN-MILLIS via the Daylight assumptions that were in place at its occurance. i.e. implement 'time of the time semantics'." )
public static final class pf_get_time_zone extends Primitive {
pf_get_time_zone() {
super("get-time-zone", PACKAGE_EXT, true, "time-in-millis");
}
private static final LispObject getTimeZone(long unixTimeMillis) {
TimeZone tz = TimeZone.getDefault();
//int offset = tz.getOffset(System.currentTimeMillis());
// Classpath hasn't implemented TimeZone.getOffset(long).
int rawOffset = tz.getRawOffset();
final boolean inDaylightTime =
tz.inDaylightTime(new Date(unixTimeMillis));
if (inDaylightTime)
rawOffset += tz.getDSTSavings();
// "Time zone values increase with motion to the west..."
// Convert milliseconds to hours.
return LispThread.currentThread().setValues(
Fixnum.getInstance(- rawOffset).divideBy(Fixnum.getInstance(3600000)),
inDaylightTime ? T : NIL);
}
public LispObject execute(LispObject unixTimeMillis) {
// should be a reference to a singleton for the lifetime of an ABCL process
TimeZone tz = TimeZone.getDefault();
// int offset = tz.getOffset(System.currentTimeMillis());
// Classpath hasn't implemented TimeZone.getOffset(long).
int rawOffset = tz.getRawOffset();
final boolean inDaylightTime = tz.inDaylightTime(new Date(unixTimeMillis.longValue()));
if (inDaylightTime)
rawOffset += tz.getDSTSavings();
// "Time zone values increase with motion to the west..."
// Convert milliseconds to hours.
return LispThread.currentThread()
.setValues(Fixnum
.getInstance(- rawOffset).divideBy(Fixnum.getInstance(3600000)),
inDaylightTime ? T : NIL);
}
};
// ### get-time-zone universal-time => hours-west daylight-p
private static final Primitive GET_TIME_ZONE =
new Primitive("get-time-zone", PACKAGE_SYS, false)
{
@Override
public LispObject execute(LispObject arg)
{
return getTimeZone((arg.longValue() - 2208988800L) * 1000);
}
};
}
......@@ -42,8 +42,6 @@
(defconstant november-17-1858 678882)
(defconstant weekday-november-17-1858 2)
;;; decode-universal-time universal-time &optional time-zone
;;; => second minute hour date month year day daylight-p zone
;;; If time-zone is not supplied, it defaults to the current time zone adjusted
......@@ -55,7 +53,7 @@
(if time-zone
(setf seconds-west (* time-zone 3600)
daylight nil)
(multiple-value-bind (time-zone daylight-p) (ext:get-time-zone (* 1000 universal-time))
(multiple-value-bind (time-zone daylight-p) (get-time-zone universal-time)
(setf seconds-west (* time-zone 3600)
daylight daylight-p)))
(multiple-value-bind (weeks secs)
......@@ -128,7 +126,9 @@
(leap-years-before year))
(* (- year 1900) 365)))
(hours (+ hour (* days 24))))
(cond ((> year 2037)
(cond (time-zone
(+ second (* (+ minute (* (+ hours time-zone) 60)) 60)))
((> year 2037)
(labels ((leap-year-p (year)
(cond ((zerop (mod year 400)) t)
((zerop (mod year 100)) nil)
......@@ -141,17 +141,8 @@
(* 86400 (+ (* 365 (- year fake-year))
(- (leap-years-before year)
(leap-years-before fake-year))))))))
((not time-zone)
(let* ((tz-guess (ext:get-time-zone (* 1000 (* hours 3600))))
(guess (+ second (* 60 (+ minute (* 60 (+ hours tz-guess))))))
(tz (ext:get-time-zone (* 1000 guess))))
(+ guess (* 3600 (- tz tz-guess)))))
(t
(+ second (* (+ minute (* (+ hours time-zone) 60)) 60))))))
#|
(intern "GET-TIME-ZONE" (find-package :ext))
(define-symbol-macro EXT:GET-TIME-ZONE
`(get-time-zone))
(export (intern "GET-TIME-ZONE" (find-package :ext)))
#|
(let* ((tz-guess (get-time-zone (* hours 3600)))
(guess (+ second (* 60 (+ minute (* 60 (+ hours tz-guess))))))
(tz (get-time-zone guess)))
(+ guess (* 3600 (- tz tz-guess))))))))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment