JavaScript日期转换成带有ISO格式的字符串(带有时区)

8

我一直在使用MomentJS,但是我正在开始一个新项目,因为我只需要处理几次日期,所以我不想包含这个库。

所以我要做的就是获取日期的字符串表示形式,以ISO格式('YYYY-MM-DDZHH:mm:ss'或'YYYY-MM-DD HH:mm:ss')呈现。我不想用UTC,我想用给定的时区(可以通过程序提供)。

例如,现在的表示形式将是“2017-04-11 11:20:00”(法国时区 - 相当于“2017-04-11 09:22:00Z”)。

我想使用本地JavaScript。我已经尝试过toLocaleString,但没有成功。

谢谢

[编辑]在完美的世界中,我正在寻找一个函数,它接受日期格式、时区,并返回我想要的字符串。例如:

function magicDateFormatter(format, tz) {
  /* ... */
}

var now = new Date();
console.log(magicDateFormatter('YYYY-MM-DD HH:mm:ss', 'Europe/Paris'));
// print "2017-04-11 11:20:00"

为什么你不想包含一些能解决你遇到的问题的东西呢? - evolutionxbox
2
因为为了执行几个操作而加载一个库是过度的。 - Valentin Coudert
取决于您尝试实现这些“几个方法”所创建的技术债务量。如果您不想使用库,为什么不查看内部并仅提取所需内容? - evolutionxbox
内置的日期对象方法中没有容量来完成您所要求的操作。最终你会编写与当前执行相同操作的库几乎相同的东西。ECMA-402国际化API是实现相关的,因此虽然您可以指定部分和语言,但无法精确指定格式。此外,它指定语言而不是位置,即使语言参数被错误地称为“区域设置”。 - RobG
仅包含您所需的时区信息的IANA时区数据库的数据组件大小为205kb。 - RobG
4个回答

13
const dt = new Date().toLocaleString("sv-SE");

4
虽然这段代码可能回答了问题,但提供有关它如何和/或为什么解决问题的额外上下文信息将提高答案的长期价值。您可以在帮助中心找到有关编写好答案的更多信息:https://stackoverflow.com/help/how-to-answer。祝你好运! - nima
1
看起来没有 ISO 标准的本地化,所以最好的选择是使用一个使用 ISO 时间标准的地点的本地化。这个地方是瑞典。 - Benjamin Atkin
1
同时 new Date().toLocaleString("lt") 也可以使用。这个是立陶宛语。 - Fawaz Ahmed

3
这样的东西可能适合你:
function formatDateWithZone(date, tz) {
    var s = date.toLocaleString('en-GB', { timeZone: tz });
    var a = s.split(/\D/);
    return a[2] + '-' + a[1] + '-' + a[0] + ' ' + a[4] + ':' + a[5] + ':' + a[6];
}

使用方法:

formatDateWithZone(new Date(), 'Europe/Paris')  // "2017-04-12 03:37:59"

这将适用于通过ECMA-402实现了时区支持的环境。兼容性表在此处将向您展示哪些环境支持它们,您可以展开DateTimeFormat部分,并查看标有accepts IANA timezone names的行。

但并非所有已实现ECMA-402的浏览器都实现了除UTC以外的时区选项。对于上述情况,Firefox 38返回“RangeError:无效的时区”。此外,对于上述情况,IE 10的toLocaleString返回格式为“DDDD,d MMMM YYYY h:mm:ss A”(使用moment.js标记)的字符串,因此重新格式化也不起作用。 :-( - RobG
1
这很好,但日期缺少零填充。 - EliSherer
填充应该已经存在于从 toLocaleString 输出的结果中。 - Matt Johnson-Pint

1

像这样的东西可能是您需要的: 首先按您希望的格式对时间戳进行格式化,包括时区偏移,然后使用正则表达式的replace函数更改数字项的位置:

const timeStamp = new Date().toLocaleString('de-DE', {
                    timeZone: 'Europe/Berlin',
                    hour12: false,
                    year: "numeric",
                    month: "2-digit",
                    day: "2-digit",
                    hour: "2-digit",
                    minute: "2-digit",
                    second: "2-digit",
                }).replace(/(\d+)\.(\d+)\.(\d+),\s(\d+):(\d+):(\d+)/, "$3$2$1_$4$5$6");

2
注意——并非所有环境都支持您使用的语言环境,例如在这种情况下 de-DE。这意味着 toLocaleString 不会输出您期望的格式,因此正则表达式替换将无法工作。 - tremby
你是对的。更改区域设置将需要更改正则表达式。 - Iulian M.
我的观点更多的是,即使您拥有正确的区域设置正则表达式,也不能依赖它。一旦有一个访问者没有相同的区域设置可用,代码就无法正常工作。 - tremby

0

使用内置方法无法实现您所要求的功能,因为ECMAScript实现不需要存储所有(甚至任何)时区的历史数据。它们只需要访问主机的当前时区偏移量。

此外,ECMA-402国际化API也不足够。虽然它允许指定时区,但并非所有实现都支持ECMA-402,而且其中一些实现并不支持除“UTC”之外的时区值(这是ECMA-402要求支持的唯一值,其他值是可选的)。仅使用ECMA-402很难或几乎不可能精确指定格式。

我认为最好使用像moment.js和Moment-timezone.js这样的现有库。相对于网页的一般大小(最近似乎至少为1MB),下载量并不大。如果您尝试自己编写代码,最终会得到类似moment的东西。

为了减小下载量,您可以获取2012年至2022年的时区数据。

如果您想使用简化的调用,则可以使用一个小的magicDateFormatter来利用moment.js的内容:

/* Return date string for a date in the required timezone and format
** @param {string} timezone: IANA time zone designator, e.g. Asia/Sakhalin
** @param {Date}   [date]  : date to use, default is current date
** @param {string} [format]: output format using Moment.js tokens, 
**                         default is 'YYYY-MM-DDTHH:mm:ssZZ'
** @returns {string}       : formatted string
**
** magicDateFormatter(timezone[, date[, format]])
*/
function magicDateFormatter(timezone, date, format) {
  // Validate that the time zone is supported
  if (!moment.tz.zone(timezone)) {
    return 'Unknown time zone: "' + timezone + '"';
  }
  // Use current date if not supplied
  date = date || new Date();
  // Use default format if not supplied
  format = format || 'YYYY-MM-DDTHH:mm:ssZZ'
  return moment(date).tz(timezone).format(format)
}

console.log(magicDateFormatter('Europe/Paris'));
console.log(magicDateFormatter('Asia/Sakhalin', new Date(2016,1,29), 'Do MMMM, YYYY'));
console.log(magicDateFormatter('foo/bar'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.13/moment-timezone-with-data.min.js"></script>

当然,如果您想要的话,也可以在调用中指定格式。


1
ECMA-402 确实支持时区,并且大多数新型浏览器现在都可以使用它。 - Matt Johnson-Pint
@MattJohnson,很好知道,但是ECMA-402仍然是UTC,并支持其他时区选项。Firefox 38支持ECMA-402,但忽略时区选项,除了“UTC”之外。同时,精确指定格式仍然不太实用。 - RobG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接