Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NodeJS: Why is there a two hour difference in new Date()?

I am doing a

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

It outputs

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

But the current time is 10:07 not 08:07.

The actual problem is that when I save a model to the db, it somehow gets converted to UTC which is not what I want. Its like order.delivery_date = 2018-08-06 10:00:00; order.save(). when I look in the db, it says 08:00:00. How do I prevent this from happening?

I am using Loopback 3 and MySQL.

like image 961
apfz Avatar asked Sep 02 '18 08:09

apfz


2 Answers

It outputs

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

But the current time is 10:07 not 08:07.

The Z on the string indicates that the time is in UTC, not local time. That's just the string output by Node.js's console when you pass it a string (it's from toUTCString). JavaScript Date objects work in local time, but also have features to access UTC time instead (getUTCHours, getUTCMinutes, etc.); toUTCString is one of them.

You can use the various local time functions on the Date object (getHours, getMinutes, etc.) and you'll get local time information from it. (For instance, toString will probably give you a local time string.)

like image 120
T.J. Crowder Avatar answered Oct 19 '22 00:10

T.J. Crowder


I don't have the complete picture of your setup, but yes, loopback does convert to UTC from local time when saving dates. If you look in the mysql connector, you'll find the following function that builds up the datetime string from UTC values of the given date:

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;
  }
}

It should, however, restore the date to local time on load because it initializes the javascript Date object from the stored string, which will convert to local time:

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

Your best option is probably to use operation hooks and manipulate the data as it flows in/out of your model. For example, you could format the date however you want as the data gets loaded from the data store:

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

    next();
  });

You can also approach this from the other direction and manipulate the data that's being persisted. You can't really prevent loopback from storing the date as UTC, but you could add or remove the timezone offset so once it gets stripped it by loopback connector, it will persist a string with your local time (VERY hacky, I wouldn't recommend it). Example:

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();
  });
like image 38
Unglückspilz Avatar answered Oct 19 '22 00:10

Unglückspilz