Reformat Date
EasyPrompt
Given a date string in the form Day Month Year, where:
Dayis in the set{"1st", "2nd", "3rd", "4th", ..., "30th", "31st"}.Monthis in the set{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}.Yearis in the range[1900, 2100].
Convert the date string to the format YYYY-MM-DD, where:
YYYYdenotes the 4 digit year.MMdenotes the 2 digit month.DDdenotes the 2 digit day.
Example 1:
Input: date = "20th Oct 2052"
Output: "2052-10-20"Example 2:
Input: date = "6th Jun 1933"
Output: "1933-06-06"Example 3:
Input: date = "26th May 1960"
Output: "1960-05-26"
Constraints:
- The given dates are guaranteed to be valid, so no error handling is necessary.
Approaches
2 approaches with complexity analysis and trade-offs.
This approach is straightforward and relies on standard library functions for parsing. We first split the input date string by spaces to separate the day, month, and year components. Then, we use a HashMap to map the three-letter month abbreviations to their corresponding two-digit numerical representation. The day part is processed by removing the ordinal suffix (e.g., "st", "nd", "rd", "th"). Finally, we assemble the parts into the required "YYYY-MM-DD" format.
Algorithm
- Initialize a
HashMap<String, String>to store the mapping from month names to two-digit month numbers. For example, "Jan" maps to "01", "Feb" to "02", and so on for all 12 months. - Split the input
datestring using a space" "as the delimiter. This will result in a string array of three elements:[day, month, year]. - The year is the third element of the array (
parts[2]). - The month number is obtained by looking up the second element (
parts[1]) in theHashMap. - The day is the first element (
parts[0]). We need to extract the numerical part by removing the last two characters (the suffix). - If the extracted day string has a length of 1, prepend a "0" to make it a two-digit string.
- Use a
StringBuilderor string concatenation to assemble the year, month, and day with hyphens in between to form the final "YYYY-MM-DD" string.
Walkthrough
This method breaks down the problem into simple, manageable steps using built-in Java functionalities. First, a HashMap is created to act as a dictionary for converting month abbreviations like "Jan" into their numeric format "01". The input string is then split at each space, which conveniently separates the day, month, and year into a string array. The year is taken directly from the array. The month is looked up in our map. For the day, we take the day string (e.g., "20th") and remove the last two characters to get the number ("20"). A quick check is done to see if the resulting day is a single digit; if so, a '0' is prepended. Finally, these three components are concatenated in the correct order with hyphens to produce the desired output format.
import java.util.HashMap;import java.util.Map; class Solution { public String reformatDate(String date) { Map<String, String> months = new HashMap<>(); months.put("Jan", "01"); months.put("Feb", "02"); months.put("Mar", "03"); months.put("Apr", "04"); months.put("May", "05"); months.put("Jun", "06"); months.put("Jul", "07"); months.put("Aug", "08"); months.put("Sep", "09"); months.put("Oct", "10"); months.put("Nov", "11"); months.put("Dec", "12"); String[] parts = date.split(" "); String dayPart = parts[0]; String monthPart = parts[1]; String yearPart = parts[2]; String day = dayPart.substring(0, dayPart.length() - 2); if (day.length() == 1) { day = "0" + day; } String month = months.get(monthPart); return yearPart + "-" + month + "-" + day; }}Complexity
Time
O(L), where L is the length of the input string. The `split()` operation takes time proportional to the string length. While L is small and bounded in this problem, this approach is technically dependent on the input length.
Space
O(L), where L is the length of the input string. The `split()` method creates an array of strings, and the total space for these strings is proportional to the original string's length. The `HashMap` requires constant extra space.
Trade-offs
Pros
Easy to read and understand due to its high-level, declarative nature.
Uses standard, idiomatic library functions, making the code concise and maintainable.
Cons
Slightly less performant than manual parsing due to the overhead of the
split()method, which may use regular expressions.Creates intermediate data structures (the string array) that might be unnecessary for this specific problem.
This approach leverages the fixed format of the input date string to parse the components directly using substring() without splitting the string. By observing the structure, we can determine the exact positions of the year, month, and day. This avoids the overhead of creating an intermediate array from split() and can be more efficient.
Algorithm
- The structure of the date string is
Day Month Year. TheYearis always the last 4 characters. TheMonthis always the 3 characters preceding the year and its space. TheDayis at the beginning. - Initialize a
StringBuilderto build the result. - Append the
Yearto theStringBuilderby extracting the last 4 characters of the input string:date.substring(date.length() - 4). Append a hyphen. - Extract the
Monthabbreviation usingdate.substring(date.length() - 8, date.length() - 5). Convert it to its two-digit number using a pre-populatedHashMapor aswitchstatement, and append it to theStringBuilder. Append a hyphen. - Parse the
Day. Check if the second character of the input string (date.charAt(1)) is a digit. - If it is a digit, the day is two digits long (e.g., "10th", "21st"). Append the first two characters
date.substring(0, 2)to theStringBuilder. - If it is not a digit, the day is one digit long (e.g., "1st", "2nd"). Prepend a "0" and append the first character
date.charAt(0)to theStringBuilder. - Return the string from the
StringBuilder.
Walkthrough
Instead of splitting the string, this method treats the input as a fixed-format sequence of characters and extracts the required parts using their known positions. The year is always the last four characters. The month is the three characters located at a fixed offset from the end. The day is at the beginning, and its length (one or two digits) can be determined by checking if the second character of the string is a digit. A StringBuilder is used for efficient string construction. This direct manipulation avoids the overhead of creating intermediate objects like a string array, making it the most performant solution.
import java.util.HashMap;import java.util.Map; class Solution { public String reformatDate(String date) { Map<String, String> months = new HashMap<>(); months.put("Jan", "01"); months.put("Feb", "02"); months.put("Mar", "03"); months.put("Apr", "04"); months.put("May", "05"); months.put("Jun", "06"); months.put("Jul", "07"); months.put("Aug", "08"); months.put("Sep", "09"); months.put("Oct", "10"); months.put("Nov", "11"); months.put("Dec", "12"); StringBuilder sb = new StringBuilder(); // Append Year sb.append(date.substring(date.length() - 4)); sb.append("-"); // Append Month String monthStr = date.substring(date.length() - 8, date.length() - 5); sb.append(months.get(monthStr)); sb.append("-"); // Append Day if (Character.isDigit(date.charAt(1))) { // Day is two digits (e.g., "10th") sb.append(date.substring(0, 2)); } else { // Day is one digit (e.g., "1st") sb.append("0").append(date.charAt(0)); } return sb.toString(); }}Complexity
Time
O(1). All operations (`substring`, `charAt`, `HashMap` lookup) are performed on strings of a small, constant length. The complexity does not depend on the length of the input string L, as we are using fixed offsets.
Space
O(1). We use a `StringBuilder` which takes constant space for a fixed-size output. The `HashMap` also requires constant space. No intermediate data structures that scale with input size are created.
Trade-offs
Pros
Highly efficient with constant time and space complexity.
Avoids the overhead of
split()and creating intermediate arrays, leading to better performance.
Cons
The logic is more coupled to the exact format of the input string. If the format had more variability (e.g., variable spaces), this approach would become more complex.
Can be slightly harder to read than the
split()approach due to the "magic numbers" used for substring indices.
Solutions
Solution
class Solution { public String reformatDate ( String date ) { var s = date . split ( " " ); String months = " JanFebMarAprMayJunJulAugSepOctNovDec" ; int day = Integer . parseInt ( s [ 0 ]. substring ( 0 , s [ 0 ]. length () - 2 )); int month = months . indexOf ( s [ 1 ]) / 3 + 1 ; return String . format ( "%s-%02d-%02d" , s [ 2 ], month , day ); } }class Solution { public: string reformatDate ( string date ) { string months = " JanFebMarAprMayJunJulAugSepOctNovDec" ; stringstream ss ( date ); string year , month , t ; int day ; ss >> day >> t >> month >> year ; month = to_string ( months . find ( month ) / 3 + 1 ); return year + "-" + ( month . size () == 1 ? "0" + month : month ) + "-" + ( day > 9 ? "" : "0" ) + to_string ( day ); } };class Solution : def reformatDate ( self , date : str ) -> str : s = date . split () s . reverse () months = " JanFebMarAprMayJunJulAugSepOctNovDec" s [ 1 ] = str ( months . index ( s [ 1 ]) // 3 + 1 ). zfill ( 2 ) s [ 2 ] = s [ 2 ][: - 2 ]. zfill ( 2 ) return "-" . join ( s )Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.