Javascript 日期在 iOS 上无效 [英] Javascript date is invalid on iOS

查看:45
本文介绍了Javascript 日期在 iOS 上无效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发基于 Phonegap 的 iOS 应用,该应用已针对 Android 完成.以下几行适用于 Android,但不适用于 iOS.为什么?

I'm working on a Phonegap-based iOS app, which is already done for Android. The following lines are working fine for Android but not for iOS. Why?

var d = new Date("2015-12-31 00:00:00");
console.log(d.getDate() + '. ' + d.getMonth() + ' ' + d.getFullYear();

Android 结果:

Result for Android:

31.11 2015

iOS 上的结果:

NaN. NaN NaN

差异从何而来?

推荐答案

您的日期字符串不是指定用于 new Date 的格式.规范中唯一的格式是ISO-8601 的简化版本,在 ES5 (2009) 中添加.你的字符串不是那种格式,但它真的很接近.将其更改为规范中未包含但普遍支持的格式也很容易

Your date string is not in a format specified to work with new Date. The only format in the spec is a simplified version of ISO-8601, added in ES5 (2009). Your string isn't in that format, but it's really close. It would also be easy to change it to a format that isn't in the spec, but is universally supported

四种选择:

  • 使用即将推出的 Temporal 功能(现在处于第 3 阶段)
  • 指定格式
  • 一种几乎得到普遍支持的未指定格式
  • 自己解析
  • Use the upcoming Temporal feature (it's now at Stage 3)
  • The specified format
  • An unspecified format that's near-universally supported
  • Parse it yourself

Temporal 提案 目前处于第 3 阶段2021 年 8 月更新.您可以使用它来解析您的字符串,将其视为 UTC 或本地时间:

The Temporal proposal is at Stage 3 as of this update in August 2021. You can use it to parse your string, either treating it as UTC or as local time:

将字符串视为UTC:

// (Getting the polyfill)
const {Temporal} = temporal;

const dateString = "2015-12-31 00:00:00";
const instant = Temporal.Instant.from(dateString.replace(" ", "T") + "Z");
// Either use the Temporal.Instant directly:
console.log(instant.toLocaleString());
// ...or get a Date object:
const dt = new Date(instant.epochMilliseconds);
console.log(dt.toString());

<script src="https://unpkg.com/@js-temporal/polyfill/dist/index.umd.js"></script>

或将其视为当地时间:

// (Getting the polyfill)
const {Temporal} = temporal;

const dateString = "2015-12-31 00:00:00";

console.log("Parsing as local time:");
const tz = Temporal.Now.timeZone();
const instant = tz.getInstantFor(dateString.replace(" ", "T"));
console.log(instant.toLocaleString());
const dt = new Date(instant.epochMilliseconds);
console.log(dt.toString());

<script src="https://unpkg.com/@js-temporal/polyfill/dist/index.umd.js"></script>

Temporal 不存在以下提到的问题,即在未指定时区时指定的日期/时间字符串格式历史上存在的问题.

Temporal doesn't have the problem mentioned below that the specified date/time string format historically had when no timezone was specified.

如果您将空格更改为 T,您将符合规范:

If you change the space to a T, you'll be in spec:

var dateString = "2015-12-31 00:00:00";
// Treats the string as local time -- BUT READ BELOW, this varied
var d = new Date(dateString.replace(" ", "T"));
console.log(d.toString());

(我假设您实际上没有使用字符串文字,因此调用了 replace.)

(I'm assuming you're not actually using a string literal, hence the replace call.)

为了在旧浏览器中可靠地处理时区,您还需要附加 Z(用于 GMT/UTC)或时区指示符(+/- HH:MM),因为在 ES5 中错误地指定了没有它们的字符串的处理,在 ES2015 中更新,然后在 ES2016 中进一步更新.当前版本的现代浏览器现在遵循规范,其中说:

For reliable timezone handling in old browsers, you'll also want to append a Z (for GMT/UTC) or a timezone indicator (+/- HH:MM), because the handling of strings without them was mis-specified in ES5, updated in ES2015, and then updated further in ES2016. Current versions of modern browsers follow the spec now, which says:

  • 如果字符串上有时间但没有时区指示符,则以本地时间解析字符串
  • 如果字符串上没有时间并且没有时区指示符,则以 UTC 格式解析字符串

(ES5 说总是默认UTC.ES2015 表示 总是默认为本地时间. ES2016 是定义当前行为的地方. 从那以后一直很稳定.)

(ES5 said always default to UTC. ES2015 said always default to local time. ES2016 is where the current behavior was defined. It's been stable since.)

因此最好包含时区指示器,尤其是在您必须支持旧浏览器的情况下.注意必须是 Z (UTC) 或 +/- HH:MM;不允许使用像 CST 这样的缩写,因为它们没有标准.这是一个 UTC 示例:

So it's best to include a timezone indicator, especially if you have to support older browsers. Note that it must be a Z (UTC) or +/- HH:MM; abbreviations like CST are not allowed, as there's no standard for them. Here's a UTC example:

var dateString = "2015-12-31 00:00:00";
// Treat the string as UTC
var d = new Date(dateString.replace(" ", "T") + "Z");
console.log(d.toString());

有第二种格式不在规范中,但几乎得到普遍支持并且已经存在很长时间了:YYYY/MM/DD HH:MM:SS,它被解释为当地时间.所以:

There's a seconnd format that isn't in the specification but is near-universally supported and has been for a long time: YYYY/MM/DD HH:MM:SS, which is interpreted as local time. So:

var dateString = "2015-12-31 00:00:00";
// Treats the string as local time
var d = new Date(dateString.replace(/-/g, "/"));
console.log(d.toString());

再说一次,这是未指定的行为,所以请注意空客.但它至少适用于 IE8+(可能更早)、Chrome 和其他任何使用 V8 JavaScript 引擎、Firefox 和 Safari 的产品.

Again, though, that's unspecified behavior, so caveat emptor. But it works in at least IE8+ (probably earlier), Chrome and anything else using the V8 JavaScript engine, Firefox, and Safari.

自己解析该字符串也很容易.使用 ES2020+ 特性:

It's also easy to parse that string yourself. Using ES2020+ features:

function parseDate(str) {
    const [dateparts, timeparts] = str.split(" ");
    const [year, month, day] = dateparts.split("-");
    const [hours = 0, minutes = 0, seconds = 0] = timeparts?.split(":") ?? [];
    // Treats the string as UTC, but you can remove the `Date.UTC` part and use
    // `new Date` directly to treat the string as local time
    return new Date(Date.UTC(+year, +month - 1, +day, +hours, +minutes, +seconds));
}

const dateString = "2015-12-31 00:00:00";
const d = parseDate(dateString);
console.log(d.toString());

或者只有 ES5 级别的特性(因为问题来自 2015 年):

Or with only ES5-level features (since the question is from 2015):

function parseDate(str) {
    var parts = str.split(" ");
    var dateparts = parts[0].split("-");
    var timeparts = (parts[1] || "").split(":");
    var year = +dateparts[0];
    var month = +dateparts[1];
    var day = +dateparts[2];
    var hours = timeparts[0] ? +timeparts[0] : 0;
    var minutes = timeparts[1] ? +timeparts[1] : 0;
    var seconds = timeparts[2] ? +timeparts[2] : 0;
    // Treats the string as UTC, but you can remove the `Date.UTC` part and use
    // `new Date` directly to treat the string as local time
    return new Date(Date.UTC(year, month - 1, day, hours, minutes, seconds));
}

var dateString = "2015-12-31 00:00:00";
var d = parseDate(dateString);
console.log(d.toString());

这篇关于Javascript 日期在 iOS 上无效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆