
Mastering Time Handling in TypeScript with Moment.js
A practical guide to working with dates and times in TypeScript applications using the powerful Moment.js library, with real-world utility functions.

Pheak
Time handling is one of those deceptively complex areas of programming that can quickly become a source of frustration. Between time zones, formatting, calculations, and the inherent complexity of date objects, even seemingly simple operations can lead to unexpected bugs. This is where specialized libraries like Moment.js shine.
The Challenge with JavaScript's Native Date
JavaScript's built-in Date
object has numerous shortcomings that make complex time operations cumbersome:
- Limited formatting options
- No built-in localization
- Unintuitive API for calculations
- No time zone handling out of the box
These limitations explain why so many developers turn to external libraries for date handling. Among these, Moment.js has been a long-standing favorite—though newer alternatives like date-fns and Luxon are gaining popularity for modern projects.
Creating Utility Functions for Time Operations
When working with dates in a TypeScript application, I often create utility functions that encapsulate common operations. These functions improve code readability and ensure consistent date handling throughout the application.
Let's examine a practical example: a function that takes one or more dates and transfers the current time (hour, minute, second, millisecond) to each date.
import moment from 'moment'
import _ from 'lodash'
export default function wrapCurrentTime(dates: Date | Date[]): Date | Date[] {
// Check type of dates
let arrDates = _.isArray(dates) ? dates : [dates]
let newDates: Date[] = []
arrDates.forEach(date => {
const currentDate = moment()
let newDate = moment(date)
newDate.hour(currentDate.hour())
newDate.minute(currentDate.minute())
newDate.second(currentDate.second())
newDate.millisecond(currentDate.millisecond())
newDates.push(newDate.toDate())
})
return _.isArray(dates) ? newDates : newDates[0]
}
This function is incredibly useful when you need to preserve the date portion but update the time to the current moment—for example, when scheduling events for today but at a specific time.
Breaking Down the Function
Let's analyze what makes this function both elegant and versatile:
Flexible Input Handling
let arrDates = _.isArray(dates) ? dates : [dates]
Using Lodash's isArray
check, the function accepts either a single date or an array of dates. This flexibility means we can use the same function regardless of whether we're processing one or multiple dates.
Working with Moment Objects
const currentDate = moment()
let newDate = moment(date)
The function converts inputs to Moment.js objects, which provide a rich API for date manipulation. The current time is captured at the beginning of the function execution.
Precise Time Transfer
newDate.hour(currentDate.hour())
newDate.minute(currentDate.minute())
newDate.second(currentDate.second())
newDate.millisecond(currentDate.millisecond())
Each component of time is transferred individually. While this could be done with more concise methods like startOf('day')
combined with time addition, the explicit approach makes the function's intent crystal clear.
Preserving Return Type
return _.isArray(dates) ? newDates : newDates[0]
The function returns data in the same format it was received—if you pass in a single date, you get back a single date; if you pass an array, you get back an array. This consistency makes the function a drop-in replacement in various contexts.
Real-World Applications
This seemingly simple utility function has numerous practical applications:
Calendar Events
When a user selects a day from a calendar but needs the event to be scheduled at the current time:
const selectedDay = getSelectedDayFromCalendar() // Returns a Date
const eventTime = wrapCurrentTime(selectedDay)
scheduleEvent(eventTime)
Batch Processing with Current Timestamp
When processing multiple dated records that need to be updated with the current timestamp:
const datesToProcess = getDateRecordsFromDatabase()
const updatedDates = wrapCurrentTime(datesToProcess)
saveDatesToDatabase(updatedDates)
Date Range Generation
When creating a range of dates for the same time of day:
const dateRange = generateDateRange('2025-01-01', '2025-01-07') // Array of dates
const dateRangeWithCurrentTime = wrapCurrentTime(dateRange)
Performance Considerations
While Moment.js is powerful, it's worth noting that it's a relatively heavy library. For large-scale applications or those with strict performance requirements, consider:
- Using more lightweight alternatives like date-fns
- Implementing only the specific date functionality you need
- Using the browser's Intl API for formatting when appropriate
Conclusion
Effective time handling is critical in many applications, and having well-designed utility functions like wrapCurrentTime
can significantly simplify your codebase. The combination of TypeScript's type safety with Moment.js's powerful API creates a robust foundation for handling complex time operations.
Remember that while Moment.js has been the go-to library for years, the JavaScript ecosystem continues to evolve. For new projects, you might want to explore alternatives like date-fns (functional approach) or Luxon (modern successor to Moment.js with better immutability and tree-shaking support).
What are your favorite date handling patterns in TypeScript? Have you created your own utility functions for common operations? I'd love to hear about your experiences in the comments.