【问题标题】:How to subtract or add GMT number from new Date in JavaScript?如何从 JavaScript 中的新日期中减去或添加 GMT 数字?
【发布时间】:2020-06-08 05:14:14
【问题描述】:

我有 IST 日期和时间 - Thu Oct 01 2020 05:30:00 GMT+0530(印度标准时间),我需要根据用户浏览器时区转换该日期时间。 因此,如果我可以从我的日期时间中减去或添加 GMT 值,我可以获得正确的日期时间。 请帮忙。

        var newdate = $(this).data("systemdate");
        var format = $(this).data("format");

        var timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
        var tm_short = moment.tz(newdate, timezone).format('z');

        var datecoverted = new Date(newdate+" GMT+0530")

        var result = moment(datecoverted).format(format); 

我已尝试使用上述代码,它在 chrome 中运行良好。但它在 Mozilla Firefox 中显示无效日期。

【问题讨论】:

  • 欢迎来到 Stack Overflow。请查看How do I ask a good question。如果您不向我们展示导致问题的代码,我们将无法提供帮助。请编辑您的问题,在 Minimal, Complete, and Verifiable example 中包含 相关 代码以及您已尝试解决问题的摘要,以便我们提供帮助。
  • 感谢您更新问题。您能告诉我们您在 Firefox 中遇到的确切错误吗?
  • 显示“无效日期”
  • 实际上 Mozilla 在我的代码中不支持 'datecoverted' 变量。
  • 你为什么不用moment.tz?

标签: javascript datetime


【解决方案1】:

格式为 Thu Oct 01 2020 05:30:00 GMT+0530(印度标准时间)的时间戳是内置解析器可靠解析的仅有的两个时间戳之一,因此您可以将它们直接传递给 Date 构造函数:

let d = new Date('Thu Oct 01 2020 05:30:00 GMT+0530 (India Standard Time)');

如果时间戳是在客户端系统上生成的,那么默认使用系统时区偏移量:

d.toString(); // e.g. Thu Oct 01 2020 09:00:00 GMT+0900 (WIT)

所以不需要图书馆或任何搞乱时区的东西。

如果你真的想要使用一个库,那么你可以在 moment.js 中使用以下代码做同样的事情:

// Timestamp to parse
let s = 'Thu Oct 01 2020 05:30:00 GMT+0530 (India Standard Time)';

// POJS
console.log(new Date(s).toString());

// With moment.js
let format = 'ddd MMM DD YYYY HH:mm:ss ZZ';
console.log(moment(s, format).format(format));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.26.0/moment.min.js"></script>

【讨论】:

  • 您没有阅读 cmets。他试图将没有适当时区信息的 ISO 日期时间转换为本地时间,并且它在 Firefox 中被打破,因为 Firefox 下的 Date.parse (和构造函数)更具限制性并且也无法解析奇怪的日期字符串。您的代码仍然无法为他工作,并且不会进行他想要的时区转换。如果您想查看并理解其中的推理,您可以尝试阅读我编写的代码和讨论 OP 问题的 cmets。
  • 如果你想为他写一个没有时间的版本,你可以使用这个字符串:“2020-11-01 05:30:00”。 @RobG 尝试将您声称已可靠解析的字符串提供给 moment.js 并查看闪烁的警告。 不建议您使用提供给 Date.parse 的那种格式的字符串,因为其他比我们更有经验的人认为这种解析跨平台不可靠。
  • @user120242—ECMA-262不难发现:“[Date.parse]函数首先尝试按照日期时间字符串格式(@987654322)中描述的格式解析字符串@)…”。您从 moment.js 看到的警告不规范。
  • @user120242 — MDN 是一个任何人都可以贡献的公共 wiki,它不具有权威性。我知道它关于内置解析器的警告——我对它们负有部分责任。自 2011 年的 EMCA-262 第 5 版(又名 ES5)以来,浏览器被要求解析格式为 YYYY-MM-DDTHH:mm:ss.sssZ 的字符串,当时只有 IE8 不兼容。从 ECMAScript 2016 开始,他们还需要解析由他们的 toString 和 toUTCString 方法生成的字符串。从 ECMAScript 2018 开始,toString 的格式已经标准化。所以浏览器应该(并且确实)正确地解析它们。
  • @user120242 — MDN Date 构造函数页面上对 RFC 2822 的引用是一个红鲱鱼,它没有在 Date.parse 页面上引用(应该是解析信息所在的位置)。 ECMA-262 为 toString 指定的格式不符合 RFC 2822(尽管非常接近)。
【解决方案2】:

注意:“仅按惯例支持 RFC 2822 格式字符串。” MDN reference(RFC2822 是 OP 问题开头的字符串格式)
因此可以得出结论,在规范中到处使用“依赖于实现”的语言是故意模棱两可的,这取决于浏览器开发人员的选择,但坚持认为它不是规范的。
您可能可以使用它,就像可以使用对象映射键顺序一样,但重要的是要区分它不是由规范,例如 moment.js 最有可能选择拒绝它正是因为这个原因。

OP 试图建立自己的 ISO 日期字符串,但 FF 无法读取,因为他使用了错误的后缀。他可能已经通过验证他的字符串并使用:
datestring +='+05:30'
而不是 GMT+05:30,这会使 ISO 字符串无效。

未来读者的注意事项。 moment.js 确实存在一些问题,并且不一定是与 Dates 相关的所有内容的最佳选择。大多数情况下,您只需使用普通日期和时间戳数学即可,您实际上不需要引入 moment.js 作为依赖项。

但是,正如该线程中所示,日期解析可能会出现问题,并且允许内置日期解析您的日期可能会导致意外结果,特别是因为不同的平台可能会给出不同的结果。确保您充分了解平台之间的细微差别。
(时区差异、闰年、月日差异、字符串格式(现在使用 Intl.DateTimeFormat 已经足够好了)是您应该使用日期库的其他一些原因。虽然 moment(tz) 确实有 @987654322 @即使在这方面。)

问题顶部给出的日期类似于 ES2015 中批准的日期格式的(字符串显示表示)。不幸的是,月份和日期与批准的标准的顺序不同,这导致与 OP 通信时出现更多问题。

使用 moment、moment.tz 和 custom format

//var newdate = $(this).data("systemdate");
//var format = $(this).data("format");

// shim newdate, format values
newdate=`Thu Oct 01 2020 05:30:00 GMT+0530 (India Standard Time)`
format = `ddd MMM DD YYYY hh:mm:ss ZZ`

var timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
// other ways to get timezone.  use the one that gets the right results:
t=new Date().getTimezoneOffset()/60
var timezone2 = `+${`${t|0}`.padStart(2,'0')}:${`${(t-(t|0))*60}`.padStart(2,'0')}` 

console.log(moment.tz.guess(), timezone, timezone2)

// example custom format string using strict mode and isValid() for first example:
var result = moment(newdate.replace(/ \(.*\)/,''),'ddd MMM DD YYYY HH:mm:ss [GMT]Z', true)
if (result.isValid())
 result = result.tz(timezone).format(format)
else; //didn't match, continue to try to parse date string with other methods here

console.log(result);

newdate=`2020-11-01 05:30:00`

// this works, but is not recommended:
// should use strict mode to make sure you recognize the format
// and you want to force time zone parsing in your desired time zone
var result = moment.tz(newdate, 'Asia/Calcutta').tz(timezone).format(format);
console.log(result);

// notice 3rd parameter is true for strict mode.  reject dates that don't match
var result = moment.tz(newdate, 'YYYY-MM-DD HH:mm:ss', true, 'Asia/Calcutta')
if (result.isValid())
 result = result.tz(timezone).format(format)
else; // try to fallback to parsing date other ways
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.25.3/moment-with-locales.min.js" integrity="sha256-8d6kI5cQEwofkZmaPTRbKgyD70GN5mDpTYNP9YWhTlI=" crossorigin="anonymous"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.28/moment-timezone-with-data.js" integrity="sha256-O1PdKrSbpAYWSBteb7yX/CMmHhu3US31mtCbsryGwaY=" crossorigin="anonymous"></script>

【讨论】:

  • 无效日期对象 { _isAMomentObject: true, _i: "Thu Oct 01 2020 05:30:00 GMT+0530 (India Standard Time)", _f: "ddd MMM DD YYYY HH:mm:ss Z", _tzm: 330, _isUTC: false, _pf: {…}, _locale: {…}, _a: (7) […], _d: 日期 Thu 2020 年 10 月 1 日 05:30:00 GMT+0530(印度标准Time), _isValid: true, ... } Thu Oct 01 2020 05:30:00 +0530
  • 会一直是(印度标准...)吗?我已对其进行了更新,并选择丢弃括号中的时区(如果找到)
  • 是的,它将永远是印度标准时间。我尝试使用更新的代码......在 chrome 上它正在工作。时间没有改变......它显示相同的日期时间 Thu Oct 01 2020 05:30:00 GMT+0530
  • {…} _a: Array(7) [ 2020, 9, 1, ... ] _d: Date Thu Oct 01 2020 05:30:00 GMT+0530 (India Standard Time) ​ _f : "ddd MMM DD YYYY HH:mm:ss [GMT]Z" _i: "Thu Oct 01 2020 05:30:00 GMT+0530" _isAMomentObject: true _isUTC: false _isValid: true _locale: Object { _calendar: {…}, _longDateFormat: {…}, _invalidDate: "无效日期", … } _pf: Object { empty: false, overflow: -1, charsLeftOver: 0, … } _tzm: 330 _z: null ​: Object { add: qt(e, t), calendar: calendar(e, t), clone: clone(), ... } Thu Oct 01 2020 05:30:00 +0530
  • 我使用Thu Oct 01 2020 05:30:00 GMT+0530 (India Standard Time) 作为模型解析的日期字符串。这是您使用的日期时间的实际格式吗?您使用的是非标准的日期字符串格式,因此需要特殊处理。
猜你喜欢
  • 2011-01-21
  • 1970-01-01
  • 1970-01-01
  • 2011-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-12
相关资源
最近更新 更多