Source code

Revision control

Copy as Markdown

Other Tools

const DOCUMENT_LASTMODIFIED_REGEX = /^([0-9]{2})\/([0-9]{2})\/([0-9]{4}) ([0-9]{2}):([0-9]{2}):([0-9]{2})$/;
function assert_document_lastmodified_string_approximately_now(str) {
// We want to test that |str| was a time in the user's local
// timezone generated within a few seconds prior to the present.
// This requires some care, since it is possible that:
// - the few second difference may have crossed a
// year/month/day/hour/minute boundary
// - the few second difference may have crossed a change in the
// local timezone's UTC offset
// - the local time might be one that has multiple valid UTC
// representations (for example, because it's in the hour
// following a shift from summer time to winter time)
// We will make some assumptions to do this:
// - local time's UTC offset doesn't change more than once per
// minute
// - local time's UTC offset only changes by integral numbers of
// minutes
// The date must be equal to or earlier than the present time.
var dmax = new Date();
// The date must be equal to or later than 2.5 seconds ago.
var TOLERANCE_MILLISECONDS = 2500;
var dmin = new Date();
dmin.setTime(dmax.getTime() - TOLERANCE_MILLISECONDS);
// Extract the year/month/date/hours/minutes/seconds from str. It
// is important that we do *not* try to construct a Date object from
// these, since the core of the date object is a timestamp in UTC,
// and there are cases (such as the hour on each side of a change
// from summer time to winter time) where there are multiple
// possible UTC timestamps for a given YYYY-MM-DD HH:MM:SS, and
// constructing a Date object would pick one of them, which might be
// the wrong one. However, we already have the right one in dmin
// and dmax, so we should instead extract local time from those
// rather than converting these values to UTC.
var m = DOCUMENT_LASTMODIFIED_REGEX.exec(str);
var syear = Number(m[3]);
var smonth = Number(m[1]) - 1; // match Javascript 0-based months
var sdate = Number(m[2]);
var shours = Number(m[4]);
var sminutes = Number(m[5]);
var sseconds = Number(m[6]);
if (dmin.getFullYear() == dmax.getFullYear() &&
dmin.getMonth() == dmax.getMonth() &&
dmin.getDate() == dmax.getDate() &&
dmin.getHours() == dmax.getHours() &&
dmin.getMinutes() == dmax.getMinutes()) {
// min and max have the same minute
assert_equals(smonth, dmin.getMonth(), "month");
assert_equals(sdate, dmin.getDate(), "date");
assert_equals(syear, dmin.getFullYear(), "year");
assert_equals(shours, dmin.getHours(), "hours");
assert_equals(sminutes, dmin.getMinutes(), "minutes");
assert_true(dmin.getSeconds() <= sseconds &&
sseconds <= dmax.getSeconds(), "seconds");
} else if (dmin.getFullYear() == syear &&
dmin.getMonth() == smonth &&
dmin.getDate() == sdate &&
dmin.getHours() == shours &&
dmin.getMinutes() == sminutes) {
// actual value has the same minute as min
assert_true(dmin.getSeconds() <= sseconds, "dmin.getSeconds() <= sseconds");
assert_true(57 <= dmin.getSeconds(), "unexpected local time rules (dmin match)");
} else if (dmax.getFullYear() == syear &&
dmax.getMonth() == smonth &&
dmax.getDate() == sdate &&
dmax.getHours() == shours &&
dmax.getMinutes() == sminutes) {
// actual value has the same minute as max
assert_true(sseconds <= dmax.getSeconds(), "sseconds <= dmax.getSeconds()");
assert_true(dmax.getSeconds() <= 2, "unexpected local time rules (dmax match)");
} else {
assert_unreached("unexpected local time rules (no match)");
}
}