Part 1 of this series examined how handling date and time presents a slightly different challenge than other data types. Part 2 focused on design-time considerations, including schema, validation, and operation definitions. In Part 3, we will look at some of the implementation aspects, and I will use javascript as the language here.
Accepting date-time
If you are building an API, enforce a standard format. I generally use ISO 8601 for date, time, and timestamps.
The API client consumes the API by following the published API spec. During design/development, there might be an ask to support multiple formats. From my experience, supporting multiple formats for date and time at an API level sounds convenient, but it adds complexity. It’s better to follow a standard and then stick to it.
Support for multiple formats would still be required. We should decouple it from the API layer as much as possible. Push that on to the consumer. The API consumer might be a front-end application where the user can be guided to use a date-time picker while inputting the date, or the date can be displayed in a format that the user can understand better. The consumer could also be another application. In this case, a standard like ISO 8601 is more than sufficient. It could be possible that the user is a real human being consuming the API using an API client. In that case, it’s safe to assume that the user has sufficient technical knowledge to understand the ISO format. 😀
One way to support additional formats is to piggyback on the language that you have used for building the APIs. Our APIs are built on Nodejs, and when asked to support additional formats, we tell them that as long as it is javascript-parseable (Date.parse()
) we will accept it.
Handling date-time and timezones
Here’s a sample code that I would be using,
function printDate(inputData, tzInfo) {
let parsedDate = new Date(inputData);
console.log(`Input data : ${inputData}`);
console.log(`Input timezone : ${tzInfo}`);
console.log(`Date (String) : ${parsedDate}`);
console.log(`Date (ISO) : ${parsedDate.toISOString()}`);
console.log(`Date (Locale) : ${parsedDate.toLocaleString('en-US', { timeZone: tzInfo })}`);
console.log(`Date (Locale/Zulu) : ${parsedDate.toLocaleString('en-US', { timeZone: 'Zulu' })}`);
console.log(`Date (ms since Epoch) : ${Date.parse(inputData)}`);
}
If we call this function – printDate("2023-01-01 12:00:00 AM", "Asia/Kolkata");
, -it gives the output
Input data : 2023-01-01 12:00:00 AM
Input timezone : Asia/Kolkata
Date (String) : Sun Jan 01 2023 00:00:00 GMT+0530 (India Standard Time)
Date (ISO) : 2022-12-31T18:30:00.000Z
Date (Locale) : 1/1/2023, 12:00:00 AM
Date (Locale/Zulu) : 12/31/2022, 6:30:00 PM
Date (ms since Epoch) : 1672511400000
printDate("2023-01-01 12:00:00 AM", "Asia/Kolkata");
12AM IST (+5:30)
is 6:30PM
the previous day at UTC. Hence 2023-01-01 12:00:00 AM
is 2022-12-31T18:30:00.000Z
.
Let’s try a different input, printDate("2023-01-01 00:00:00 AM", "Asia/Tokyo");
, and the output is,
Input data : 2023-01-01 00:00:00 AM
Input timezone : Asia/Tokyo
Date (String) : Sun Jan 01 2023 00:00:00 GMT+0530 (India Standard Time)
Date (ISO) : 2022-12-31T18:30:00.000Z
Date (Locale) : 1/1/2023, 3:30:00 AM
Date (Locale/Zulu) : 12/31/2022, 6:30:00 PM
Date (ms since Epoch) : 1672511400000
printDate("2023-01-01 00:00:00 AM", "Asia/Tokyo");
It still looks the same. So what happened? This is where the timezone of the machine running the code starts to matter. Simply put, the machine’s timezone affected the output. This is something that gets overlooked quite often. To understand this better, let’s run the same code, but this time we will run it with the timezone set to Asia/Tokyo
process.env.TZ = "Asia/Tokyo";
printDate("2023-01-01 00:00:00 AM", "Asia/Tokyo");
Input data : 2023-01-01 00:00:00 AM
Input timezone : Asia/Tokyo
Date (String) : Sun Jan 01 2023 00:00:00 GMT+0900 (Japan Standard Time)
Date (ISO) : 2022-12-31T15:00:00.000Z
Date (Locale) : 1/1/2023, 12:00:00 AM
Date (Locale/Zulu) : 12/31/2022, 3:00:00 PM
Date (ms since Epoch) : 1672498800000
Notice how the ISO date, Epoch, and all the values have changed.
Most of the time, this influence that the system’s timezone has on date-time calculations goes unnoticed. Servers are provisioned on the cloud, which by default runs the servers in UTC. We seldom change the timezone. To see this in action, let’s set the timezone to UTC
and check the output.
process.env.TZ = "Zulu";
printDate("2023-01-01 00:00:00 AM", "Asia/Tokyo");
Input data : 2023-01-01 00:00:00 AM
Input timezone : Asia/Tokyo
Date (String) : Sun Jan 01 2023 00:00:00 GMT+0000 (Coordinated Universal Time)
Date (ISO) : 2023-01-01T00:00:00.000Z
Date (Locale) : 1/1/2023, 9:00:00 AM
Date (Locale/Zulu) : 1/1/2023, 12:00:00 AM
Date (ms since Epoch) : 1672531200000
ℹ️ If your application handles date and time, ensure the servers are set at the same timezone.
The situation is not that different on the browser too. When you convert the raw data to ISO format, it considers the timezone the browser is running. If your application is sensitive to time zones, it makes sense to capture the timezone information of the browser.
Date manipulation
If date and time manipulation must be done, using a good date-time library is much better than writing the whole functionality yourself.
Javascript has good support for date-time manipulations.
let parsedDate = new Date("2023-02-28 12:00:00 AM");
console.log(parsedDate.toString());
// Tue Feb 28 2023 00:00:00 GMT+0530 (India Standard Time)
parsedDate.setDate(parsedDate.getDate() + 1);
console.log(parsedDate.toString());
// Wed Mar 01 2023 00:00:00 GMT+0530 (India Standard Time)
Most languages have either inbuilt support or good libraries that support date-time manipulations. Give those a try and build a custom one only if none of them fits your use case.
Storing only Date / only Time
Most SQL DBs support storing only date or only time. https://www.postgresql.org/docs/current/datatype-datetime.html.
But document DBs like MongoDB don’t have a Date or Time data type. They deal with date objects which also have a time component. I recommend using the ISO format and ignoring the time or date part. This would give you flexibility in terms of querying. That would lead to 1st Jan 2023
to be stored as 2023-01-01T00:00:00.000Z
and 10AM
to be 01-01-01T10:00:00.000Z
⛳ Here are some things for you to explore.
Take the code I used and generate epoch values for the following dates.
1970-01-01 00:00:00 1900-01-01 00:00:00 10-01-01 00:00:00
Did you notice something? 😀
Managing date and time data is a crucial aspect of working with data. It is essential to understand that date and time data cannot be treated like other data types due to their unique characteristics. When working with dates and times, it is crucial to consider several factors, such as the purpose of the data, the actions that can be performed on it, and the associated metadata information.
Furthermore, the design of the schema must be carefully planned, keeping in mind the requirements of the system and the user. The schema must capture the necessary date and time information in a standardized and consistent format to facilitate easy processing and retrieval of data. Additionally, the schema must accommodate various operations that can be performed on the data, such as querying, updating, and exporting.
In conclusion, managing date and time data requires careful consideration and planning to ensure the data’s accuracy, consistency, and completeness. By understanding the unique characteristics of date and time data and implementing best practices in data design, we can efficiently manage this critical aspect of data management.
🤖 ChatGPT wrote the above paragraph. I didn’t know how to conclude, so I took some help. 🤷🏽♂️
./J
- Part 1 – The Date
- Part 2 – The Second Date