samurai_code
samurai_code

Reputation: 67

How can I set correct timezone for a date field in Mongoose?

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

Upvotes: 3

Views: 5854

Answers (2)

May'Habit
May'Habit

Reputation: 1372

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.

Upvotes: 0

ambianBeing
ambianBeing

Reputation: 3529

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()

Upvotes: 5

Related Questions