解释(不转换!)日期在其他时区的JavaScript /时刻

时间:2017-10-17 07:56:00

标签: javascript date momentjs

此问题与Deprecation warning: moment construction falls back to js Date类似,因为出现了相同的警告。但是,该警告不是此问题的焦点,并且所描述的解决方案不适合我的用例。我已经编辑了下面的相应段落来解释为什么会这样。

考虑一个Web应用程序,用户可以在其中选择固定摄像机拍摄的图像的时间范围。 显然,这台相机可能不属于他自己的时区。 除此之外,提供图像的REST-API可以完成UTC中的所有操作。

我正在使用angular4,moment.js和moment timezone。

因此,他可以选择是否要在当地时区,相机所在的时区或UTC中查看带有时间戳的图像。到目前为止,一切都在努力达到这一点。

我遇到麻烦的地方是设定时间范围。显然,用户设置的开始和结束时间应该被解释为在他选择显示的时区中,因此我可以在将请求发送到服务器之前将它们转换为UTC。 我从日期选择器获取的Date对象(在这种情况下是primeng日历,但这并不重要)当然是在浏览器本地时间。

所以我需要做的就是拍摄日期并在相机的时区中解释它,而不是转换它。因此,如果用户在时区UTC -2中设置“从10:00到17:00”,并且摄像机位于UTC + 2,我需要获得“UTC +2中的10:00到17:00” ,不是“UTC +2的14:00到21:00”。

我尝试了几种方法,其中一些甚至可以工作,但每种方法似乎都有自己的注意事项,而且它们都很难看,因为它们会进行不必要的字符串转换。例如:

moment.tz(date.toLocaleString, cameraTimezone)

这样可行,但会抛出弃用警告:

  提供的

值不是公认的RFC2822或ISO格式。时刻构造回落到js Date(),这在所有浏览器和版本中都不可靠。

我可以通过指定传递的日期字符串的格式来消除该警告,但我面临的问题是toLocaleString()和toString()都不一致。 toLocaleString()显然会根据语言环境给我另一种格式,toString()会在不同的浏览器中产生不同的结果,所以我怎么知道我得到了什么呢?

所以我尝试使用正确的格式,但如果直接使用Date::toIsoString,我得到的那一刻就转换为UTC,这不是我所需要的:

let datestring = date.toISOString();   //datestring will be in utc
const mom = moment.tz(datestring, cameraTimezone);  //moment will therefore be the wrong time.

有一种显而易见的方法是自己创建一个Date对象的字符串(这在javascript中非常难看),然后通过指定该格式将其解析为片刻。但所有这些字符串转换感觉更像是一个黑客,而不是一个正确的解决方案,我真的想完全摆脱它们,只是告诉时刻“这里你有一个约会,它应该在这个时区,即使它说它不是“。有没有办法做到这一点?

1 个答案:

答案 0 :(得分:1)

它可能适合根据本地日期和用户选择的时间和时区构建符合ISO 8601标准的字符串,例如

window.onload = function() {
  var form = document.getElementById('cameraTimeDetail');
  form.addEventListener('submit', getPicISO, false);
  
}

function getPicISO(e) {

  // For demo
  e.preventDefault();

  function z(n){return ('0'+n).slice(-2)}
  var date = new Date();
  var form = this;
  
  // Use local date parts
  var s = date.getFullYear() + '-' +
          z(date.getMonth()+1) + '-' +
          z(date.getDate()) + 'T' +
          // Use input timezone and time
          form.pictureTime.value + 
          form.cameraTimezone.value;

  // Consructed ISO string
  form.timeString.value = (s);
  
  // Convert to UTC ISO String
  form.timeStringUTC.value = new Date(s).toISOString();

  return false;
}
input, button {
  width: 15em;
}
<form id="cameraTimeDetail">
  <table>
    <tr>
      <td>Enter timezone (e.g. -08:00, +05:30)
      <td><input name="cameraTimezone" value="+05:30">
    <tr>
      <td>Enter time (HH:mm)
      <td><input name="pictureTime" value="14:37">
    <tr>
      <td><input type="reset">
      <td><button>Get pic</button>
    <tr>
      <td>Selected date and time:
      <td><input name="timeString" readonly>
    <tr>
      <td>Equivalent UTC:
      <td><input name="timeStringUTC" readonly>
  </table>
</form>

显然,这是简化的,需要验证输入值,但显示逻辑。您可能还想让用户选择日期,这可以使用相同的逻辑。