I am using Mongoose and Luxon to display a date, selected by the user from a form. But the date is console.logging one date, but displaying on the page as the day before.
This is my model:
const mongoose = require("mongoose");
const { DateTime, Settings } = require("luxon");
// Configure time zone
console.log(Settings);
const Schema = mongoose.Schema;
let AccomplishmentSchema = new Schema({
dateInput: {
type: Date,
required: true,
},
textInput: {
type: String,
required: true,
},
});
AccomplishmentSchema.virtual("dateInput_formatted").get(function () {
return DateTime.fromJSDate(this.dateInput).toLocaleString(DateTime.DATE_FULL); // format 'YYYY-MM-DD
});
module.exports = mongoose.model("Accomplishment", AccomplishmentSchema);
And this is my console log vs what is showing up on the page
dateInput: 2023-01-01T00:00:00.000Z,
textInput: 'etst',
December 31, 2022
etst
I can only assume this has to do with some kind of time conversion, but I’ve tried changing the time zone, and the settings, although I could’ve read the docs wrong. I cannot find a way to fix this issue.
2
Answers
When working with JS
Date
, the most important thing to understand is thatDate
doesn’t store or know about a time zone. It simply stores the number of milliseconds since midnight on Jan 1, 1970 (aka UNIX epoch) in the UTC time zone. Then, when you callDate
methods, the results are calculated for the current user’s time zone (for methods likegetMinutes()
) or UTC (for methods likegetUTCMinutes()
). But the underlying data inside theDate
is just a timezone-less number of milliseconds.With that in mind, let’s look at a simple example:
new Date(0)
, which is equivalent tonew Date('1970-01-01T00:00Z')
.If your computer’s time zone set to the
Europe/Paris
time zone, then when you callnew Date(0).toLocaleDateString('en-US')
then you’ll get a result of'1/1/1970'
. But if you change your computer’s time zone toAmerica/Los_Angeles
and run the same code, you’ll get a result of'12/31/1969'
.This happens because the
Date
‘s stored value corresponds to midnight on Jan 1, 1970 in the UTC time zone. In Paris that instant was 1:00AM on Jan 1, 1970, while in California it was 4:00PM on December 31, 1969. The same exactDate
will print a different date depending on the time zone that’s active at the time that date is printed.Where this becomes particularly problematic is in cases where you’re trying to express a date without a time. For example, assume you store a
Date
value of2023-01-01T00:00:00.000Z
in MongoDB.When you display that
Date
in a date picker in a browser in California, the date shown will be Dec 31, 2022, because California is 8 hours ahead of UTC.One way to solve this problem is to tell
Date
that the date you’re using is a UTC date. Like this:Note that this all will get a lot easier in a year or so when the new JavaScript built-in date/time API, called Temporal starts shipping in browsers and Node.js. With Temporal, these kinds of problems are much easier because there’s a dedicated API,
Temporal.PlainDate
for dealing with date-only values.Luxon is working as intended and the display is correct. What is wrong is the data in your MongoDB.
Most libraries consider current time zone when you parse a date. I live in Switzerland.
However, the native JavaScript
new Date()
constructor does not!Maybe this behavior depends on your environment and scripting engine, I don’t know.
You should also use Luxon when you parse the input data – don’t forget to use
.toJSDate()
to convert the DateTime object back to Javascript nativeDate
object.Luxon uses the system time zone by default. You can change it:
If you don’t care about the time, you can also use startOf(‘day’)