3

I'm using moment for generating time and date:

const moment = require('moment-timezone');
const emailModel = require('./api/models/emails');

sentTime=moment().tz('America/Los_Angeles').format();
console.log(sentTime);    //console log  shows correct time
emailModel.findOneAndUpdate({ _id: emailInfo._id }, {sentTime: sentTime }, { upsert: true },function (err, doc) {
  if (err)
    console.log(err);
});

And this is Schema that I'm using mongoose :

const mongoose = require('mongoose');

const Schema = mongoose.Schema;
const EmailSchema = new Schema({
   .
   .
   .
    sentTime: {
        type: Date,
        trim: true
    }
   .
   .
   .
});

Problem is: Console log shows correct time 2020-01-07T12:23:00-08:00 BUT mongoose saved incorrect timezone in DB : 2020-01-07T20:23:01.000+00:00

ambianBeing
  • 3,449
  • 2
  • 14
  • 25
samurai_code
  • 57
  • 2
  • 9
  • 1
    It's because string is getting converted into Date which is usually in UTC format. What is the specific reason for opting region `America/Los_Angeles` ? If it's your local time & wanted to insert the local time, there is a work around but if you want region specific let's say one request has `America/Los_Angeles` the other has `America/Chicago` then it might be a bit difficult. – whoami - fakeFaceTrueSoul Jan 07 '20 at 22:28

2 Answers2

5

Currently the default behavior of Mongodb is to: (From the docs)

MongoDB stores times in UTC by default, and will convert any local time representations into this form.

As a solution (and rightly so) what they recommend is:

Applications that must operate or report on some unmodified local time value may store the time zone alongside the UTC timestamp, and compute the original local time in their application logic.

Update: Since you are already using moment-timezone a simple way I would go about this is:

Change the EmailSchema to have a timezone field and create a Mongoose virtual field on that schema to get adjusted time.

const schemaOpts = { toJSON: { virtuals: true } };
const EmailSchema = new Schema(
  {
    sentTime: {
      type: Date,
      trim: true
    },
    timeZone: {
      type: String
    }
  },
  schemaOpts
);

EmailSchema.virtual("adjustedTime").get(function() {
  return moment.tz(this.sentTime, this.timeZone).format();
});

//fetching data
const result = await EmailSchema.findOne({}).exec();
console.info("result::", result.toJSON());

//note that if using .lean() for performance which has a caveat on using .toJSON()
ambianBeing
  • 3,449
  • 2
  • 14
  • 25
0

trick for this case is before save, you need to add time with date. Ex: 2021/01/02 ==> 2021/01/02 15:00:00, ofcouse hour is always equal or greater than 04:00:00. Becase without time, date will be 00:00:00 and mongo will convert it to default timezone and substract hour with 4.

May'Habit
  • 1,334
  • 12
  • 18