DEV Community

Cover image for Solving Problems the Right Way: Leveraging Frameworks Over Quick Fixes
Bedram Tamang
Bedram Tamang

Posted on

Solving Problems the Right Way: Leveraging Frameworks Over Quick Fixes

We have a feature that allows importing CSV files into a database. The CSV rows can contain date fields as well, so we implemented a date parser before inserting the data into the database. The date parser looked like this:

class DateParser {
  ....

    public function parse(mixed $value)
    {
        try {
            return Carbon::parse($value)->format('Y-m-d');
        } catch (Exception $exception) {
            return $value;
        }
    }
} 

Enter fullscreen mode Exit fullscreen mode

I would say that this is very standard date parsing code any Laravel developer would write, as we are very familiar with the Carbon library, which Laravel uses internally for all date and time manipulations. However, we encountered an issue. When a user imported a date field with just the month and day (e.g., 11/11), it was being parsed as 2025-11-11. While this makes sense—since the current year is added when the year is not provided—it was not the expected behavior for our case. Instead, we wanted it to throw an exception and return the original value.

I started looking for solutions on StackOverflow and GitHub issues to see if anyone had already discussed this case, but I couldn’t find any solutions. I considered writing a regex to check if the given date matched certain formats, such as YYYY-MM-DD or YYYY/MM/DD. However, there are so many possible combinations that it felt cumbersome to support all formats. I asked ChatGPT for help with the regex (I admit, I was too lazy to figure it out myself), and it provided this regex:

$pattern = '/\b(?:(?:19|20)\d{2}[-/.](?:0?[1-9]|1[0-2])[-/.](?:0?[1-9]|[12][0-9]|3[01])  # YYYY-MM-DD, YYYY/MM/DD, YYYY.MM.DD
| (?:0?[1-9]|1[0-2])[-/.](?:0?[1-9]|[12][0-9]|3[01])[-/.](?:19|20)\d{2}      # MM-DD-YYYY, MM/DD/YYYY, MM.DD.YYYY
| (?:0?[1-9]|[12][0-9]|3[01])[-/.](?:0?[1-9]|1[0-2])[-/.](?:19|20)\d{2})\b/x';
Enter fullscreen mode Exit fullscreen mode

But I wasn’t sure if it would work, and I didn’t feel it was the right approach. Additionally, the Carbon::parse method also supports date strings like first day of December 2020, which returns 2020-12-01. The new regex solution completely missed this case.

I then decided to check if 11/11 was a valid date according to Laravel's validation. I tested it in a small tinker script:

Validator::make([
  'date' => '11/11'
], [
  'date' => [Rule::date()]
])
Enter fullscreen mode Exit fullscreen mode

It was throwing validation errors, which indicated that Laravel is handling the validation correctly. So I dug deeper into how Laravel validates dates. I discovered that Laravel uses two methods for date parsing and validation: date_parse() and checkdate(). These methods are built-in PHP functions. The date_parse() function returns an array like this:

[
  "year" => false,
  "month" => 11,
  "day" => 11,
  "hour" => false,
  "minute" => false,
  "second" => false,
  "fraction" => false,
  "warning_count" => 0,
  "warnings" => [],
  "error_count" => 0,
  "errors" => [],
  "is_localtime" => false
]
Enter fullscreen mode Exit fullscreen mode

We pass the year, month, and day to the checkdate() method. It returns true if the date is valid, and we create the date and return the valid result. This method also supports string-based dates, as shown above. The final solution we came up with was:

...
public function parse(mixed $value){
    $date = date_parse($value);

    if (checkdate($date['month'], $date['day'], $date['year'])) {
        return Carbon::create($date['year'], $date['month'], $date['day'])->format('Y-m-d');
    }

    return $value;
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

When we encounter problems and are unable to solve them using native Carbon library, many of us instinctively jump to writing regex-based solutions or complex custom logic to fix the issue immediately. However, such solutions often come at a cost—they can be hard to maintain, difficult to extend, and prone to breaking when requirements change.

Instead of taking that approach, we decided to look into the framework itself to understand how Laravel handles date validation. By doing so, we found that Laravel relies on PHP’s built-in date_parse() and checkdate() functions, which provided a more reliable and framework-aligned solution.

This reinforces an essential lesson: before writing custom fixes, it’s always worth exploring how the framework or language solves similar problems. This approach not only saves time but also ensures that our solution is maintainable, scalable, and in line with best practices.

Top comments (0)