[Solved] How to read and store datetime as is from javascript to mysql

I am building an application node.js where a user creates a record with a field named tour date and time. I am using daterangepicker plugin to show the date and time dropdown window. Once the user saves the record it is saved in the MySQL table as datetime field.

Then I am using fullcalendar to display all the tour dates for a given month-year.

But here is the problem. Lets say I select 28/11/2018 6:30 PM as the tour date and time. In the daterange picker it gets saved as

2018-11-28 18:30

$('input#tour_date').daterangepicker({
    singleDatePicker: true,
    showDropdowns: true,
    timePicker: true,
    timePickerIncrement: 30,
    locale: {
        format: 'DD/MM/YYYY hh:mm A'
    }
}, function (chosendate) {
    $('input[name="tour_date"]').val(moment(chosendate).format('YYYY-MM-DD hh:mm'));
    //the value for input becomes 2018-11-28 18:30
});

I have not set any timezone for daterangepicker or momentjs.
The datetime I get from the form (before saving to the database) is the same. i.e. it comes in as 2018-11-28 18:30.

However on saving to the database, it gets saved as

2018-11-28 01:00:00

It adds +06:30 (IST, Indian Standard Time value) to the incoming datetime field.

So when I open my calendar, the date is correct (28/11/2018) but the time is incorrect. The user saved the field expecting the time to be 6.30 PM but instead sees 01:00

I am saving the datetime as

var tourDate = new Date(req.body.tour_date).toISOString();

I am using Sequelize ORM and I have not given any specific timezone.

const sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASSWORD, {
    host: process.env.DB_HOST,
    port: 3306,
    dialect: 'mysql',
    pool: {
        max: 10,
        min: 0,
        acquire: 30000,
        idle: 10000
    },
    logging: false
});

What I want to do is no matter which timezone the user is present in. I want to save the given date and time as is in the database and retrieve it as is, to be shown in the calendar.

How do I achieve this?

Solution #1:

If you are storing date via sequelize, then it will store the date as UTC ,

So from the front end just pass the date in UTC , so it will get stored
and if you are using date time picker it will automatically convert the UTC into your timezone , just pass the UTC data to your plugin.

Just use UTC while passing and you are good to go.

Respondent: codeinprogress

Solution #2:

  1. If you use DATETIME data type in mysql, then value save as is
    independent on mysql time_zone system variable. See here and here.
  2. mysql return different values for some functions depending on time_zone system varible. For example:

    SET time_zone='+00:00'; 
    SELECT now(); //2018-11-30 17-52-00
    
    SET time_zone='+03:00'; 
    SELECT now(); //2018-11-30 20-52-00
    
  3. You can pass timezone option in sequelize to DB connetion. By default it
    ‘+00:00’. First of all, Sequelize use this value to set time_zone
    option on each connection (you can see it, if start Sequelize with
    DEBUG variable). Also Sequelize (or mysql2 package, i don’t know) use timezone option to convert results returned by mysql to js Date objects. So:

    const sequelize = new Sequelize('database', 'user', 'password', {timezone: "+00:00"});
    
    sequelize.query('SELECT now() AS now;', {type: sequelize.QueryTypes.SELECT})
    //2018-11-30T17:52:00.000Z
    
    sequelize.query('SELECT createdAt FROM users WHERE userId = 1;', {type: sequelize.QueryTypes.SELECT})
    //2017-09-05T13:43:00.000Z
    
    
    const sequelize = new Sequelize('database', 'user', 'password', {timezone: "+03:00"});
    
    sequelize.query('SELECT now() AS now;', {type: sequelize.QueryTypes.SELECT})
    //2018-11-30T17:52:00.000Z
    
    sequelize.query('SELECT createdAt FROM users WHERE userId = 1;', {type: sequelize.QueryTypes.SELECT})
    //2017-09-05T10:43:00.000Z 
    

Explain:

For now:

+-----------+---------------------+----------------------------+--------------------------+
| time_zone | mysql return        | sequelize read result as   | sequelize return         |
+-----------+---------------------+----------------------------+--------------------------+
|  +00:00   | 2018-11-30 17-52-00 | 2018-11-30 17-52-00 +00:00 | 2018-11-30T17:52:00.000Z |
+-----------+---------------------+----------------------------+--------------------------+
|  +03:00   | 2018-11-30 20-52-00 | 2018-11-30 20-52-00 +03:00 | 2018-11-30T17:52:00.000Z |
+-----------+---------------------+----------------------------+--------------------------+

For createdAt:

+-----------+---------------------+----------------------------+--------------------------+
| time_zone | mysql return        | sequelize read result as   | sequelize return         |
+-----------+---------------------+----------------------------+--------------------------+
|  +00:00   | 2017-09-05 13-43-00 | 2017-09-05 13-43-00 +00:00 | 2017-09-05T13:43:00.000Z |
+-----------+---------------------+----------------------------+--------------------------+
|  +03:00   | 2017-09-05 13-43-00 | 2017-09-05 13-43-00 +03:00 | 2017-09-05T10:43:00.000Z |
+-----------+---------------------+----------------------------+--------------------------+

So be carefully when set timezone option, when use DATETIME datatype. If you insert/select your data only with sequelize, then you don’t need to change timezone option.

For correct work with datetime in my work, I use next rules:

  • For transport datetime between client and server use uniquely determined format: UNIX, ISO 8601 (string like 2017-09-05T13:43:00.000Z);
  • All DATETIME values in Mysql DB stores with zero timezone (+00:00); So timezone option for Sequelize is ‘+00:00’;

Finally, browsers use time zone setting on your computer. Check the values at all steps and eliminate the uncertainties associated with incorrect interpretation of the time zone.

Respondent: Vivek Doshi

Solution #3:

Alright, after much confusion here is how this got solved. I had to convert the date at my client side to utc and then when it comes to my node.js server, I need to convert it to UTC again before saving it to database.

On client side I am setting the date in a hidden input field (which is what I am sending to server) using

$('input#tour_date').daterangepicker({
  singleDatePicker: true,
  showDropdowns: true,
  timePicker: true,
  timePickerIncrement: 30,
  locale: {
    format: 'DD/MM/YYYY hh:mm A'
  }
}, function (chosendate) {
    //this is the hidden input where the set date is being sent
    $('input[name="tour_date"]').val(moment(chosendate).format('YYYY-MM-DDTHH:mm:ss'));
});

So one server it comes in as

2018-12-31T10:30:00.000Z

Which then I have to process again using moment like this:

moment.utc(req.body.tour_date); //this is saved to db

When I read the record and display it to the user I reprocess the date as

moment.utc(act.tour_date).format('DD/MM/YYYY hh:mm A')

So the user sees 31/12/2018 10:30 AM in the datepicker

I also pass moment.utc(act.tour_date).format('YYYY-MM-DDTHH:mm:ss') back to the hidden input, in case the user updates the record

Thank you everyone who helped me figure this out. Appreciate your time and efforts.

Respondent: Faris

The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Leave a Reply

Your email address will not be published.