# Reformat Date
**Difficulty:** EASY
[External](https://leetcode.com/problems/reformat-date)
Canonical: https://scaleengineer.com/dsa/problems/reformat-date
**Data structures:** String
**Companies:** [Expedia](https://scaleengineer.com/companies/expedia), [Twilio](https://scaleengineer.com/companies/twilio), [Celigo](https://scaleengineer.com/companies/celigo), [Veritas](https://scaleengineer.com/companies/veritas)
---
## Problem
Given a `date` string in the form `Day Month Year`, where:

* `Day` is in the set `{"1st", "2nd", "3rd", "4th", ..., "30th", "31st"}`.
* `Month` is in the set `{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}`.
* `Year` is in the range `[1900, 2100]`.

Convert the date string to the format `YYYY-MM-DD`, where:

* `YYYY` denotes the 4 digit year.
* `MM` denotes the 2 digit month.
* `DD` denotes 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
## String Splitting with HashMap
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.
**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.
**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.
### Explanation
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.

```java
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;
    }
}
```
### 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 `date` string 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 the `HashMap`.
*   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 `StringBuilder` or string concatenation to assemble the year, month, and day with hyphens in between to form the final "YYYY-MM-DD" string.

## Direct String Parsing with Fixed Offsets
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.
**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.
**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.
### Explanation
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.

```java
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();
    }
}
```
### Algorithm
*   The structure of the date string is `Day Month Year`. The `Year` is always the last 4 characters. The `Month` is always the 3 characters preceding the year and its space. The `Day` is at the beginning.
*   Initialize a `StringBuilder` to build the result.
*   Append the `Year` to the `StringBuilder` by extracting the last 4 characters of the input string: `date.substring(date.length() - 4)`. Append a hyphen.
*   Extract the `Month` abbreviation using `date.substring(date.length() - 8, date.length() - 5)`. Convert it to its two-digit number using a pre-populated `HashMap` or a `switch` statement, and append it to the `StringBuilder`. 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 the `StringBuilder`.
*   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 the `StringBuilder`.
*   Return the string from the `StringBuilder`.

# Solutions
### Java

```java
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 ); } }
```

### CPP

```cpp
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 ); } };
```

### Python

```python
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 )
```
