Sling Academy
Home/Node.js/How to Set Timezone in Mongoose

How to Set Timezone in Mongoose

Last updated: December 30, 2023

Overview

Setting the timezone correctly in Mongoose is crucial for many applications that require accurate date and time representation according to a specific locale. While JavaScript date objects are always created in the browser’s timezone, in Node.js, the default timezone is always UTC. Thus, when using Mongoose, which builds on top of MongoDB and runs in a Node.js environment, dates stored in the database are also by default in UTC. In this tutorial, we’ll journey through different techniques for handling timezones in Mongoose to ensure our applications consistently record and process dates and times accurately.

Setting the System Timezone

Before we deep dive into Mongoose-specific configurations, it’s essential to understand that the system environment can influence dates in our application. A natural way to define the desired timezone is by setting the system environment’s timezone. For a Node.js service running on a server, consider configuring the system to use the correct timezone:

"UTC"

This will adjust the base environment, thereby affecting date objects and operations at a process level. While straightforward, we recommend this approach for consistent timezone application throughout your application stack.

Schema Timezone Adjustments

const moment = require('moment-timezone');

const userSchema = new mongoose.Schema({
  name: String,
  localCreatedAt: {
    type: Date,
    default: () => moment().tz('Your_Timezone').toDate()
  }
});

This method relies on using moment-timezone as a helpful tool to tweak our schema definitions to record times relevant to our application’s actual location.

Query Timezone Compensation

Most modern applications store dates in UTC and convert them to the required timezone only when displaying to users. Here, we will look at converting the returned dates into local timezone during queries.

const getUserById = async (userId) => {
  const user = await User.findById(userId);
  user.localCreatedAt = moment(user.createdAt).tz('Your_Timezone').toDate();
  return user
};

We retrieve the UTC date from the database and convert it to our desired timezone using moment-timezone.

Virtuals for Timezone Conversion

Mongoose virtual attributes allow us to define properties that are not stored in the database but are calculated at runtime. We can use virtuals to facilitate timezone conversion without persisting additional data:

userSchema.virtual('localCreatedAt').get(function() {
  return moment(this.createdAt).tz('Your_Timezone').format();
});

The use of virtuals provides a seamless way for timezone management at the model level, abstracting away presentation logic from our database schemas.

Middleware for Timezone Handling

We can also employ Mongoose’s middleware hooks to intercept document saving and querying to accomplish our timezone objectives:

userSchema.pre('save', function(next) {
  this.createdAt = moment().tz('Your_Timezone').toDate();
  next();
});

userSchema.post('find', function(docs) {
  docs.forEach(doc => {
    doc.createdAt = moment(doc.createdAt).tz('Your_Timezone').format();
  });
});

This is a more intrusive method, but ensures that every document saved or fetched exhibits a consistent timezone attribute.

Aggregation Timezone Conversion

In cases where we need to perform aggregation operations that factor in time, Mongoose offers utilities within its aggregation framework:

const pipeline = [
  {
    $addFields: {
      localCreatedAt: {
        $toDate: {
          $add: [
            'OFFSET_IN_MILLISECONDS',
            '$createdAt'
          ]
        }
      }
    }
  }
];

User.aggregate(pipeline);

The use of MongoDB’s $addFields stage and arithmetic operations enable us to adjust dates according to offsets, which we can calculate based on the application’s timezone needs.

Conclusion

In summary, managing timezones in Mongoose allows for greater flexibility in presenting dates to users according to their locales, while maintaining a standardized form of UTC in the database. In this tutorial, we discussed multiple ways to manage timezones—from underlying system configurations to Mongoose schema adjustments, query hooks, virtuals, middleware handlers, and aggregation transformations. It’s imperative to choose the method that best aligns with your application’s architecture and user experience goals while ensuring timezone integrity throughout your data lifecycle. The power of timezone management in Mongoose opens the door for truly global applications with reliable date and time interactions.

Next Article: Mastering the Date schema type in Mongoose

Previous Article: How to set default values in Mongoose

Series: Mongoose.js Tutorials

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates