Dealing with MongoDB DateTime in ASP.NET Core

MongoDB is one of the popular NoSQL databases available today. You can use
MongoDB database in your ASP.NET Core applications using MongoDB.Driver NuGet
package. I discussed the basics of MongoDB including CRUD operations
here and
here.
Document databases such as MongoDB store data as JSON documents. Although JSON
supports basic data types such as string, number, and boolean JSON doesn't
support DateTime. So, date-time values are stored as string. In this article we
will discuss a few things that you need to take into account while storing
date-time values.
To work with the following code you can create a new ASP.NET Core web
application or a console application. For the sake of simplicity I am going to
use a .NET Core console application.
Once you create the application make sure to add the NuGet package for
MongoDB.Driver. This NuGet package allows you to connect with the MongoDB server
and perform the database operations.

Also, run the MongoDB server using mongod.exe before you run the application.
For example, you could run the server using the following command:
> mongod.exe --dbpath .\Data
Then create a POCO that maps to the JSON / BSON document you want to store in
the MongoDB database. Consider the following Employee class that I am going to
use:
public class Employee
{
[BsonId]
public ObjectId Id { get; set; }
[BsonElement]
public string Name { get; set; }
[BsonElement]
public DateTime HireDate { get; set; }
}
The Id property acts as the ObjectId of the document. Name and HireDate
properties are decorated with [BsonElement] attribute so they are serialized and
de-serialized as a part of the JSON document.
DateTime is stored in UTC by default
By default, MongoDB stores DateTime value in UTC format. That means whatever
value you assign to the HireDate property will be converted to its UTC value and
then stored in the database. Naturally, what you assign to HireDate and what you
retrieve after saving to database might be different values. Let's see this in
action. Consider the following code:
Employee emp = new Employee();
emp.Id = new ObjectId();
emp.Name = "Nancy Davolio";
emp.HireDate = DateTime.Now;
Console.WriteLine(emp.HireDate);
MongoClient client = new MongoClient();
IMongoDatabase db = client.GetDatabase("TestDb");
IMongoCollection<Employee> employees =
db.GetCollection<Employee>("Employees");
employees.InsertOne(emp);
Employee emp2 = employees.Find
(e => e.Id == emp.Id).SingleOrDefault();
Console.WriteLine(emp2.HireDate);
Console.ReadLine();
The code creates a new Employee object and assigns Id, Name, and HireDate
properties. Notice that the HireDate is assigned to the current date and time
value. The value assigned to the HireDate is outputted on the console for
checking.
Then the code creates a MongoClient object. A database named TestDb is
created along with Employees collection. The InsertOne() method of employees
IMongoCollection adds the supplied Employee document to the database.
The code then retrieves the same Employee from the database based on its
ObjectId and outputs the HireDate on the console.
A sample output from the application is as follows:
> 5/17/2019 8:43:20 AM
> 5/17/2019 3:13:20 AM
As you can see the two time values are different because the first value is
the local DateTime whereas the second value is UTC DateTime.
Obviously, this can lead to confusion in your application. Luckily there is
an easy way to handle the situation.
Storing local time
Suppose you don't want MongoDB to store UTC DateTime to the database. You
prefer to store the local DateTime as it is into the database. You can
accomplish this task as follows:
[BsonElement]
[BsonDateTimeOptions(Kind = DateTimeKind.Local)]
public DateTime HireDate { get; set; }
The HireDate property is now decorated with [BsonDateTimeOptions] attribute.
Moreover, this attribute sets the Kind property to DateTimeKind.Local. This
tells MongoDB driver to treat the property as a local DateTime value. So, while
saving the document UTC conversion won't happen and while retrieving the same
DateTime will be obtained.
After making the change run the application again to confirm the behavior.
> 5/17/2019 8:51:41 AM
> 5/17/2019 8:51:41 AM
As you can see, now both the values are same and they indicate client's local
DateTime.
Storing UTC explicitly
In the preceding example you indicated you choice of storing values as local
DateTime using the DateTimeKind.Local option. You can also store the values
explicitly in UTC by setting the Kind property to DateTimeKind.Utc.
[BsonElement]
[BsonDateTimeOptions(Kind = DateTimeKind.Utc)]
public DateTime HireDate { get; set; }
However, if you decide to do so the value assigned to HireDate must be a UTC
value. Consider the following code.
Employee emp = new Employee();
emp.Id = new ObjectId();
emp.Name = "Nancy Davolio";
emp.HireDate = DateTime.Now.ToUniversalTime();
Console.WriteLine(emp.HireDate);
The HireDate is now obtained by using the ToUniversalTime() method.
This time the sample output is:
> 5/17/2019 3:35:39 AM
> 5/17/2019 3:35:39 AM
As you can see, both the values are same but this time they are UTC values.
Storing only date
At times you want to store only the Date part of the DateTime. In that case
you can instruct MongoDB that you want to store only date as follows:
[BsonElement]
[BsonDateTimeOptions(DateOnly = true)]
public DateTime HireDate { get; set; }
The DateOnly property of [BsonDateTimeOptions] attribute is set to true
indicating that only date part is to be persisted. Also ensure that only date is
being assigned to HireDate.
Employee emp = new Employee();
emp.Id = new ObjectId();
emp.Name = "Nancy Davolio";
emp.HireDate = DateTime.Now.Date;
Console.WriteLine(emp.HireDate);
A sample run of the application produces this output.
> 5/17/2019 12:00:00 AM
> 5/17/2019 12:00:00 AM
As you can see, the time part is now 12:00:00 AM indicating that only date
part is considered.
That's it for now! Keep coding!!