Skip to content

Commit 4bd41bb

Browse files
dbaronchromium-wpt-export-bot
authored andcommitted
Make XHR document.lastModified test handle summer to winter time change.
document.lastModified is a legacy API which is tricky to test because it reports times in the local timezone, but without any timezone indicator. Such times cannot be reliably converted to UTC, because times during the hour on either side of the change from summer to winter time produce the same local time string as times on the other side of the change. This change moves the code in document-lastModified-01.html that already deals with this complexity into a shared support script and then uses it to fix the equivalent test in responsexml-document-properties.htm, which still has failures around the change from summer time to winter time, as document-lastModified-01.html used to have. This also renames the moved function and constant to fit better in a separate support script. Bug: 1382239 Change-Id: I3f45cdaae3908016235c715f8e7400b6eaf6492b Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5006704 Reviewed-by: Mason Freed <[email protected]> Commit-Queue: David Baron <[email protected]> Cr-Commit-Position: refs/heads/main@{#1220700}
1 parent f30784e commit 4bd41bb

File tree

3 files changed

+84
-87
lines changed

3 files changed

+84
-87
lines changed

html/dom/documents/resource-metadata-management/document-lastModified-01.html

Lines changed: 4 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -3,101 +3,23 @@
33
<meta name="timeout" content="long">
44
<script src="/resources/testharness.js"></script>
55
<script src="/resources/testharnessreport.js"></script>
6+
<script src="support/document-lastModified-utils.js"></script>
67
<div id="log"></div>
78
<script>
89
var last_modified = document.lastModified;
910

10-
var pattern = /^([0-9]{2})\/([0-9]{2})\/([0-9]{4}) ([0-9]{2}):([0-9]{2}):([0-9]{2})$/;
11-
1211
test(function() {
13-
assert_regexp_match(last_modified, pattern,
12+
assert_regexp_match(last_modified, DOCUMENT_LASTMODIFIED_REGEX,
1413
"Format should match the pattern \"NN/NN/NNNN NN:NN:NN\".");
1514
}, "Date returned by lastModified is in the form \"MM/DD/YYYY hh:mm:ss\".");
1615

17-
function assert_date_string_approximately_now(str) {
18-
// We want to test that |str| was a time in the user's local
19-
// timezone generated within a few seconds prior to the present.
20-
// This requires some care, since it is possible that:
21-
// - the few second difference may have crossed a
22-
// year/month/day/hour/minute boundary
23-
// - the few second difference may have crossed a change in the
24-
// local timezone's UTC offset
25-
// - the local time might be one that has multiple valid UTC
26-
// representations (for example, because it's in the hour
27-
// following a shift from summer time to winter time)
28-
// We will make some assumptions to do this:
29-
// - local time's UTC offset doesn't change more than once per
30-
// minute
31-
// - local time's UTC offset only changes by integral numbers of
32-
// minutes
33-
34-
// The date must be equal to or earlier than the present time.
35-
var dmax = new Date();
36-
37-
// The date must be equal to or later than 2.5 seconds ago.
38-
var TOLERANCE_MILLISECONDS = 2500;
39-
var dmin = new Date();
40-
dmin.setTime(dmax.getTime() - TOLERANCE_MILLISECONDS);
41-
42-
// Extract the year/month/date/hours/minutes/seconds from str. It
43-
// is important that we do *not* try to construct a Date object from
44-
// these, since the core of the date object is a timestamp in UTC,
45-
// and there are cases (such as the hour on each side of a change
46-
// from summer time to winter time) where there are multiple
47-
// possible UTC timestamps for a given YYYY-MM-DD HH:MM:SS, and
48-
// constructing a Date object would pick one of them, which might be
49-
// the wrong one. However, we already have the right one in dmin
50-
// and dmax, so we should instead extract local time from those
51-
// rather than converting these values to UTC.
52-
var m = pattern.exec(str);
53-
var syear = Number(m[3]);
54-
var smonth = Number(m[1]) - 1; // match Javascript 0-based months
55-
var sdate = Number(m[2]);
56-
var shours = Number(m[4]);
57-
var sminutes = Number(m[5]);
58-
var sseconds = Number(m[6]);
59-
60-
if (dmin.getFullYear() == dmax.getFullYear() &&
61-
dmin.getMonth() == dmax.getMonth() &&
62-
dmin.getDate() == dmax.getDate() &&
63-
dmin.getHours() == dmax.getHours() &&
64-
dmin.getMinutes() == dmax.getMinutes()) {
65-
// min and max have the same minute
66-
assert_equals(smonth, dmin.getMonth(), "month");
67-
assert_equals(sdate, dmin.getDate(), "date");
68-
assert_equals(syear, dmin.getFullYear(), "year");
69-
assert_equals(shours, dmin.getHours(), "hours");
70-
assert_equals(sminutes, dmin.getMinutes(), "minutes");
71-
assert_true(dmin.getSeconds() <= sseconds &&
72-
sseconds <= dmax.getSeconds(), "seconds");
73-
} else if (dmin.getFullYear() == syear &&
74-
dmin.getMonth() == smonth &&
75-
dmin.getDate() == sdate &&
76-
dmin.getHours() == shours &&
77-
dmin.getMinutes() == sminutes) {
78-
// actual value has the same minute as min
79-
assert_true(dmin.getSeconds() <= sseconds, "dmin.getSeconds() <= sseconds");
80-
assert_true(57 <= dmin.getSeconds(), "unexpected local time rules (dmin match)");
81-
} else if (dmax.getFullYear() == syear &&
82-
dmax.getMonth() == smonth &&
83-
dmax.getDate() == sdate &&
84-
dmax.getHours() == shours &&
85-
dmax.getMinutes() == sminutes) {
86-
// actual value has the same minute as max
87-
assert_true(sseconds <= dmax.getSeconds(), "sseconds <= dmax.getSeconds()");
88-
assert_true(dmax.getSeconds() <= 2, "unexpected local time rules (dmax match)");
89-
} else {
90-
assert_unreached("unexpected local time rules (no match)");
91-
}
92-
}
93-
9416
test(function() {
95-
assert_date_string_approximately_now(last_modified);
17+
assert_document_lastmodified_string_approximately_now(last_modified);
9618
}, "Date returned by lastModified is current at page load");
9719

9820
var t = async_test("Date returned by lastModified is current after timeout.");
9921
t.step_timeout(function() {
100-
assert_date_string_approximately_now(document.lastModified);
22+
assert_document_lastmodified_string_approximately_now(document.lastModified);
10123
t.done();
10224
}, 4000);
10325
</script>
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
const DOCUMENT_LASTMODIFIED_REGEX = /^([0-9]{2})\/([0-9]{2})\/([0-9]{4}) ([0-9]{2}):([0-9]{2}):([0-9]{2})$/;
2+
3+
function assert_document_lastmodified_string_approximately_now(str) {
4+
// We want to test that |str| was a time in the user's local
5+
// timezone generated within a few seconds prior to the present.
6+
// This requires some care, since it is possible that:
7+
// - the few second difference may have crossed a
8+
// year/month/day/hour/minute boundary
9+
// - the few second difference may have crossed a change in the
10+
// local timezone's UTC offset
11+
// - the local time might be one that has multiple valid UTC
12+
// representations (for example, because it's in the hour
13+
// following a shift from summer time to winter time)
14+
// We will make some assumptions to do this:
15+
// - local time's UTC offset doesn't change more than once per
16+
// minute
17+
// - local time's UTC offset only changes by integral numbers of
18+
// minutes
19+
20+
// The date must be equal to or earlier than the present time.
21+
var dmax = new Date();
22+
23+
// The date must be equal to or later than 2.5 seconds ago.
24+
var TOLERANCE_MILLISECONDS = 2500;
25+
var dmin = new Date();
26+
dmin.setTime(dmax.getTime() - TOLERANCE_MILLISECONDS);
27+
28+
// Extract the year/month/date/hours/minutes/seconds from str. It
29+
// is important that we do *not* try to construct a Date object from
30+
// these, since the core of the date object is a timestamp in UTC,
31+
// and there are cases (such as the hour on each side of a change
32+
// from summer time to winter time) where there are multiple
33+
// possible UTC timestamps for a given YYYY-MM-DD HH:MM:SS, and
34+
// constructing a Date object would pick one of them, which might be
35+
// the wrong one. However, we already have the right one in dmin
36+
// and dmax, so we should instead extract local time from those
37+
// rather than converting these values to UTC.
38+
var m = DOCUMENT_LASTMODIFIED_REGEX.exec(str);
39+
var syear = Number(m[3]);
40+
var smonth = Number(m[1]) - 1; // match Javascript 0-based months
41+
var sdate = Number(m[2]);
42+
var shours = Number(m[4]);
43+
var sminutes = Number(m[5]);
44+
var sseconds = Number(m[6]);
45+
46+
if (dmin.getFullYear() == dmax.getFullYear() &&
47+
dmin.getMonth() == dmax.getMonth() &&
48+
dmin.getDate() == dmax.getDate() &&
49+
dmin.getHours() == dmax.getHours() &&
50+
dmin.getMinutes() == dmax.getMinutes()) {
51+
// min and max have the same minute
52+
assert_equals(smonth, dmin.getMonth(), "month");
53+
assert_equals(sdate, dmin.getDate(), "date");
54+
assert_equals(syear, dmin.getFullYear(), "year");
55+
assert_equals(shours, dmin.getHours(), "hours");
56+
assert_equals(sminutes, dmin.getMinutes(), "minutes");
57+
assert_true(dmin.getSeconds() <= sseconds &&
58+
sseconds <= dmax.getSeconds(), "seconds");
59+
} else if (dmin.getFullYear() == syear &&
60+
dmin.getMonth() == smonth &&
61+
dmin.getDate() == sdate &&
62+
dmin.getHours() == shours &&
63+
dmin.getMinutes() == sminutes) {
64+
// actual value has the same minute as min
65+
assert_true(dmin.getSeconds() <= sseconds, "dmin.getSeconds() <= sseconds");
66+
assert_true(57 <= dmin.getSeconds(), "unexpected local time rules (dmin match)");
67+
} else if (dmax.getFullYear() == syear &&
68+
dmax.getMonth() == smonth &&
69+
dmax.getDate() == sdate &&
70+
dmax.getHours() == shours &&
71+
dmax.getMinutes() == sminutes) {
72+
// actual value has the same minute as max
73+
assert_true(sseconds <= dmax.getSeconds(), "sseconds <= dmax.getSeconds()");
74+
assert_true(dmax.getSeconds() <= 2, "unexpected local time rules (dmax match)");
75+
} else {
76+
assert_unreached("unexpected local time rules (no match)");
77+
}
78+
}

xhr/responsexml-document-properties.htm

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
<title>XMLHttpRequest: responseXML document properties</title>
55
<script src="/resources/testharness.js"></script>
66
<script src="/resources/testharnessreport.js"></script>
7+
<script src="../html/dom/documents/resource-metadata-management/support/document-lastModified-utils.js"></script>
78
</head>
89
<body>
910
<div id="log"></div>
1011
<script>
11-
var timePreXHR = Math.floor(new Date().getTime(new Date().getTime() - 3000) / 1000); // three seconds ago, in case there's clock drift
1212
var client = new XMLHttpRequest()
1313
client.open("GET", "resources/well-formed.xml", false)
1414
client.send(null)
@@ -87,10 +87,7 @@
8787
}, "Test document URL properties of document with <base> after redirect");
8888

8989
test(function() {
90-
var lastModified = Math.floor(parseLastModified(client.responseXML.lastModified).getTime() / 1000);
91-
var now = Math.floor(new Date().getTime(new Date().getTime() + 3000) / 1000); // three seconds from now, in case there's clock drift
92-
assert_greater_than_equal(lastModified, timePreXHR);
93-
assert_less_than_equal(lastModified, now);
90+
assert_document_lastmodified_string_approximately_now(client.responseXML.lastModified);
9491
}, 'lastModified set to time of response if no HTTP header provided')
9592

9693
test(function() {

0 commit comments

Comments
 (0)