How to treat date-input and time-input as local time, rather than universal time?

左心房为你撑大大i 提交于 2020-01-06 05:24:31

问题


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() returns 22, which is what the user entered
    • input.valueAsDate.getDate() returns 21, 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!