NodeJS:新的Date()为什么有两个小时的差异?

时间:2018-09-02 08:20:10

标签: javascript node.js date loopbackjs utc

我正在做

console.log(process.env.TZ);
console.log(new Date());

它输出

Europe/Amsterdam
2018-09-02T08:07:03.842Z

但是当前时间是10:07而不是08:07。

实际的问题是,当我将模型保存到数据库时,它会以某种方式转换为UTC,这不是我想要的。就像order.delivery_date = 2018-08-06 10:00:00; order.save()。当我查看数据库时,它说08:00:00。如何防止这种情况发生?

我正在使用Loopback 3和MySQL。

3 个答案:

答案 0 :(得分:18)

  

它输出

Europe/Amsterdam
2018-09-02T08:07:03.842Z
     

但是当前时间是10:07而不是08:07。

字符串上的Z表示时间是UTC,而不是本地时间。当您将字符串传递给字符串(来自toUTCString时),这只是Node.js控制台输出的字符串。 JavaScript Date对象在本地时间工作,但也具有访问UTC时间的功能(getUTCHoursgetUTCMinutes等); toUTCString是其中之一。

您可以在Date对象(getHoursgetMinutes等)上使用各种本地时间功能,并从中获取本地时间信息。 (例如,toString可能会给您一个本地时间字符串。)

答案 1 :(得分:4)

我没有您设置的完整图片,但是是的,保存日期时,环回确实会从本地时间转换为UTC。如果您查看mysql连接器,则会发现以下函数,该函数从给定日期的UTC值构建datetime字符串:

function dateToMysql(val) {
  return val.getUTCFullYear() + '-' +
    fillZeros(val.getUTCMonth() + 1) + '-' +
    fillZeros(val.getUTCDate()) + ' ' +
    fillZeros(val.getUTCHours()) + ':' +
    fillZeros(val.getUTCMinutes()) + ':' +
    fillZeros(val.getUTCSeconds());

  function fillZeros(v) {
    return v < 10 ? '0' + v : v;
  }
}

但是,它应该将日期恢复为加载时的本地时间,因为它会从存储的字符串中初始化javascript Date对象,该对象将转换为本地时间:

val = new Date(val.toString().replace(/GMT.*$/, 'GMT'));

您最好的选择可能是使用operation hooks并在数据流入/流出模型时对其进行操作。例如,您可以根据需要设置日期的格式,例如从数据存储中加载数据的时间:

Order.observe("loaded", (ctx, next) => {
    if (ctx.data) {
      ctx.data.delivery_date_formatted = tzFormat(ctx.data.delivery_date);
    }

    next();
  });

您还可以从另一个方向进行处理,并处理要保留的数据。您无法真正阻止回送将日期存储为UTC,但是您可以添加或删除时区偏移,因此一旦被回送连接器剥离了时区偏移量,它将以您的本地时间保存字符串(很黑,我不会推荐)。示例:

Order.observe("before save", (ctx, next) => {
    if (ctx.instance) {
      ctx.instance.delivery_date = new Date(
        Date.UTC(
          ctx.instance.delivery_date.getFullYear(),
          ctx.instance.delivery_date.getMonth(),
          ctx.instance.delivery_date.getDate(),
          ctx.instance.delivery_date.getHours(),
          ctx.instance.delivery_date.getMinutes(),
          ctx.instance.delivery_date.getSeconds()
        )
      );
    }

    next();
  });

答案 2 :(得分:0)

回答标题问题: new Date()将返回UTC时间值,该值在字符串末尾具有Z时区指示符和时区值(在您的情况下为2)。

回答有关数据库save()的问题: 这取决于您的数据访问层和数据列类型。

可能有两种主要方法:

  • 保存UTC并显示本地时间(当您拥有2个以上时区的用户时)

因此您的save()可以正确地使用该方法,您应该只添加一个本地时间转换器(通常最好的方法是将其添加到前端)

  • 按原样保存本地时间的值(不建议使用,但可能有用)

因此,您应该在写/读时建立转换器,或者更改列的类型,因此它不应该使用UTC格式(一种简单的方法,但是不巧的方法是将其存储为字符串值),例如

如果您选择转换器的方式,我建议您使用moment.js(用于前端或后端)。当您需要进行任何时间操作时,它可以节省时间,但可能会增加开销。

您也可以手动进行制作(例如,以减小捆绑包尺寸),也可以使用this答案中的方法:

const options = {
    timeZone: "America/New_York",
    year: 'numeric', month: 'numeric', day: 'numeric',
    hour: 'numeric', minute: 'numeric', second: 'numeric'
};

const formatter = new Intl.DateTimeFormat([], options);

const UTCTime = "2017-09-03T02:00:00Z";
const localTime = formatter.format(new Date(UTCTime));
const currentTime = formatter.format(new Date()); 
console.log(currentTime, localTime);