<!DOCTYPE html>
<title>document.lastModified should return current local time</title>
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
  var last_modified = document.lastModified;

  var pattern = /^([0-9]{2})\/([0-9]{2})\/([0-9]{4}) ([0-9]{2}):([0-9]{2}):([0-9]{2})$/;

  test(function() {
     assert_regexp_match(last_modified, pattern,
                         "Format should match the pattern \"NN/NN/NNNN NN:NN:NN\".");
  }, "Date returned by lastModified is in the form \"MM/DD/YYYY hh:mm:ss\".");

  function assert_date_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 = pattern.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)");
    }
  }

  test(function() {
    assert_date_string_approximately_now(last_modified);
  }, "Date returned by lastModified is current at page load");

  var t = async_test("Date returned by lastModified is current after timeout.");
  t.step_timeout(function() {
    assert_date_string_approximately_now(document.lastModified);
    t.done();
  }, 4000);
</script>
