如何将日期输入和时间输入视为本地时间,而不是通用时间?

时间:2019-12-22 08:09:03

标签: javascript date time timezone

用户输入2019-12-22的日期输入将给出以下值:

  • input.value"2019-12-22"
  • input.valueAsNumber1576972800000
  • input.valueAsDate"Sat Dec 21 2019 16:00:00 GMT-0800 (Pacific Standard Time)"
    • 此结果日期对象似乎是错误的
    • 浏览器返回值时,会将用户输入视为通用时间
    • 因此日期对象的utc表示形式与输入向用户显示的内容相同
    • input.valueAsDate.getUTCDate()返回22,这是用户输入的内容
    • input.valueAsDate.getDate()返回21,而不是用户输入的内容
    • 因此我们得出结论,显示日期输入并接受utc时间,而不是本地时间

我们希望结果date.toString()显示与日期输入中原始用户输入相同的结果

我们如何允许用户与当地时间互动,然后在脚本中获取正确的日期对象?

2 个答案:

答案 0 :(得分:2)

此问题是由TC-39决定将日期(仅ISO 8601格式)时间戳记为UTC来决定的,这在逻辑上与ISO 8601保持一致并将它们视为本地是更合理的。参见Why does Date.parse give incorrect results?

简单的解决方案是手动解析字符串,不要使用内置的解析器,作为至少一种当前实现,直到最近将YYYY-MM-DD解析为本地。另外,请勿使用当前时区偏移量来调整时间值,因为这不允许偏移量的历史性更改或可能的夏时制更改。

// 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));

编辑

在支持输入类型日期并且按ECMA-262将YYYY-MM-DD解析为UTC的情况下,可以使用 valueAsDate 和UTC方法。但是,并非所有浏览器都支持输入类型日期,也不是所有解析器都会将该格式解析为UTC。

不依赖输入类型日期并手动解析值,检查格式和有效性更为可靠。这就是为什么通常使用日期小部件和库而不是内置日期功能的原因之一。

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">

答案 1 :(得分:-2)

由于日期/时间输入元素正在接受用户输入作为UTC时间,但是我们要接受本地时间,因此必须手动补偿用户计算机上配置的本地时区偏移量

因此,我们接受输入值作为数字,但是在使用它创建Date对象之前,先将其偏移时区偏移量

// 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)

当通过toString()toLocaleDateString()向用户显示时,结果日期对象将与用户最初输入的时间相同。