Working with dates is an unavoidable part of most web applications. Thankfully JavaScript provides the built-in Date
object for creating and manipulating dates. However, dealing with oddities like timezone shifts and daylight saving time can trip up even experienced developers.
In this comprehensive guide, you‘ll learn foolproof techniques for adding days to dates in JavaScript. By following best practices and avoiding common pitfalls, you can confidently write reliable date handling code.
Here‘s what we‘ll cover:
- Date Concepts: Timestamps, Timezones & DST
- Using setDate()/getDate()
- Adding Days with Milliseconds
- Building Reusable Date Utilities
- Native JavaScript Dates vs Libraries
- Visual Explanation of Dates & Offsets
- Recap of Best Practices
Let‘s dive in and level up your date manipulation skills!
Date Concepts: Timestamps, Timezones & DST
To understand what‘s happening when adding days to dates, we first need to review some key date-related concepts.
Millisecond Timestamp
Computers store dates and times as a numeric timestamp – the number of milliseconds that have elapsed since the "Unix Epoch" (January 1st, 1970 at 00:00:00 GMT).
For example, the timestamp value 1674329625873
refers to this specific moment in time.
We can convert a timestamp to a human-readable date using new Date(milliseconds)
:
const now = 1674329625873;
const date = new Date(now); // Fri Jan 20 2023 18:20:25
Think of timestamps as raw serialized date data. The Date objects add display formatting.
Timezones
While timestamps are fixed points in time, human-readable dates must account for timezones.
For example, 5pm in San Francisco vs New York:
SF: Jan 20, 2023 17:00:00 // 5pm
NY: Jan 20, 2023 20:00:00 // 5pm
The underlying timestamp is the same absolute point (1674329625873
) – but the display time differs by timezone.
Browsers normally display dates in the local system timezone of the end user. However, dates from databases or APIs use a fixed reference timezone instead. We need to handle any mismatches to display the right time for the user.
Daylight Saving Time (DST)
Further confusing matters is Daylight Saving Time (DST). For part of the year, clocks shift forward or back by an hour.
These DST transitions mean adding 24 hours does not always equal 1 calendar day:
During DST changes, 24 hours ≠ 1 day
If adding days across a DST boundary, we need special logic to handle the 1 hour offset.
Okay, with those concepts covered, let‘s look at techniques for incrementing dates…
Using setDate() and getDate()
The easiest approach is using the native setDate()
and getDate()
methods:
// Today
const date = new Date();
// Add 1 day
date.setDate(date.getDate() + 1);
Here‘s what‘s happening:
- Create new Date object (
date
) - Call
getDate()
to get the day of month - Increment the day value
- Pass new day back into
setDate()
This automatically handles overflow into the next month.
For example, January 31 + 1 day = February 1.
Let‘s look at some more examples:
// Birthday in current year
const birthday = new Date(2023, 0, 19);
// Next year
birthday.setDate(birthday.getDate() + 365);
birthday; // Fri Jan 19 2024 00:00:00
We can use the same approach to subtract days:
// 2 weeks ago
const weeksAgo = new Date();
weeksAgo.setDate(weeksAgo.getDate() - 14);
Easy! Behind the scenes, the JavaScript engine handles all the messy month and year rollover logic for us.
Here are some pros of this technique:
✅ Simple and readable
✅ Built-in methods work consistently
✅ Auto handles month/year rollovers
The one minor drawback is that setDate()
does not update the day of week. So you may end up with a "Tuesday" that is actually a Wednesday when incrementing days.
Overall, this setDate()
approach strikes the best balance for readability and robustness when adding days.
Adding Days with Milliseconds
We can also add days by directly manipulating timestamps.
Every 24 hours = 86,400,000 milliseconds.
So to add 1 day:
// March 7 2025, 3:15pm
const start = new Date(2025, 2, 7, 15, 15);
// 86,400,000 ms per day
const oneDay = 1000 * 60 * 60 * 24;
// New timestamp = +1 day
const end = start.getTime() + oneDay;
new Date(end);
// Tue Mar 08 2025 15:15:00
The .getTime()
method converts Date objects to milliseconds since the Unix Epoch. By adding 86,400,000 ms, we offset forward 1 whole day.
Or in function form:
function addDays(date, days) {
// 24 hrs
const oneDay = 1000 * 60 * 60 * 24;
const offset = days * oneDay;
return new Date(date.getTime() + offset);
}
addDays(new Date(), 7); // 7 days later
This allows simple control of day increments and decrements by adjusting the millisecond offsets.
However, DST transitions throw off fixed offsets.
During spring forward, some hours don‘t exist:
1AM
|
12AM 1AM *2AM* 3AM
|
Actual: 1AM -> 3AM
While in fall back, 1AM repeats twice:
1AM
* | *
1AM 2AM
|
Actual: 1AM -> 1AM again
So blindly by adding 24 hours during transitions fails:
// Spring forward night, 1:30am
const dstStart = new Date(2023, 2, 12, 1, 30);
// Next day should be 3:30am...
const nextDay = addDays(dstStart, 1);
// But is still 1:30am!
nextDay; // Sun Mar 12 2023 01:30:00
We skipped over the missing 2am hour and remained on the same day.
To fix this, we need to handle DST transitions by temporarily removing the timezone:
function addDays(date, days) {
// 1. Remove timezone to avoid DST
date.setHours(date.getHours() - date.getTimezoneOffset()/60);
// 2. Now add days normally
date.setTime(date.getTime() + days * oneDay);
// 3. Restore timezone
date.setHours(date.getHours() + date.getTimezoneOffset()/60);
return date;
}
By converting to UTC dates without DST, plain offsets work properly again through transitions.
In summary, millisecond offsets give us precision control when adding days. But we need to beware of DST changes tripping things up.
Okay, let‘s look at building reusable functions next…
Building Reusable Date Utilities
Rather than writing messy one-off date scripts, we can centralize common date manipulation operations into reusable utility modules.
Here is an example with functions to add days, weeks, and weekdays:
// date-utils.js
export function addDays(date, days) {
date = shiftTZ(date);
date.setDate(date.getDate() + days);
return backToTZ(date);
}
export function addWeeks(date, weeks) {
return addDays(date, weeks * 7);
}
export function addWeekdays(date, days) {
// ...impl...
}
// Reusable helpers
function shiftTZ(date) {
date = new Date(date);
date.setHours(date.getHours() - date.getTimezoneOffset()/60);
return date;
}
function backToTZ(date) {
date = new Date(date);
date.setHours(date.getHours() + date.getTimezoneOffset()/60);
return date;
}
Now we can import just the addDays
function without any other helpers:
// main.js
import { addDays } from ‘./date-utils.js‘;
const nextWeek = addDays(new Date(), 7);
This keeps our main code clean and focused.
For even more versatility, we could build a full date calculation engine handling intervals like:
- Days
- Weeks
- Weekdays
- Months
- Years
With a battle-tested reusable library, incrementing dates becomes trivial anywhere in our apps!
Native JavaScript Dates vs Libraries
At this point, you may be wondering whether to use the built-in JavaScript Date object or rely on an external library? Let‘s do a quick comparison of the pros and cons.
Native Date
new Date().setDate(new Date().getDate() + 1);
- ✅ Simple syntax
- ✅ High performance
- ✅ Built into JavaScript by default
- ❌ Handwritten fallbacks required
- ❌ Verbose for complex duration logic
date-fns Library
import { addDays } from ‘date-fns‘;
addDays(new Date(), 1);
- ✅ Clean readable chains
- ✅ Robust durarion calculations
- ✅ ISO 8601 string parsing
- ❌ Slower performance
- ❌ External dependency
As we can see, native Dates have the advantage of being builtin with good browser coverage support and speed. But they lack niceties like immutable date instances and custom duration adding functions.
Third party libraries like date-fns, Moment.js and dayjs fill the gaps with utility functions and locale support. But at the cost of increased bundle sizes.
So think carefully about your needs:
- For simple use cases, prefer native Dates
- For complex calendars, use a library!
With large applications, a library may be worth the tradeoff. But simpler pages can just utilize setDate()
and getTime()
.
Visual Explanation of Dates & Offsets
Let‘s visualize what‘s actually happening when we add days to dates under the hood…
Here is a helpful metaphor:
Think of Date objects as individual calendar pages
Methods like .setDate(15)
will flip the page to the 15th day of the month.
And .getTime()
peeks at the internal timestamp value used to track the position.
We can shift days by changing the position of the calendar:
Adding days offsets the calendar page position
The setDate()
method handles moving to the next/previous month automatically.
This visualization helps build an intuitive understanding of how DateTime logic works – dates are just positions on a virtual calendar!
Okay, let‘s conclude by recapping some key learnings…
Recap of Best Practices
We‘ve covered quite a lot of techniques and concepts throughout this guide!
Let‘s recap some best practices when adding days to dates in JavaScript:
✅ Use setDate()
/getDate()
for simple increments
✅ Convert Dates to UTC temporarily to avoid DST issues
✅ Build reusable date utility functions
✅ Visually think of Dates as moveable calendar pages
✅ Consider a library like date-fns for advanced use cases
Following these tips will help you avoid common date manipulation pitfalls.
Understanding the root cause of issues with DST, timezones and calculations is critical for debugging date code. Expect some trial and error while ramping up!
And there you have it – everything you need to know to become a date shifting master in JavaScript. You now have a solid grasp of core concepts like:
- Timestamps & Timezones
- Daylight Saving Time exceptions
- setDate() vs Millisecond Offsets
- Encapsulating Date Utilities
- Visualizing Date Movement
Phew, quite a tour! I hope you feel empowered to handle all kinds of date manipulations in your apps going forward. Let me know if any questions pop up!
Date work might not be glamorous, but it‘s a necessary skill we all need to learn. This guide aimed to help shorten that learning curve through lots of concrete examples and visuals.
Now get out there, have fun incrementing some dates! 🗓