问题
a date input where the user enters 2019-12-22
gives these values:
input.value
:"2019-12-22"
input.valueAsNumber
:1576972800000
input.valueAsDate
:"Sat Dec 21 2019 16:00:00 GMT-0800 (Pacific Standard Time)"
- this resulting date object just seems wrong
- when the browser returns a value, it treats the user input as universal time
- so the date object's utc representation is the same as what the input displays to the user
input.valueAsDate.getUTCDate()
returns22
, which is what the user enteredinput.valueAsDate.getDate()
returns21
, NOT what the user entered- thus we conclude the date input displays and accepts utc time, not local times
we want the resulting date.toString()
to show the same result as the original user input in the date-input
how can we allow users to interact with local times, but then obtain a correct date object in our scripts?
回答1:
This issue is caused by a decision by the TC-39 to treat date–only ISO 8601 format timestamps as UTC, when it would have been more logical to be consistent with ISO 8601 and treated them as local. See Why does Date.parse give incorrect results?
The simple solution is to manually parse the string, do not use the built–in parser, as at least one current implementation until recently parsed YYYY-MM-DD as local. Also, do not use the current timezone offset to adjust the time value as that doesn't allow for historic changes in offsets or possible daylight saving changes.
// Parse timestamp in YYYY-MM-DD format as local
function parseISOLocal(s) {
let [y, m, d] = s.split(/\D/);
return new Date(y, --m, d);
}
// Format date as YYYY-MM-DD local
function formatISOLocal(d) {
let z = n => (n<10?'0':'') + n;
return d.getFullYear() + '-' + z(d.getMonth()+1) + '-' + z(d.getDate());
}
let s = '2019-12-22';
let d = parseISOLocal(s);
console.log( d.toString());
console.log( formatISOLocal(d));
Edit
Where input type date is supported and YYYY-MM-DD is parsed per ECMA-262 as UTC, you can use valueAsDate and UTC methods. However, not all browsers support input type date and not all parsers will parse that format as UTC.
It's much more reliable to not rely on input type date and to manually parse the value, checking format and validity. This is one reason why date widgets and libraries are commonly used instead of built–in Date functionality.
let inp = document.getElementById('dob');
let dobObj = inp.valueAsDate;
let dobStr = inp.value;
console.log('Value as date: ' + dobObj); // Safari: null
console.log('Value as string: ' + dobStr); // 2018-06-15
<input id="dob" type="date" value="2018-06-15">
回答2:
Since the date/time input elements are accepting user input as UTC time, but we want to accept local time, we must manually compensate by the amount of local timezone offset that is configured on the user's computer
So we accept the input value as a number, but then offset it by the amount of timezone offset before making a Date object with it
// ascertain the timezone offset
const timeOffset = (new Date()).getTimezoneOffset() * 60 * 1000
// compensate for the weirdness
const milliseconds = input.valueAsNumber + timeOffset
// make a real date object
const date = new Date(milliseconds)
the resulting date object, when displayed to the user via toString()
or toLocaleDateString()
, will be the same as the time that the user had originally input.
来源:https://stackoverflow.com/questions/59442593/how-to-treat-date-input-and-time-input-as-local-time-rather-than-universal-time