ToLocaleDateString() 在 IE11 中的变化

IT技术 javascript date internet-explorer-11
2021-02-06 13:06:09

在 IE 11 中,我使用 ToLocaleDateString() 得到了有趣的结果。返回的字符串在浏览器中看起来不错,例如“1/28/2014 11:00:46 AM”,但是如果我将该值复制并粘贴到纯文本编辑器中,它看起来像这样:“?1?/? 28?/?2014?11?:?00?:?46??AM”。

有趣的是,如果我将文本粘贴到 Microsoft 产品中,它看起来不错……问题是,如果您尝试以编程方式使用该值来创建日期,则它无效。您可以通过在 IE11 中打开控制台并在其上使用 ToLocaleDateString() 创建一个新日期来测试这一点,然后尝试使用结果字符串在 javascript 或您选择的语言中创建一个新日期(我'我在这里使用 ASP.NET...)。

我做错了什么,还是我应该通过其他方式与 javascript Date 交互?我怎样才能摆脱那些时髦的符号?

编辑: 感谢下面的评论,我能够弄清楚未显示的字符是什么,它们是从左到右的标记。根据我将值粘贴到的编辑器和编辑器设置使用的编码,文本会以不同的方式显示:有时带有“?”,有时没有。

5个回答

我用下面的replace(/[^ -~]/g,'')方法解决了这个问题

(new Date("7/15/2014").toLocaleString().replace(/[^ -~]/g,'')
你的回答对我来说是最简单也最中肯的。谢谢你。
2021-04-08 13:06:09

问题是,如果您尝试以编程方式使用该值来创建日期,则它是无效的。

...

我做错了什么,还是我应该通过其他方式与 javascript Date 交互?

是的,你做错了。您不应该使用旨在为特定于语言环境的人类显示格式化某些内容的函数,并期望输出是机器可解析的。任何的输出的toLocaleStringtoLocaleDateStringtoLocaleTimeString仅仅是用来人类可读显示。(正如 Bergi 在评论中澄清的那样,toString也用于人类展示,但ECMA §15.9.4.2说它应该往返)

您可能会获得 LTR 标记,因为您的显示区域设置是 RTL。除此之外,请考虑语言环境将始终影响输出。也许您的语言环境使用 dd/mm/yyyy 格式而不是 mm/dd/yyyy 格式。或者,您的语言环境可能需要亚洲或阿拉伯字符。这些都是确定显示格式时的考虑因素,但并不适合机器解析。

还要考虑一下,ECMAScript 规范并没有为这些方法的输出定义任何特定的格式规则,不同的浏览器会产生不同的结果。

如果意图不是向用户显示,那么您应该使用以下功能之一:

  • toISOString 会给你一个 ISO8601/RFC3339 格式的时间戳
  • toGMTString或者toUTCString会给你一个 RFC822/RFC1123 格式的时间戳
  • getTime 会给你一个毫秒精度的整数 Unix 时间戳

以上所有内容都将返回一个基于 UTC 的值。如果你想在本地时间,你可以建立自己的字符串与各种存取功能(getFullYeargetMonth,等...),或者你可以使用库如moment.js

这使用 moment.js 返回 ISO8601 格式的本地时间 + 日期偏移量:

moment(theDate).format()   // ex:  "2014-08-14T13:32:21-07:00"
再说一次,如果它是一个简单的日期(例如生日),我可能不想将其转换为 UTC。整个日期和日期+时间之间存在差异。javascriptDate对象实际上是一个日期+时间对象。
2021-03-17 13:06:09
我觉得我明白了。因此,如果您正在构建一个要求出生日期的控件,并且您必须适应其他外国语言环境(RTL、dd/mm/yy 等),您将如何获得安全可解析的内容(例如 UTC 时间戳)返回到服务器,同时仍以本地化格式向用户显示所选日期?
2021-03-25 13:06:09
这就是为什么这么多日期输入控件让您从日历中选择而不是解析输入的原因。虽然有一些方法。Moment.js 具有针对各种语言环境的输入解析,HTML5 日期/时间/日期时间输入也有一些。Date对象也可以进行一些解析,并且它应该适用于当前的语言环境。但是没有一种方法可以接受用户可能输入的所有内容。大多数情况下,您希望给用户一些预期输入格式的提示。
2021-03-28 13:06:09
虽然toString输出用于人类可读的显示,但它不仅用于此。看看第15.9.4.2 节:“对于一个Date对象x,它是预期的x.valueOf() === Date.parse(x.toString())”——当然这不会使它成为一种实现间的交换格式,但它需要以某种方式进行解析。
2021-03-31 13:06:09
@Bergi - 谢谢。而在相同的部分,它说toLocaleString没有要求这样做。编辑了我的答案。:)
2021-04-10 13:06:09
function FixLocaleDateString(localeDate) {
    var newStr = "";
    for (var i = 0; i < localeDate.length; i++) {
        var code = localeDate.charCodeAt(i);
        if (code >= 47 && code <= 57) {
            newStr += localeDate.charAt(i);
        }
    }
    return newStr;
}

只返回数字和 / 字符。似乎使这项工作:

new Date(FixLocaleDateString(new Date("7/15/2014").toLocaleString()));

返回正确的日期。如果不调用 FixLocaleDateString(),结果将是无效日期。

根据您使用的服务器端技术,左/右字符会得到正确处理(即,忽略)。我将它与 MVC 5 Web 服务一起使用,将输入作为字符串传输,然后我通过 DateTime.Parse 使用解析 - 它可以处理任何编码的字符串,包括包含空白字符的字符串,如 Unicode 字节顺序标记等。不犯错误。这是一个黑客。这是解决 IE 的 JavaScript 实现中的错误的方法。Webkit 浏览器不会遇到这个问题,因此 FixLocaleDateString 对它们来说不是必需的。
2021-03-17 13:06:09
这看起来可行,所以我将其标记为答案。不过,这感觉就像一个黑客。尝试从 ToLocaleDateString() 的输出中获取 Date 对象是错误的吗?如果日期选择器使用 ToLocaleDateString() 填充输入怎么办?你应该如何在服务器端获取日期?如果您只是从输入中获取值,它将具有从左到右的字符,这会让您感到困惑。
2021-04-06 13:06:09

为完整起见,请填写表格:

在我的系统上,IE 11 的 Date 对象的方法在控制台中运行时toLocaleDateString导致,"7/6/2014"它表示为以下字节:

00000000 22 e2 80 8e 37 e2 80 8e 2f e2 80 8e 36 e2 80 8e |"â.Z7â.Z/â.Z6â.Z|
00000010 2f e2 80 8e 32 30 31 34 22 |/â.Z2014"|

不可打印的内容0xe2 0x80 0x8e贯穿始终,它是 Unicode Code Point U+200E的 UTF-8 表示正如上面的评论所说,这是从左到右的标记。

这个 JSFiddle使用返回的值来返回toLocaleDateString()日期似乎没有问题至少在我的 IE 11.0.9600.17239 和更新版本 11.0.11 (KB2976627) 中。那么也许只有控制台添加了额外的字符?

我更新了答案以包含一个似乎没有遇到问题的 JSFiddle 链接。
2021-03-25 13:06:09
这解释了角色是什么,但这并不是谜团。我认为更大的问题是,如果您从 ToLocaleDateString() 的输出开始,如何回到实际日期
2021-04-05 13:06:09
var startDateConverted = new Date(start).toLocaleString().replace(/[^A-Za-z 0-9 \.,\?""!@#\$%\^&\*\(\)-_=\+;:<>\/\\\|\}\{\[\]`~]*/g, '')

如果您还想删除时间使用 .split(' ').slice(0, -1).join(' ');

尽管您可以将 LTR 标记 \u200E 替换为 ''。;-)
2021-03-19 13:06:09