How to Set Timezone in Mongoose

Updated: December 30, 2023 By: Guest Contributor Post a comment

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.