Javascript 日期在 iOS 上无效

我正在开发一个基于 Phonegap 的 iOS 应用程序,这个应用程序已经在 Android 上使用了。下面的代码可以在 Android 上正常工作,但是在 iOS 上就不行了。为什么?

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

Android 的结果:

31.11 2015

IOS 的结果:

NaN. NaN NaN

有什么区别吗?

64071 次浏览

我不能告诉你为什么。也许是因为 iOS 不像 Android 那样支持 Javascript Date 功能,或者支持不同的格式?

但我可以给你一个变通方案:

var s = "2015-12-31 00:00:00".split(" ")[0].split("-"),
d = new Date( s[0], s[1], s[2], 0, 0, 0 );


console.log(d);

var s = "2015-12-31 00:00:00".replace(/[ :]/g, "-").split("-"),
d = new Date( s[0], s[1], s[2], s[3], s[4], s[5] );


console.log(d);

尝试与 var d = new Date("2015/12/31 00:00:00");为我工作。

您的日期字符串的格式不是指定用于 new Date的格式。规范中唯一的格式是 ES5(2009)中添加的 ISO-8601的简化版本。您的字符串不是那种格式,但是非常接近。还可以很容易地将其更改为一种不在规范中但得到普遍支持的格式

你有四个选择:

  • 使用即将推出的 Temporal特性(现在处于第3阶段)
  • 指定的格式
  • 一种几乎得到普遍支持的未指定格式
  • 你自己解析吧

使用即将推出的 Temporal特性

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

将字符串视为 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>

Or treating it as local time:

// (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 doesn't have the problem mentioned below that the specified date/time string format historically had when no timezone was specified.

The specified format

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调用。)

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

  • 如果字符串上有时间,但没有时区指示器,则以本地时间解析字符串
  • 如果字符串上没有时间,也没有时区指示器,则用 UTC 解析字符串

(ES5说始终默认为 UTC。ES2015说始终默认为本地时间。ES2016是定义当前行为的地方。从那以后就一直很稳定。)

因此,最好包含一个时区指示器,特别是如果您必须支持较老的浏览器。请注意,它必须是 Z(UTC)或 +/- HH:MM; 像 CST这样的缩写是不允许的,因为它们没有标准。这里有一个 UTC 的例子:

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,它被解释为本地时间。所以:

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 的浏览器上运行。

你自己解析吧

使用 ES2020 + 功能:

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年) :

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

还有

var d = new Date("2015/12/31T00:00:00");

为我工作:)

谢谢@dda

一个同时适用于 IOS 和 Android 的解决方案,并且在不需要时避免字符串操作

let fullDate = "1991-03-29 00:00:00";
let date = new Date(fullDate);


// In case its IOS, parse the fulldate parts and re-create the date object.
if(Number.isNaN(date.getMonth())) {
let arr = fullDate.split(/[- :]/);
date = new Date(arr[0], arr[1]-1, arr[2], arr[3], arr[4], arr[5]);
}

如果还有人在找的话。

为我在 IE,Safari,IOS-FF,IOS-Safari... 等工作。

getIOSSaveDateObj = function(dateString){
if(dateString.indexOf('-') > 0){
var arr = dateString.split(/[- :]/);
var date = new Date(arr[0], arr[1]-1, arr[2], arr[3], arr[4], arr[5]);
}else{
var arr = dateString.split(/[. :]/);
var date = new Date(arr[2], arr[1]-1, arr[0], arr[3], arr[4], arr[5]);
}
return date;
}

我有这么一个困难的时间试图解决这个问题,我最终去寻找一个更简单的解决方案,并使用 等一下 JS。您不需要做太多,只需声明日期并在每个设备中工作即可。