LeetCode 2758 - Next Day
This problem asks us to extend JavaScript's built in Date object by adding a new method called nextDay(). Once implemented, any valid Date instance should be able to call this method and receive a string representing the next calendar day in the format YYYY-MM-DD.
Difficulty: 🟢 Easy
Topics: —
Solution
LeetCode 2758 - Next Day
Problem Understanding
This problem asks us to extend JavaScript's built in Date object by adding a new method called nextDay(). Once implemented, any valid Date instance should be able to call this method and receive a string representing the next calendar day in the format YYYY-MM-DD.
The input is a valid JavaScript Date object. The method must compute the day immediately following the current date and return it as a formatted string. For example, if the date represents June 20, 2014, the method should return "2014-06-21".
The output is always a string, not a Date object. The string must follow the exact format required by the problem, with four digits for the year, two digits for the month, and two digits for the day.
The constraint guarantees that new Date(date) produces a valid date object. This means we do not need to perform any input validation or handle malformed dates. The challenge is simply to compute the next calendar day correctly.
Several edge cases can cause problems in a naive implementation. Moving from the end of a month to the beginning of the next month must be handled correctly. Dates such as January 31 or April 30 require different month transitions. Leap years introduce special handling for February 29. Year transitions, such as December 31 to January 1 of the next year, must also work correctly. Fortunately, JavaScript's built in date arithmetic already handles all of these cases automatically.
Approaches
Brute Force Approach
A brute force solution would manually calculate the next day. We could extract the year, month, and day components, determine the number of days in the current month, check whether the year is a leap year, and then increment the day accordingly.
If the day exceeds the maximum number of days in the month, we would reset the day to 1 and increment the month. If the month exceeds 12, we would reset the month to 1 and increment the year.
This approach produces the correct answer, but it requires implementing a large amount of calendar logic manually. The code becomes longer and more error prone because we must carefully handle leap years and month lengths.
Optimal Approach
The key observation is that JavaScript's Date object already knows how to perform calendar arithmetic correctly.
Instead of manually handling month boundaries, leap years, and year transitions, we can create a copy of the current date, add one day using the built in date operations, and then format the result.
The Date object automatically adjusts all calendar fields when a day increment causes an overflow. For example:
- January 31 automatically becomes February 1.
- February 28 in a leap year automatically becomes February 29.
- December 31 automatically becomes January 1 of the next year.
This dramatically simplifies the implementation while remaining correct.
Approach Comparison
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(1) | O(1) | Manually handles month lengths, leap years, and year transitions |
| Optimal | O(1) | O(1) | Uses built in Date arithmetic to advance one day |
Algorithm Walkthrough
- Create a new
Dateobject using the current date's timestamp. This avoids modifying the original date object directly. - Increment the day component by one using
setDate(getDate() + 1). JavaScript automatically normalizes the date if the increment crosses a month or year boundary. - Extract the year using
getFullYear(). - Extract the month using
getMonth() + 1. JavaScript stores months as zero indexed values, so January is0and December is11. - Extract the day using
getDate(). - Convert the month and day to two digit strings using
padStart(2, '0'). - Concatenate the components into the format
YYYY-MM-DD. - Return the formatted string.
Why it works
The correctness relies on the fact that JavaScript's Date implementation performs calendar normalization automatically. When one day is added, the object adjusts months, years, leap years, and varying month lengths according to the Gregorian calendar rules. Therefore, the resulting date always represents the next calendar day, and formatting simply converts that date into the required string representation.
Python Solution
Although the original LeetCode problem is implemented in JavaScript, the equivalent logic in Python is shown below.
from datetime import datetime, timedelta
class Solution:
def nextDay(self, date: str) -> str:
current_date = datetime.strptime(date, "%Y-%m-%d")
next_date = current_date + timedelta(days=1)
return next_date.strftime("%Y-%m-%d")
The implementation first parses the input string into a datetime object. It then adds a one day timedelta, which automatically handles month boundaries, leap years, and year transitions. Finally, the result is formatted back into the required YYYY-MM-DD string format.
For the actual LeetCode JavaScript problem, the prototype extension would look like this:
Date.prototype.nextDay = function () {
const nextDate = new Date(this);
nextDate.setDate(nextDate.getDate() + 1);
const year = nextDate.getFullYear();
const month = String(nextDate.getMonth() + 1).padStart(2, "0");
const day = String(nextDate.getDate()).padStart(2, "0");
return `${year}-${month}-${day}`;
};
Go Solution
The equivalent implementation in Go is shown below.
package main
import "time"
func nextDay(date string) string {
currentDate, _ := time.Parse("2006-01-02", date)
nextDate := currentDate.AddDate(0, 0, 1)
return nextDate.Format("2006-01-02")
}
Go uses the time package to parse and manipulate dates. The AddDate(0, 0, 1) call advances the date by one day while automatically handling leap years, month transitions, and year transitions. The result is then formatted using Go's reference date layout syntax.
Unlike Python, Go's date formatting uses the special reference value "2006-01-02" instead of format specifiers such as %Y-%m-%d.
Worked Examples
Example 1
Input:
2014-06-20
| Step | Value |
|---|---|
| Original Date | 2014-06-20 |
| Add 1 Day | 2014-06-21 |
| Year | 2014 |
| Month | 06 |
| Day | 21 |
| Result | "2014-06-21" |
Output:
2014-06-21
Example 2
Input:
2017-10-31
| Step | Value |
|---|---|
| Original Date | 2017-10-31 |
| Add 1 Day | 2017-11-01 |
| Year | 2017 |
| Month | 11 |
| Day | 01 |
| Result | "2017-11-01" |
Output:
2017-11-01
Additional Example: Year Transition
Input:
2023-12-31
| Step | Value |
|---|---|
| Original Date | 2023-12-31 |
| Add 1 Day | 2024-01-01 |
| Year | 2024 |
| Month | 01 |
| Day | 01 |
| Result | "2024-01-01" |
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(1) | Only a constant number of date operations are performed |
| Space | O(1) | No auxiliary data structures proportional to input size are used |
Since the input consists of a single date and we perform only a fixed number of arithmetic and formatting operations, both the running time and memory usage remain constant regardless of the specific date provided.
Test Cases
from datetime import datetime, timedelta
def next_day(date: str) -> str:
current_date = datetime.strptime(date, "%Y-%m-%d")
return (current_date + timedelta(days=1)).strftime("%Y-%m-%d")
assert next_day("2014-06-20") == "2014-06-21" # Provided example
assert next_day("2017-10-31") == "2017-11-01" # Month transition
assert next_day("2023-01-31") == "2023-02-01" # January to February
assert next_day("2023-04-30") == "2023-05-01" # 30-day month transition
assert next_day("2023-12-31") == "2024-01-01" # Year transition
assert next_day("2024-02-28") == "2024-02-29" # Leap year
assert next_day("2024-02-29") == "2024-03-01" # Leap day transition
assert next_day("2023-02-28") == "2023-03-01" # Non-leap year February
assert next_day("2000-02-28") == "2000-02-29" # Century leap year
assert next_day("1900-02-28") == "1900-03-01" # Century non-leap year
Test Summary
| Test | Why |
|---|---|
| 2014-06-20 | Basic increment within same month |
| 2017-10-31 | Transition to next month |
| 2023-01-31 | End of 31-day month |
| 2023-04-30 | End of 30-day month |
| 2023-12-31 | End of year transition |
| 2024-02-28 | Leap year February handling |
| 2024-02-29 | Leap day transition |
| 2023-02-28 | Non-leap year February handling |
| 2000-02-28 | Leap century year |
| 1900-02-28 | Non-leap century year |
Edge Cases
End of Month Transitions
Dates such as January 31, March 31, or April 30 can easily introduce bugs if month lengths are handled incorrectly. A manual implementation must know the exact number of days in each month. The built in date arithmetic automatically normalizes these transitions, ensuring that January 31 becomes February 1 and April 30 becomes May 1.
Leap Year Handling
February behaves differently depending on whether the year is a leap year. For example, February 28, 2024 should become February 29, while February 28, 2023 should become March 1. Leap year calculations are notoriously error prone, especially around century years. By relying on the language's date library, these rules are handled correctly without additional code.
End of Year Transition
December 31 requires incrementing both the month and the year. A naive implementation may forget to update the year after resetting the month back to January. Using built in date arithmetic ensures that December 31, 2023 automatically becomes January 1, 2024.
Century Leap Year Rules
Years divisible by 100 are not always leap years. For example, 1900 is not a leap year, while 2000 is. Manual implementations often mishandle this rule. Standard date libraries already implement the Gregorian calendar correctly, so these special cases are processed accurately.
Preservation of Formatting
The required output format always uses two digits for both month and day. Without proper padding, dates such as January 5 might incorrectly become "2024-1-5" instead of "2024-01-05". The implementation explicitly pads month and day values to guarantee the required YYYY-MM-DD format.