how to change date timezone in mongoose? - node.js

In model schema,
Using
updated: {
type: Date,
default: Date.now
In server.js
put(function(req, res) {
var query = {name: req.params.name};
// use our bear model to find the bear we want
Domain.find(query, function(err, domains) {
if (err)
res.send(err);
var domain = domains[0];
domain.password = req.body.password; // update the bears info
domain.updated = new Date();
// save the bear
domain.save(function(err, data) {
if (err)
res.send(err);
res.json({ status: 'success', message: 'domain updated!' }, data);
});
});
});
However,
In db side it shows,
"updated": "2016-02-27T16:20:42.941Z"
But, my timezone is UTC+02.00
So it should be like 18:20:42
What I'm doing wrong?

I'm using moment-timezone
npm install moment-timezone
const moment = require('moment-timezone');
const dateThailand = moment.tz(Date.now(), "Asia/Bangkok");
console.log(dateThailand); // "2018-08-20T16:35:14.033+07:00"
*** Asia/Bangkok +07:00
Schema in the mongoose.
const categorySchema = new Schema(
{
_id: {type: mongoose.Schema.Types.ObjectId, auto: true},
c_name: String,
created_by: String,
created_date: {type: Date, default: dateThailand},
updated_by: String,
updated_date: {type: Date, default: dateThailand}
}, {_id: false}
);
See up that created_date, updated_date: {type: Date, default: dateThailand }
Read more: http://momentjs.com/timezone/docs/
*If you using Robo 3T tool.
You can set "Display Dates In..."
Options > Display Dates In... > Local Timezone
:) Work for me.

The timestamps are timezone agnostic, stored as a unix timestamp. This timestamp will work across timezones, and node interprets it using current timezone of the server. The date you've shown is correctly stored. As soon as you'll retrieve it, if your server's timezone is UTC+2, it will show you correct time.

There is nothing wrong in your code. MongoDb saves date in UTC format no matter in whichever timezone you try to insert your date.
If you log domain.updated before saving in DB, result will be UTC+2 (your local time)
If you see updated column in DB, result will be in UTC
If you fetch updated column value from DB, then again result will be in UTC+2 (your local time)

I changed this,
var utc = new Date();
utc.setHours( utc.getHours() + 2);
domain.updated = utc;
Now it works.

You can create a Date Object from a specific UTC time:
new Date(Date.UTC(year, month, day, hour, minute, second))

Remember that no matter what you use to set time in mongoose schema, mongoose will always use UTC time, hence you need to dynamically allocate the UTC timestamp inside the Schema. Here it goes :-
var current = new Date();
const timeStamp = new Date(Date.UTC(current.getFullYear(),
current.getMonth(),current.getDate(),current.getHours(),
current.getMinutes(),current.getSeconds(), current.getMilliseconds()));
//Here goes your schema
const auditSchema = mongoose.Schema({
dateTime : { type: Date, default : timeStamp }
})

Using moment.js it is as easy as:
var moment = require('moment');
var utcDate = moment.utc().toDate();
Enjoy!

Related

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

How to update MongoDB createdAt date

I am trying to update the automatically added createdAt date on a record to right now.
Here the code I am using:
Document.findOneAndUpdate({_id: docId}, {createdAt: new Date()}, function(err, updated) {});
It works on my dev environment, but not the server. It does not return an error, but does not update the record, just returns the unchanged record.
I tried formatting it with new Date().toISOnew Date().toISOString() or .toGMTString() but both still only work on the dev environment. Both have node 6.10, but the server has mongo 3.4.4 and the dev has mongo 3.2.10.
If I add another field to be updated (second arugment), that field gets updated fine, but createdAt remains unchanged.
Automatic createdAt and updatedAt fields are populated by mongoose using the timestamps option as
const schema = new Schema({
// Your schema...
}, {
timestamps: { createdAt: true, updatedAt: false }
})
If you take a look at the source code you'll see that createdAt is excluded from updates. It's fairly easy though to modify your schema accordingly.
const schema = mongoose.Schema({
name: String,
createdAt: { type: Date, default: Date.now }
});
const Test = mongoose.model('test', schema);
const john = await Test.create({name: 'John Doe'});
console.log(john);
const updatedJohn = await Test.findOneAndUpdate({name: 'John Doe'}, { createdAt: Date.now() });
console.log(updatedJohn);
I do not know if it works for update, but for create, I first make sure have the createdAt field abled in my DB and then set the createdAt field like this:
{createdAt: moment().toISOString()}
because createdAt and updatedAt are ISO strings.
Edit: Just like Nigel mentioned, I do use moment library but new Date().toISOString() gives you the same result.

Sequelize compare with current timestamp

This is my code right now:
const Grace = sequelize.define('grace', {
userId: Sequelize.TEXT,
tribeName: Sequelize.TEXT,
server: Sequelize.TEXT,
hours: Sequelize.INTEGER,
date: Sequelize.DATE,
datef: Sequelize.DATE,
});
As you can see datef is stores as a date. datef is a future date. Example: current time + 36h
else if (command === 'showdb'){
var now = Date.now();
const gracep = await Grace.findAll({
where: {
datef: {
$gt: now,
},
},
});
}
What I want to do is to have it fetch the results in the db, where datef is greather than current timestamp.
The thing is datef is stored as: 2018-06-07 05:11:04.221 +00:00
And the var now is: 1528330290003
So I'm pretty sure that's the reason why it's not working, as it's outputing [], when it shouldn't.
Not sure what to do.
I've used date comparisons in Sequelize for WHERE clause when I want to compare something against the current date.
In my case I converted the current timestamp (from Date.now()) to an ISO string like so:
const now = (new Date()).toISOString();
I didn't have any problems when calling using an [Op.gte] or [Op.lte] operator to compare against the stored dates.
date.now() returns the number of milliseconds since midnight 01 January 1970 UTC. It is the same as new Date().valueOf()
here is what you can do
where : { datef : { [Op.gt]: new Date() } },
Sequelize documentation

Mongoose Date.now time is not accurate

I've been tearing my hair out for the past 2 hours, At first I thought Moment.js is the culprit for not returning a correct time, but it was mongoose Date.now that has been doing some evil stuff.
Here's the code
const moment = require('moment');
const mongoose = require('mongoose');
const item = new mongoose.Schema({
time: { type: Date, default: Date.now },
time2: { type: Date }
});
As you can see I have two fields, one is for the default date from mongoose and the other one is just a field for storing date.
item.pre('save', function() {
console.log(moment()); // Showing a correct date and time
console.log(this.time); // Showing a correct date but false time
this.time2 = moment(); // When it is saved to the database, it will show a correct date but false time
});
The result is
moment("2017-01-09T19:42:48.896") // the first console.log. This is correct, the time is correct
2017-01-09T11:42:48.884Z // Second console.log. The date is correct but the time is FALSE
I thought If I do this everything will be solved
const item = new mongoose.Schema({
time: { type: Date, default: moment() },
time2: { type: Date, default: Date.now }
});
But you know what is the console.log for the first field which is time?
2017-01-09T11:42:48.884Z // it is this time which is WRONG TIME
My guess would be that mongoose data type which is Date has an inaccurate timezone check.
Any help would be appreciated.
You are comparing two different things. moment() gives time in local time zone and Date.now is time in UTC. The only reason mongoose has that way is because mongo db saves it that way. No fix is required here.
Just convert the fetched mongoose date back to local time zone using moment library.

How do I update a property with the current date in a Mongoose schema on every save?

In my database collections, I want to update a 'lastChanged' field every time the record is updated with the current datetime. I want it to be in the same format as mongoose's default date like:
ISODate("2011-10-06T14: 01: 31.106Z")
Any words of wisdom?
If you just want an ISO String use:
new Date().toISOString()
One way of accomplishing this is to use Mongoose Middleware and update the field pre-save.
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
//schema
var SomethingSchema = new Schema({
text: {type: String},
createdAt: {type: Date, default: Date.now},
updatedAt: {type: Date, default: Date.now}
});
//middle ware in serial
SomethingSchema.pre('save', function preSave(next){
var something = this;
something.updatedAt(Date.now());
next();
});
It seems, however, that the middleware is not always invoked:
Notes on findAndUpdate()
pre and post are not called for update operations executed directly on the database, including Model.update,.findByIdAndUpdate,.findOneAndUpdate, .findOneAndRemove,and .findByIdAndRemove.order to utilize pre or post middleware, you should find() the document, and call the init, validate, save, or remove functions on the document. See explanation.
Update: See this question "add created_at and updated_at fields to mongoose schemas"
In a few days Mongo is going to announce new 2.6 version (currently you can download experimental 2.5.x version). Among many other features you can use $currentDate which is going to do exactly the thing you want:
db.users.update(
<criteria>,
{
$currentDate: { yourField: true},
}
)
The middleware function is a good approach, however, it should be
SomethingSchema.pre('save', function preSave(next){
var something = this;
something.updatedAt = Date.now();
next();
});
Since something.updateAt is not a function.
I added updated: new Date to fix a similar problem. Here is how I used it.
update: (req, res) => {
let userId = req.params.id;
let userParams = {
name: {
first: req.body.first,
last: req.body.last
},
email: req.body.email,
password: req.body.password,
updated: new Date
};
db.User.findOneAndUpdate(userId, { $set: userParams })
.then(upUser => res.json(`Profile Updated for: ${upUser.fullName}`))
.catch(err => res.status(422).json(err));
}

Resources