Safari 中的日期无效

Posted

技术标签:

【中文标题】Safari 中的日期无效【英文标题】:Invalid date in safari 【发布时间】:2011-05-17 16:37:48 【问题描述】:
 alert(new Date('2010-11-29'));

chrome, ff 对此没有问题,但 safari 会喊“无效日期”。为什么?

编辑:好的,根据下面的 cmets,我使用了字符串解析并尝试了这个:

alert(new Date('11-29-2010')); //doesn't work in safari
alert(new Date('29-11-2010')); //doesn't work in safari
alert(new Date('2010-29-11')); //doesn't work in safari

编辑 2018 年 3 月 22 日:似乎人们仍然在这里登陆 - 今天,我会使用 momentdate-fns 并完成它。 Date-fns 也非常轻松且无痛。

【问题讨论】:

仅针对其他正在寻找相同问题的人:我最终使用了 DateJS,它总体上解决了我的问题。有关详细信息,请参阅接受的答案。 使用moment.js 解析时间戳。特别是在处理跨平台网络时 这是一个老问题。从 ECMAScript 2015 开始,ISO 8601 仅日期字符串被解析为 UTC。但是,可能仍有一些旧浏览器根本不解析它或将其视为本地浏览器。 What are valid Date Time Strings in javascript? 如问题“alert(new Date('29-11-2010')); alert(new Date('2010-29-11'));”中所述这两种格式在 Firefox/Chrome 中也不起作用。所以这两种格式我认为是完全错误的,根本不应该使用。 【参考方案1】:

对我来说,仅仅因为 Safari 不能正确地实现一个新的库就太过分了,而且正则表达式是矫枉过正的。 这是oneliner

console.log (new Date('2011-04-12'.replace(/-/g, "/")));

【讨论】:

这一行帮助非常适合我的需要!谢谢! 这对我来说也很简单。不敢相信 Safari 不喜欢 - 但是带有 \\ 的相同格式可以工作。感谢@Elzo 并感谢 Shrinath 发布问题 我认为这是我倾向于忘记的最佳答案 ///g 而不是'-' 掌声 没有实现一个库。 我仍然不明白为什么人们想要将整个库用于单一用途。荣誉没有实现一个。【参考方案2】:

yyyy-MM-dd 模式不是Date 构造函数的官方支持格式。 Firefox 似乎支持它,但不要指望其他浏览器也这样做。

以下是一些受支持的字符串:

MM-dd-yyyy yyyy/MM/dd MM/dd/yyyy MMMM dd, yyyy MMM dd, yyyy

DateJS 似乎是解析非标准日期格式的好库。

编辑:刚刚检查了ECMA-262 standard。引用第 15.9.1.15 节:

日期时间字符串格式

ECMAScript 定义一个字符串 日期时间的交换格式 基于 ISO 的简化 8601 扩展格式。格式是 如下:YYYY-MM-DDTHH:mm:ss.sssZ 其中字段如下:

YYYY 是公历中年份的十进制数字。 “-”(连字符)在字符串中出现两次。 MM 是一年中的月份,从 01(一月)到 12(十二月)。 DD 是一个月中的一天,从 01 到 31。 “T”字面上出现在字符串中,表示开头 时间元素。 HH 是自午夜以来经过的完整小时数,为 2 十进制数字。 ":"(冒号)在字符串中出现两次。 mm 是自一小时开始以来的完整分钟数 两位小数。 ss 是自分钟开始以来的完整秒数 两位小数。 “。” (点)字面意义上的出现在字符串中。 sss 是从开始的完整毫秒数 秒为三位十进制数字。两个都 这 ”。”毫秒字段可能 省略。 Z 是指定为“Z”(对于 UTC)或“+”或“-”的时区偏移 后跟一个时间表达式 hh:mm

此格式包括仅日期格式:

YYYY YYYY-MM YYYY-MM-DD

它还包括带有时间的表单 附加一个可选的时区偏移量:

THH:mm THH:mm:ss THH:mm:ss.sss

还包括“日期时间” 可以是以上任意组合。

所以,似乎 YYYY-MM-DD 包含在标准中,但出于某种原因,Safari 不支持它。

更新:看了datejs documentation之后,使用它,你的问题应该可以用这样的代码解决:

var myDate1 = Date.parseExact("29-11-2010", "dd-MM-yyyy");
var myDate2 = Date.parseExact("11-29-2010", "MM-dd-yyyy");
var myDate3 = Date.parseExact("2010-11-29", "yyyy-MM-dd");
var myDate4 = Date.parseExact("2010-29-11", "yyyy-dd-MM");

【讨论】:

第 5 版 ECMAScript 标准使用 ISO8601 格式,尚未得到广泛支持,最安全的 IMO 方式,手动解析日期:( 这对伙计很有帮助.. 谢谢.. :) 最终使用 datejs 进行格式化。 对于那些未来的人,请注意,虽然 datejs 在大多数方面都很棒,但它并不能解决所有日期格式问题,尤其是 safari。这是一个 PITA,但如果仍有问题,最好手动完成。 我的类似问题是由于 Safari 不知道如何以 RFC 822 时区格式读取时区。我能够通过使用 ISO 8601 格式来解决这个问题。如果您可以控制日期格式,我可以使用“yyyy-MM-dd'T'HH:mm:ss.sssXXX”创建即。 “2018-02-06T20:00:00.000+00:00”。无论出于何种原因,Safari 无法读取“2018-02-06T20:00:00.000+0000”,请注意时区格式中缺少冒号。 Safari 是新的 Internet Explorer!【参考方案3】:

我遇到了类似的问题。 Date.Parse("DATESTRING") 正在使用 Chrome(版本 59.0.3071.115)但不是 Safari(版本 10.1.1 (11603.2.5))

Safari:

Date.parse("2017-01-22 11:57:00")
NaN

铬:

Date.parse("2017-01-22 11:57:00")
1485115020000

对我有用的解决方案是将 dateString 中的空格替换为 "T"。 (例如:dateString.replace(/ /g,"T")

Safari:

Date.parse("2017-01-22T11:57:00")
1485086220000

铬:

Date.parse("2017-01-22T11:57:00")
1485115020000

请注意,来自 Safari 浏览器的响应比在 Chrome 浏览器中看到的响应少 8 小时(28800000 毫秒),因为 Safari 在本地 TZ 中返回响应(比 UTC 晚 8 小时)

在同一个 TZ 中获得两个时间

Safari:

Date.parse("2017-01-22T11:57:00Z")
1485086220000

铬:

Date.parse("2017-01-22T11:57:00Z")
1485086220000

【讨论】:

或者,如果您不希望 Safari 和 Chrome 中的两个日期相同,您可以使用 new Date(year, month, date, hours, minutes, seconds, milliseconds) 构造函数。将字符串日期解析为其组件的数组,以便在构造函数中使用这些组件。 @nizantz 如果您认为可以将此类示例添加到您的答案中,那就太好了。 不是特别有用,因为你得到的是 UTC 日期而不是本地时间。 dateString.replace(/ /g,"T") 神奇的代码行对我有效。 :) 替换(/-/g, '/') 谢谢!比使用整个额外的库要容易得多!【参考方案4】:

我用时刻来解决问题。 例如

var startDate = moment('2015-07-06 08:00', 'YYYY-MM-DD HH:mm').toDate();

【讨论】:

感谢您的推荐!它是 Internet 上唯一适用于 React 应用程序的应用程序:ios IPAD/IPHONE: chrome/safari ||安卓:铬 ||窗户:镀铬。没有测试所有设备和操作系统版本,但它仍然适用于我找到的所有设备! 对于任何未来的观众,请注意moment 库现已弃用【参考方案5】:

要让解决方案适用于大多数浏览器,您应该使用这种格式创建日期对象

(year, month, date, hours, minutes, seconds, ms)

例如:

dateObj = new Date(2014, 6, 25); //UTC time / Months are mapped from 0 to 11
alert(dateObj.getTime()); //gives back timestamp in ms

适用于 IE、FF、Chrome 和 Safari。甚至更旧的版本。

IE Dev Center: Date Object (JavaScript)

Mozilla Dev Network: Date

【讨论】:

我认为 new Date(2014, 6, 25) 不会创建 UTC 时间,而是创建本地时区 '2014-6-25T00:00' 的时间戳。 new Date(Date.UTC(2014, 6, 25)) 给出 UTC【参考方案6】:

将字符串转换为日期 fromat(您必须知道服务器时区)

new Date('2015-06-16 11:00:00'.replace(/\s+/g, 'T').concat('.000+08:00')).getTime()  

其中 +08:00 = 服务器的时区

【讨论】:

这不考虑夏令时。 TZ 偏移量可能会波动,它取决于日期本身(和时间)。【参考方案7】:

我遇到了同样的问题。然后我使用了moment.Js。问题消失了。

当从字符串创建时刻时,我们首先检查字符串是否 匹配已知的 ISO 8601 格式,然后回退到 new Date(string) if 未找到已知格式。

警告:浏览器对解析字符串的支持不一致。因为 没有关于应该支持哪些格式的规范,什么 在某些浏览器中有效,在其他浏览器中无效。

为了获得一致的结果,解析除 ISO 8601 字符串之外的任何内容, 你应该使用字符串+格式。

例如

var date= moment(String);

【讨论】:

【参考方案8】:

尽管您可能希望浏览器支持ISO 8601(或其仅日期子集),但事实并非如此。我所知道的所有浏览器(至少在我使用的美国/英语语言环境中)都能够解析可怕的美国 MM/DD/YYYY 格式。

如果您已经有了日期的各个部分,您可能想尝试使用Date.UTC()。如果没有,但必须使用YYYY-MM-DD 格式,我建议使用正则表达式解析你知道的部分,然后将它们传递给Date.UTC()

【讨论】:

我猜字符串解析是要走的路:(【参考方案9】:

用fix-date劫持Date怎么样?无依赖,min + gzip = 280 B

【讨论】:

唯一适用于我的解决方案。谢谢干杯...【参考方案10】:

我在 Safari 浏览器中也遇到了同样的问题

var date = new Date("2011-02-07");
console.log(date) // IE you get ‘NaN’ returned and in Safari you get ‘Invalid Date’

解决方案在这里:

var d = new Date(2011, 01, 07); // yyyy, mm-1, dd  
var d = new Date(2011, 01, 07, 11, 05, 00); // yyyy, mm-1, dd, hh, mm, ss  
var d = new Date("02/07/2011"); // "mm/dd/yyyy"  
var d = new Date("02/07/2011 11:05:00"); // "mm/dd/yyyy hh:mm:ss"  
var d = new Date(1297076700000); // milliseconds  
var d = new Date("Mon Feb 07 2011 11:05:00 GMT"); // ""Day Mon dd yyyy hh:mm:ss GMT/UTC 

【讨论】:

【参考方案11】:

使用以下格式,适用于所有浏览器

var year = 2016;
var month = 02;           // month varies from 0-11 (Jan-Dec)
var day = 23;

month = month<10?"0"+month:month;        // to ensure YYYY-MM-DD format
day = day<10?"0"+day:day;

dateObj = new Date(year+"-"+month+"-"+day);

alert(dateObj); 

//您的输出将如下所示“Wed Mar 23 2016 00:00:00 GMT+0530 (IST)”

//请注意,在这种情况下,这将是当前时区,由 IST 表示,要转换为 UTC 时区,您可以包括

alert(dateObj.toUTCSting);

//您现在的输出应该是“Tue, 22 Mar 2016 18:30:00 GMT”

请注意,现在 dateObj 以 GMT 格式显示时间,同时请注意日期和时间已相应更改。

“toUTCSting”函数检索格林威治子午线的相应时间。这是通过建立您当前时区与格林威治子午线时区之间的时差来实现的。

在上述情况下,转换前的时间是 2016 年 3 月 23 日的 00:00 小时和分钟。从 GMT+0530 (IST) 小时转换为 GMT 后(它基本上从给定的时间减去 5.30 小时)在这种情况下为时间戳)时间反映了 2016 年 3 月 22 日的 18.30 小时(正好比第一次晚 5.30 小时)。

进一步将任何日期对象转换为您可以使用的时间戳

alert(dateObj.getTime());

//输出看起来类似于“1458671400000”

这将为您提供时间的唯一时间戳

【讨论】:

【参考方案12】:

最好的方法是使用以下格式:

new Date(year, month, day, hours, minutes, seconds, milliseconds)
var d = new Date(2018, 11, 24, 10, 33, 30, 0);

所有浏览器都支持此功能,不会给您带来任何问题。 请注意,月份是从 0 到 11。

【讨论】:

在 Safari 和 Chrome 上运行良好,但在 Firefox 上仍然存在问题。 Safari: var date = new Date(2018,06,08,19,17) Sun Jul 08 2018 19:17:00 GMT+0800 (+08) Chrome: var date = new Date(2018,06,08,19, 17) Sun Jul 08 2018 19:17:00 GMT+0800 (Malaysia Time) Firefox: var date = new Date(2018,06,08,19,17) Date 2018-07-08T11:17:00.000Z【参考方案13】:

对我来说,问题是我忘记在 YYYY-MM-DD 格式的单个数字月份或日期之前添加 0。 我正在解析的内容:2021-11-5 应该是什么:2021-11-05

所以,我写了一个小工具,将YYYY-M-D 转换为YYYY-MM-DD,即2021-1-1 转换为2021-01-01

const date = "2021-1-1"
const YYYY = date.split("-")[0];

    //convert M->MM i.e. 2->02
    const MM =
      date.split("-")[1].length == 1
        ? "0" + date.split("-")[1]
        : date.split("-")[1];

    //convert D->DD i.e. 2->02
    const DD =
      date.split("-")[2].length == 1
        ? "0" + date.split("-")[2]
        : date.split("-")[2];

    // YYYY-MM-DD
    const properDateString = `$YYYY + "-" + MM + "-" + DD`;

    const dateObj = new Date(properDateString);

【讨论】:

【参考方案14】:

在 Safari 中遇到同样的问题,通过在网页中插入这个问题解决了

 <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.en"></script> 

希望它也适用于您的情况

谢谢

【讨论】:

为什么你认为这会起作用?我查看了脚本,它似乎没有覆盖 Date 对象中的方法。我去了这里:polyfill.io/v3/url-builder,似乎没有关于解析日期的内容。【参考方案15】:

正如@nizantz 之前提到的,在 Safari 中使用 Date.parse() 对我不起作用。经过一番研究,我了解到 File 对象的 lastDateModified 属性已被弃用,Safari 不再支持。使用 File 对象的 lastModified 属性解决了我的问题。当网上发现不良信息时,肯定不喜欢它。

感谢所有为这篇文章做出贡献的人,他们帮助我走上了了解我的问题所需的道路。如果没有这些信息,我可能永远也不会弄清楚我的根本问题。也许这会帮助我遇到类似情况的其他人。

【讨论】:

【参考方案16】:

迟到了,但在我们的例子中,我们在 Safari 和 iOS 中使用 ES6 反引号而不是 String() 来键入 cast 时遇到了这个问题

这给出了“无效日期”错误

const dateString = '2011-11-18';
const dateObj = new Date(`$dateString`); 

但是这行得通

const dateObj = new Date(String(dateString)); 

【讨论】:

【参考方案17】:

对于使用date-fns的人,我们可以parseISO日期并使用它来格式化

无效

import _format from 'date-fns/format';

export function formatDate(date: string, format: string): string 
  return _format(new Date(date), format);

这个函数在 safari 上使用Invalid date 抛出错误。

解决方案 要修复它,我们应该使用:

import _format from 'date-fns/format';
import _parseISO from 'date-fns/parseISO';

export function formatDate(date: string, format: string): string 
  return _format(_parseISO(date), format);

【讨论】:

【参考方案18】:

这不起作用alert(new Date('2010-11-29')); safari 有一些奇怪/严格的处理日期格式的方法alert(new Date(String('2010-11-29'))); 试试这样。

(或)

虽然使用 Moment js 会解决这个问题,但在 ios 14 之后,safari 变得更加奇怪

试试这个警报(moment(String("2015-12-31 00:00:00")));

时刻 JS

【讨论】:

在将其粘贴到更多位置之前,请花时间阅读Is it acceptable to add a duplicate answer to several questions?。 请停止向其他人推荐momentjs momentjs.com/docs/#/-project-status【参考方案19】:

使用格式“mm/dd/yyyy”。例如:- 新日期('02/28/2015')。它适用于所有浏览器。

【讨论】:

【参考方案20】:

这不是最好的解决方案,尽管我只是捕捉到错误并发回当前日期。如果用户想使用不符合标准的浏览器,我个人觉得不解决 Safari 问题 - 他们必须忍受怪癖。

function safeDate(dateString = "") 
  let date = new Date();
  try 
    if (Date.parse(dateString)) 
      date = new Date(Date.parse(dateString))
    
   catch (error) 
    // do nothing.
  
  return date;

我建议让您的后端发送 ISO 日期。

【讨论】:

恕我直言,当您的意思是用户必须使用您为其编写代码的浏览器时,这在一般意义上看起来很糟糕。这也取决于我们的用例和目标受众——如果一个网站是为大众市场消费而构建的,我们至少也会支持 IE10。我确信 MS 中的某些人在为 Internet Explorer 设计/编码时也有同样的想法。我们都知道现在是如何谈论它的。

以上是关于Safari 中的日期无效的主要内容,如果未能解决你的问题,请参考以下文章

Safari中的Jquery UI日期选择器黑色背景部分

隐藏luxon中的无效日期

检查 Amazon Redshift 中的无效日期

在 Safari 上使用 React 的日期选择器

即使日期格式支持 ISO 8601,IE11 中的日期也无效

在日历中的特定日期显示背景颜色的问题,在除移动 Safari 之外的所有浏览器上都可以正常工作