DEV Community

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

Posted on

6 2 2 2 2

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.

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more

Top comments (5)

Collapse
 
xwero profile image
david duymelinck

I think this is a communication problem instead of a coding problem.

Why is the user allowed to add a day/month format in the first place?
The code clearly expects a year because the output format is Y-m-d.

The user should be made aware of this requirement, and even been instructed to use the output format.
That way the code didn't need to be changed.

Instead, we wanted it to throw an exception and return the original value.

I think this is a weird decision. Why would you want to have an faulty format after the parsing?
Then I would suggest to skip the parsing all together, because it has no added value. Less code to maintain.

Collapse
 
bedram-tamang profile image
Bedram Tamang

@xwero I agree with your point from a developer’s perspective, but I think you're overlooking the business side of things. Users are aware that the date should be in the 'YYYY-MM-DD' format, but we can't ignore the fact that we're importing data from CSV files, and that data can be unpredictable. Instead of rejecting the entire row due to an invalid date, we chose to import the data and show the errors to the user. This way, the user is notified that the date was imported in the wrong format, and they have the opportunity to correct their mistakes after the import.

Collapse
 
xwero profile image
david duymelinck

From a users perspective it is easier to spot an empty value than a faulty date format, if the decision is to keep all rows.
What happens if the user doesn't correct the mistakes after the import? Then they had to wait twice before they get blocked, which is going to annoy the user more.
That is why I think it is a weird decision.

If you provided the CSV template or instructions, the only thing that makes the CSV data unpredictable is the user. If you want to be lenient I understand. But dates are a headache to process, so it is better to be strict.

If you want to go forward with that code, I would suggest to wrap the value in an object with a isValid property. At least that way the parsing adds some information you can use further down the line.

Thread Thread
 
bedram-tamang profile image
Bedram Tamang

@xwero By default these fields are empty, we are storing the faulty date for the sake of showing validation errors,
and CSV templates and instructions are already provided, but users upload files with invalid data, and these data are not published automatically into our system, it needs to be validated first, so users will fix issues if they want to publish to our system.

and sorry I am not showing the complete code here, I am just showing a part to explain it.

Thread Thread
 
xwero profile image
david duymelinck

Don't be sorry, it is me that has gone way off topic.
I knew it was only code as a part of your narrative.

I wanted to push back to get the full story of the feature.
I wanted to show people how development is not only code.

And you took on the conversation, for which I am very grateful!

The Most Contextual AI Development Assistant

Pieces.app image

Our centralized storage agent works on-device, unifying various developer tools to proactively capture and enrich useful materials, streamline collaboration, and solve complex problems through a contextual understanding of your unique workflow.

👥 Ideal for solo developers, teams, and cross-company projects

Learn more