LeetCode 1507 - Reformat Date
The problem gives a date string in a human readable format such as "20th Oct 2052" and asks us to convert it into the st
Difficulty: 🟢 Easy
Topics: String
Solution
LeetCode 1507 - Reformat Date
Problem Understanding
The problem gives a date string in a human readable format such as "20th Oct 2052" and asks us to convert it into the standardized ISO style format YYYY-MM-DD.
The input string always contains exactly three parts:
- A day value with an ordinal suffix such as
"1st","2nd","3rd","4th", and so on. - A three letter month abbreviation such as
"Jan"or"Oct". - A four digit year.
The output must always follow the exact structure:
- Four digits for the year
- Two digits for the month
- Two digits for the day
This means that single digit months and days must include a leading zero. For example:
"6th Jun 1933"becomes"1933-06-06""1st Jan 2000"becomes"2000-01-01"
The constraints are very small. The problem guarantees that all dates are valid, so we do not need to perform any error checking or validation. This immediately tells us that the main challenge is simply parsing and formatting strings correctly.
One subtle edge case is handling single digit days like "1st" or "6th". A naive implementation might accidentally produce "1933-06-6" instead of "1933-06-06". Another important detail is removing the ordinal suffix correctly from the day component. The suffix may be "st", "nd", "rd", or "th".
Since the date format is guaranteed to be valid and highly structured, a direct parsing approach is the most natural solution.
Approaches
Brute Force Approach
A brute force style solution would manually inspect every character of the input string and build the output piece by piece. For example, we could iterate through the string character by character, identify where spaces occur, separate the day, month, and year manually, then process each segment individually.
For the day portion, we would scan until we encounter a non digit character. For the month, we would compare against all twelve possible month names using conditional statements. Finally, we would concatenate the formatted pieces together.
This approach works correctly because the input format is fixed and predictable. However, the implementation becomes unnecessarily verbose and harder to maintain. The repeated conditional logic for months also makes the code less elegant.
Optimal Approach
The key observation is that the format is already well structured. We can simply split the string into three components using spaces.
Once we have:
- day
- month
- year
we can process each independently:
- Remove the suffix from the day by taking only the numeric part.
- Use a hash map to convert the month abbreviation into its numeric representation.
- Concatenate everything in
YYYY-MM-DDformat.
This approach is clean, efficient, and easy to understand.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n) | O(1) | Manual parsing with many conditionals |
| Optimal | O(n) | O(1) | Split string and use hash map lookup |
Here, n is the length of the input string, which is very small.
Algorithm Walkthrough
- Split the input string using spaces.
This gives us three parts:
daymonthyear
For example:
"20th Oct 2052"
becomes:
["20th", "Oct", "2052"]
- Create a mapping from month abbreviation to month number.
We use a hash map because it provides constant time lookup. For example:
"Jan" -> "01"
"Feb" -> "02"
...
"Dec" -> "12"
- Extract the numeric portion of the day.
The last two characters are always the ordinal suffix. Therefore:
"20th"becomes"20""6th"becomes"6"
We can remove the suffix by taking all characters except the last two. 4. Ensure the day has two digits.
If the day contains only one digit, prepend a leading zero.
Examples:
"6"becomes"06""1"becomes"01"
- Look up the numeric month value from the hash map.
Example:
"Oct"becomes"10"
- Combine the year, month, and day using the required format.
Example:
"2052" + "-" + "10" + "-" + "20"
becomes:
"2052-10-20"
Why it works
The algorithm works because the input format is guaranteed to be consistent. Every date always contains exactly three space separated components, and every month abbreviation maps uniquely to a numeric month value. By removing the final two suffix characters from the day and padding with zeros when necessary, we always produce a correctly formatted ISO style date string.
Python Solution
class Solution:
def reformatDate(self, date: str) -> str:
month_map = {
"Jan": "01",
"Feb": "02",
"Mar": "03",
"Apr": "04",
"May": "05",
"Jun": "06",
"Jul": "07",
"Aug": "08",
"Sep": "09",
"Oct": "10",
"Nov": "11",
"Dec": "12",
}
day, month, year = date.split()
# Remove ordinal suffix
day_number = day[:-2]
# Ensure two digits
day_number = day_number.zfill(2)
return f"{year}-{month_map[month]}-{day_number}"
The implementation begins by defining a dictionary that maps each three letter month abbreviation to its two digit numeric representation. This allows constant time conversion from names like "Oct" to "10".
Next, the input string is split into three components using split(). Since the problem guarantees the format is always valid, we can safely unpack the result directly into day, month, and year.
The day suffix is removed using slicing. Since the suffix always contains exactly two characters, day[:-2] extracts only the numeric portion.
The zfill(2) method ensures the day always contains two digits. This automatically handles single digit days correctly.
Finally, the formatted string is constructed using an f-string.
Go Solution
package main
import (
"fmt"
"strings"
)
func reformatDate(date string) string {
monthMap := map[string]string{
"Jan": "01",
"Feb": "02",
"Mar": "03",
"Apr": "04",
"May": "05",
"Jun": "06",
"Jul": "07",
"Aug": "08",
"Sep": "09",
"Oct": "10",
"Nov": "11",
"Dec": "12",
}
parts := strings.Split(date, " ")
day := parts[0]
month := parts[1]
year := parts[2]
// Remove ordinal suffix
dayNumber := day[:len(day)-2]
// Add leading zero if needed
if len(dayNumber) == 1 {
dayNumber = "0" + dayNumber
}
return fmt.Sprintf("%s-%s-%s", year, monthMap[month], dayNumber)
}
The Go implementation follows the exact same logic as the Python version. One small difference is that Go does not have a built in equivalent of Python's zfill, so we manually prepend "0" when the day contains only one digit.
Another difference is string formatting. Go uses fmt.Sprintf instead of Python f-strings.
Since the constraints are tiny, there are no concerns about integer overflow or memory usage.
Worked Examples
Example 1
Input:
"20th Oct 2052"
Step 1: Split the string
| Variable | Value |
|---|---|
| day | "20th" |
| month | "Oct" |
| year | "2052" |
Step 2: Remove suffix
| Operation | Result |
|---|---|
"20th"[:-2] |
"20" |
Step 3: Zero padding
| Original | After zfill |
|---|---|
"20" |
"20" |
Step 4: Month lookup
| Month | Numeric |
|---|---|
"Oct" |
"10" |
Final Result
"2052-10-20"
Example 2
Input:
"6th Jun 1933"
Step 1: Split the string
| Variable | Value |
|---|---|
| day | "6th" |
| month | "Jun" |
| year | "1933" |
Step 2: Remove suffix
| Operation | Result |
|---|---|
"6th"[:-2] |
"6" |
Step 3: Zero padding
| Original | After zfill |
|---|---|
"6" |
"06" |
Step 4: Month lookup
| Month | Numeric |
|---|---|
"Jun" |
"06" |
Final Result
"1933-06-06"
Example 3
Input:
"26th May 1960"
Step 1: Split the string
| Variable | Value |
|---|---|
| day | "26th" |
| month | "May" |
| year | "1960" |
Step 2: Remove suffix
| Operation | Result |
|---|---|
"26th"[:-2] |
"26" |
Step 3: Zero padding
| Original | After zfill |
|---|---|
"26" |
"26" |
Step 4: Month lookup
| Month | Numeric |
|---|---|
"May" |
"05" |
Final Result
"1960-05-26"
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | We scan the string a constant number of times |
| Space | O(1) | Only a fixed size month map is stored |
The input string length is extremely small and bounded. The month mapping always contains exactly twelve entries, so it occupies constant space. All operations such as splitting, slicing, and dictionary lookup are linear or constant time relative to the small input size.
Test Cases
class Solution:
def reformatDate(self, date: str) -> str:
month_map = {
"Jan": "01",
"Feb": "02",
"Mar": "03",
"Apr": "04",
"May": "05",
"Jun": "06",
"Jul": "07",
"Aug": "08",
"Sep": "09",
"Oct": "10",
"Nov": "11",
"Dec": "12",
}
day, month, year = date.split()
day_number = day[:-2].zfill(2)
return f"{year}-{month_map[month]}-{day_number}"
sol = Solution()
# Provided examples
assert sol.reformatDate("20th Oct 2052") == "2052-10-20" # standard two digit day
assert sol.reformatDate("6th Jun 1933") == "1933-06-06" # single digit day
assert sol.reformatDate("26th May 1960") == "1960-05-26" # regular conversion
# Boundary days
assert sol.reformatDate("1st Jan 2000") == "2000-01-01" # smallest day
assert sol.reformatDate("31st Dec 2099") == "2099-12-31" # largest day
# Different suffixes
assert sol.reformatDate("2nd Feb 2020") == "2020-02-02" # nd suffix
assert sol.reformatDate("3rd Mar 2021") == "2021-03-03" # rd suffix
assert sol.reformatDate("4th Apr 2022") == "2022-04-04" # th suffix
# Leading zero checks
assert sol.reformatDate("9th Sep 1999") == "1999-09-09" # single digit month/day
# All month mappings
assert sol.reformatDate("15th Nov 2015") == "2015-11-15" # November
assert sol.reformatDate("10th Aug 1980") == "1980-08-10" # August
| Test | Why |
|---|---|
"20th Oct 2052" |
Validates normal conversion |
"6th Jun 1933" |
Ensures single digit day padding |
"26th May 1960" |
Confirms standard formatting |
"1st Jan 2000" |
Tests smallest valid day |
"31st Dec 2099" |
Tests largest valid day |
"2nd Feb 2020" |
Verifies nd suffix handling |
"3rd Mar 2021" |
Verifies rd suffix handling |
"4th Apr 2022" |
Verifies th suffix handling |
"9th Sep 1999" |
Confirms leading zero behavior |
"15th Nov 2015" |
Confirms month mapping correctness |
Edge Cases
One important edge case is a single digit day such as "6th Jun 1933". A buggy implementation might remove the suffix correctly but fail to prepend a leading zero. The solution handles this safely using zfill(2) in Python or manual zero padding in Go.
Another edge case involves the different ordinal suffixes. Days may end in "st", "nd", "rd", or "th". A naive parser might try to explicitly handle each suffix separately. This implementation avoids unnecessary branching entirely by simply removing the final two characters, which works for all valid suffixes.
A third important edge case is ensuring month conversion is always correct. Since month names are abbreviations rather than numbers, using a fixed mapping guarantees accurate conversion. This prevents mistakes such as incorrect ordering or accidental string parsing errors.