LeetCode 1360 - Number of Days Between Two Dates

The problem gives two dates in the format YYYY-MM-DD and asks us to compute the absolute number of days between them. Each input string represents a valid calendar date. The year, month, and day are separated by hyphens.

LeetCode Problem 1360

Difficulty: 🟢 Easy
Topics: Math, String

Solution

Problem Understanding

The problem gives two dates in the format YYYY-MM-DD and asks us to compute the absolute number of days between them.

Each input string represents a valid calendar date. The year, month, and day are separated by hyphens. For example:

  • "2019-06-29" means June 29, 2019
  • "2020-01-15" means January 15, 2020

The expected output is a single integer representing how many days separate the two dates. The order of the dates does not matter because the answer is the absolute difference.

The main challenge is handling the Gregorian calendar correctly, especially leap years. A leap year has 366 days instead of 365 days, which affects the number of days in February.

A year is a leap year if:

  • It is divisible by 400, or
  • It is divisible by 4 but not divisible by 100

Examples:

  • 2020 is a leap year
  • 2000 is a leap year
  • 1900 is not a leap year

The constraints are relatively small, dates are only between 1971 and 2100. Even a straightforward simulation approach would work within these limits. However, the cleaner and more scalable solution is to convert each date into the number of days from a fixed reference point, then compute the absolute difference.

Several edge cases are important:

  • Dates in the same month
  • Dates across different months
  • Dates across different years
  • Leap year transitions, especially February 29
  • Inputs where date1 > date2
  • Boundary years like 1971 and 2100

The problem guarantees that all dates are valid, so we do not need to validate month ranges or day ranges ourselves.

Approaches

Brute Force Approach

The brute force method simulates day-by-day movement from one date to the other.

The idea is simple:

  1. Determine which date is earlier.
  2. Repeatedly advance the earlier date by one day.
  3. Count how many increments are required until the dates become equal.

To advance a date correctly, we must:

  • Know the number of days in each month
  • Handle leap years
  • Move to the next month when the day exceeds the month limit
  • Move to the next year when the month exceeds December

This approach is correct because every iteration represents exactly one calendar day.

However, it is inefficient because we may need to simulate tens of thousands of days. While the constraints are small enough for this to pass, the approach is unnecessarily complicated and slower than needed.

Optimal Approach

The better approach converts each date into a single integer representing the total number of days elapsed since a fixed reference date.

For example:

  • Count all days from year 0 up to the target year
  • Add all days from completed months in the current year
  • Add the current day

Once both dates are converted into day counts, the answer becomes:

abs(days1 - days2)

The key insight is that comparing dates becomes trivial once dates are represented as cumulative day counts.

This avoids repeated simulation and reduces the problem to arithmetic.

Approach Time Complexity Space Complexity Notes
Brute Force O(D) O(1) Simulates every day between the two dates
Optimal O(1) O(1) Converts each date into an absolute day count

Here, D is the number of days between the two dates.

Algorithm Walkthrough

Optimal Algorithm

  1. Parse the date string into integers for year, month, and day.

The input format is fixed as YYYY-MM-DD, so we can split the string by "-" and convert each part into integers. 2. Create a helper function to determine whether a year is a leap year.

This is necessary because February has either 28 or 29 days depending on the year. 3. Create a helper function that converts a date into the total number of elapsed days.

This function computes:

  • All days contributed by complete years before the current year
  • All days contributed by complete months before the current month
  • The current day value
  1. Count days from previous years.

For every year before the current year:

  • Add 365 days
  • Add 1 extra day if the year is a leap year
  1. Count days from previous months in the current year.

Use an array of month lengths:

[31,28,31,30,31,30,31,31,30,31,30,31]

If the current year is a leap year, February becomes 29 days. 6. Add the current day.

After processing completed months, add the day value itself. 7. Compute the absolute difference.

Convert both dates into total day counts and return:

abs(days1 - days2)

Why it works

The algorithm works because every date is mapped to a unique cumulative day count measured from a fixed origin. The difference between two cumulative counts is exactly the number of days separating the dates. Leap years are explicitly handled during year and month calculations, ensuring that the calendar structure is represented correctly.

Python Solution

class Solution:
    def daysBetweenDates(self, date1: str, date2: str) -> int:
        
        def is_leap(year: int) -> bool:
            return (
                year % 400 == 0 or
                (year % 4 == 0 and year % 100 != 0)
            )
        
        def to_days(date: str) -> int:
            year, month, day = map(int, date.split("-"))
            
            month_days = [
                31, 28, 31, 30, 31, 30,
                31, 31, 30, 31, 30, 31
            ]
            
            total_days = 0
            
            # Add days from previous years
            for y in range(year):
                total_days += 365
                if is_leap(y):
                    total_days += 1
            
            # Adjust February for leap year
            if is_leap(year):
                month_days[1] = 29
            
            # Add days from previous months
            for m in range(month - 1):
                total_days += month_days[m]
            
            # Add current day
            total_days += day
            
            return total_days
        
        return abs(to_days(date1) - to_days(date2))

The implementation begins with the is_leap helper function, which encapsulates the leap year rules. Separating this logic into its own function improves readability and avoids duplication.

The to_days helper converts a date string into a cumulative day count. First, the date is parsed into integers. Then we iterate through all years before the target year and add either 365 or 366 days depending on whether the year is a leap year.

Next, we adjust February if the current year is a leap year. After that, we add the lengths of all completed months before the current month.

Finally, we add the current day itself and return the total cumulative count.

The main function simply computes the absolute difference between the two converted values.

Go Solution

func daysBetweenDates(date1 string, date2 string) int {

	isLeap := func(year int) bool {
		return year%400 == 0 || (year%4 == 0 && year%100 != 0)
	}

	toDays := func(date string) int {
		var year, month, day int
		fmt.Sscanf(date, "%d-%d-%d", &year, &month, &day)

		monthDays := []int{
			31, 28, 31, 30, 31, 30,
			31, 31, 30, 31, 30, 31,
		}

		totalDays := 0

		// Add days from previous years
		for y := 0; y < year; y++ {
			totalDays += 365
			if isLeap(y) {
				totalDays++
			}
		}

		// Adjust February for leap year
		if isLeap(year) {
			monthDays[1] = 29
		}

		// Add days from previous months
		for m := 0; m < month-1; m++ {
			totalDays += monthDays[m]
		}

		// Add current day
		totalDays += day

		return totalDays
	}

	result := toDays(date1) - toDays(date2)

	if result < 0 {
		return -result
	}

	return result
}

The Go solution follows the same logic as the Python version. The main difference is date parsing. Instead of split, Go uses fmt.Sscanf to extract the year, month, and day values directly from the formatted string.

Go does not provide a built-in absolute value function for integers in the standard library without conversion, so the code manually checks whether the result is negative.

Slices are used for month lengths, similar to Python lists.

Worked Examples

Example 1

Input:

date1 = "2019-06-29"
date2 = "2019-06-30"

Convert "2019-06-29"

Step Value
Days from years before 2019 736694
Days from Jan through May 151
Current day 29
Total 736874

Convert "2019-06-30"

Step Value
Days from years before 2019 736694
Days from Jan through May 151
Current day 30
Total 736875

Difference:

abs(736874 - 736875) = 1

Output:

1

Example 2

Input:

date1 = "2020-01-15"
date2 = "2019-12-31"

Convert "2020-01-15"

Step Value
Days from years before 2020 737059
Days from previous months 0
Current day 15
Total 737074

Convert "2019-12-31"

Step Value
Days from years before 2019 736694
Days from Jan through Nov 334
Current day 31
Total 737059

Difference:

abs(737074 - 737059) = 15

Output:

15

Complexity Analysis

Measure Complexity Explanation
Time O(1) The number of years and months processed is bounded by constants
Space O(1) Only a few variables and a fixed-size month array are used

Although the implementation loops through years, the maximum range is fixed by the constraints, between 1971 and 2100. Therefore the runtime is effectively constant. The algorithm does not allocate memory proportional to the input size, so the space complexity is constant as well.

Test Cases

solution = Solution()

assert solution.daysBetweenDates("2019-06-29", "2019-06-30") == 1
# Basic adjacent dates

assert solution.daysBetweenDates("2020-01-15", "2019-12-31") == 15
# Crossing year boundary

assert solution.daysBetweenDates("2020-02-28", "2020-03-01") == 2
# Leap year February transition

assert solution.daysBetweenDates("2019-02-28", "2019-03-01") == 1
# Non-leap year February transition

assert solution.daysBetweenDates("2020-02-29", "2020-03-01") == 1
# Leap day handling

assert solution.daysBetweenDates("1971-01-01", "1971-01-01") == 0
# Same date

assert solution.daysBetweenDates("2100-12-31", "1971-01-01") > 0
# Large date range

assert solution.daysBetweenDates("2000-01-01", "1999-12-31") == 1
# Century leap year

assert solution.daysBetweenDates("1900-03-01", "1900-02-28") == 1
# 1900 is not a leap year

assert solution.daysBetweenDates("2021-12-31", "2022-01-01") == 1
# New year transition
Test Why
"2019-06-29" vs "2019-06-30" Validates basic one-day difference
"2020-01-15" vs "2019-12-31" Tests crossing into a new year
"2020-02-28" vs "2020-03-01" Tests leap year February behavior
"2019-02-28" vs "2019-03-01" Tests normal February behavior
"2020-02-29" vs "2020-03-01" Verifies leap day correctness
Same date input Ensures zero difference works
Very large range Tests upper constraint range
"2000-01-01" vs "1999-12-31" Validates century leap year
"1900-03-01" vs "1900-02-28" Ensures non-leap century handling
"2021-12-31" vs "2022-01-01" Tests year rollover

Edge Cases

Leap Year February

Dates around February are the most common source of bugs because February changes length depending on the year. For example, 2020 has February 29 while 2019 does not. If the implementation always assumes February has 28 days, the answer becomes incorrect for leap years. The solution handles this by dynamically changing February to 29 days whenever the current year satisfies the leap year condition.

Same Input Dates

If both dates are identical, the correct answer is 0. Some implementations accidentally return 1 because they count inclusive ranges instead of differences. This implementation avoids that problem because it converts both dates into cumulative counts and subtracts them directly.

Dates Given in Reverse Order

The problem does not guarantee that date1 is earlier than date2. A naive subtraction could produce a negative result. The implementation solves this by returning the absolute value of the difference, ensuring the output is always non-negative.

Year Boundary Transitions

Transitions like December 31 to January 1 are easy to mishandle when manually simulating dates. The cumulative day count approach naturally handles year rollover because the total day count continuously increases across years.

Century Leap Year Rules

Years divisible by 100 are not leap years unless they are also divisible by 400. This rule is easy to forget. For example:

  • 1900 is not a leap year
  • 2000 is a leap year

The implementation explicitly encodes this rule in the is_leap function, ensuring correct calendar calculations.