Working With Dates

Sponsor #native_company# — #native_desc#

Here’s how you declare a path of type Date with a Mongoose schema:

  1. const mongoose = require('mongoose');
  2. const userSchema = new mongoose.Schema({
  3. name: String,
  4. // `lastActiveAt` is a date
  5. lastActiveAt: Date
  6. });
  7. const User = mongoose.model('User', userSchema);

When you create a user document, Mongoose will cast the value to a native JavaScript date using the Date() constructor.

  1. const user = new User({
  2. name: 'Jean-Luc Picard',
  3. lastActiveAt: '2002-12-09'
  4. });
  5. user.lastActiveAt instanceof Date; // true

An invalid date will lead to a CastError when you validate the document.

  1. const user = new User({
  2. name: 'Jean-Luc Picard',
  3. lastActiveAt: 'not a date'
  4. });
  5. user.lastActiveAt instanceof Date; // false
  6. user.validateSync().errors['lastActiveAt']; // CastError

Validators

Dates have two built-in validators: min and max. These validators will report a ValidatorError if the given date is strictly less than min or strictly greater than max.

  1. const episodeSchema = new mongoose.Schema({
  2. title: String,
  3. airedAt: {
  4. type: Date,
  5. // The dates of the first and last episodes of
  6. // Star Trek: The Next Generation
  7. min: '1987-09-28',
  8. max: '1994-05-23'
  9. }
  10. });
  11. const Episode = mongoose.model('Episode', episodeSchema);
  12. const ok = new Episode({
  13. title: 'Encounter at Farpoint',
  14. airedAt: '1987-09-28'
  15. });
  16. ok.validateSync(); // No error
  17. const bad = new Episode({
  18. title: 'What You Leave Behind',
  19. airedAt: '1999-06-02'
  20. });
  21. bad.airedAt; // "1999-06-02T00:00:00.000Z"
  22. // Path `airedAt` (Tue Jun 01 1999 20:00:00 GMT-0400 (EDT)) is after
  23. // maximum allowed value (Sun May 22 1994 20:00:00 GMT-0400 (EDT)).
  24. bad.validateSync();

Querying

MongoDB supports querying by date ranges and sorting by dates. Here’s some examples of querying by dates, date ranges, and sorting by date:

  1. // Find episodes that aired on this exact date
  2. return Episode.find({ airedAt: new Date('1987-10-26') }).
  3. then(episodes => {
  4. episodes[0].title; // "Where No One Has Gone Before"
  5. // Find episodes within a range of dates, sorted by date ascending
  6. return Episode.
  7. find({ airedAt: { $gte: '1987-10-19', $lte: '1987-10-26' } }).
  8. sort({ airedAt: 1 });
  9. }).
  10. then(episodes => {
  11. episodes[0].title; // "The Last Outpost"
  12. episodes[1].title; // "Where No One Has Gone Before"
  13. });

Casting Edge Cases

Date casting has a couple small cases where it differs from JavaScript’s native date parsing. First, Mongoose looks for a valueOf() function on the given object, and calls valueOf() before casting the date. This means Mongoose can cast moment objects to dates automatically.

  1. const moment = require('moment');
  2. const user = new User({
  3. name: 'Jean-Luc Picard',
  4. lastActiveAt: moment.utc('2002-12-09')
  5. });
  6. user.lastActiveAt; // "2002-12-09T00:00:00.000Z"

By default, if you pass a numeric string to the Date constructor, JavaScript will attempt to convert it to a year.

  1. new Date(1552261496289); // "2019-03-10T23:44:56.289Z"
  2. new Date('1552261496289'); // "Invalid Date"
  3. new Date('2010'); // 2010-01-01T00:00:00.000Z

Mongoose converts numeric strings that contain numbers outside the range of representable dates in JavaScript and converts them to numbers before passing them to the date constructor.

  1. [require: Date Tutorial.*Example 1.4.3]

Timezones

MongoDB stores dates as 64-bit integers, which means that Mongoose does not store timezone information by default. When you call Date#toString(), the JavaScript runtime will use your OS’ timezone.