# Date Duration Calculation This Laravel application calculates the duration between two provided dates, and outputs the number of days, week days, and weeks. A conversion parameter can also be provided to the endpoint to convert the result to seconds, minutes, hours, or years. ## General Decisions made - I've used Laravel for this, as its PHP, and something I am familiar with. - The endpoint is a POST request to `/calculate-duration`, this was done in order to leverage Laravel's validation rules. This also allows the end user to specify their data in JSON, which can be easier than managing query parameters. - Due to the specifications detailing that the duration should be initially calculated in days, week days, and weeks, and then convert it to the another value, the timezone requirement seemed redundant. This is because the most granular interval the specifications allows is a day. If, after more discussion, the requirement changed to needing the seconds between two _datetimes_, I would have changed the CalculateDuration service class to calculate the duration with the granularity of a second. - The weeks are calculated using `$start->diff($end)`, as opposed to using the PHP `DateInterval` and `DatePeriod` classes. This is primarily due to the rounding issues I experienced during dev, i.e 2024-08-01 2024-08-17 equals 4 weeks, as the duration exists _over_ 3 weeks, but does not span the _whole_ of the 3 weeks. The duration of the interval is then also added `$this->end` property during the calculation (in order to include the final day in the calculation when using P1D for the `DateInterval`). ## General Code Structure 1. `routes/web.php` - Defines the POST request route 2. `app/Http/Controllers/CalculateDurationController.php` - Handles the POST request 3. `app/Http/Requests/CalculateDurationRequest.php` - Performs validation on the POST request data 4. `app/Http/Resources/CalculateDurationResource.php` - Returns the calculated durations 5. `app/Services/CalculateDuration.php` - Calculates the duration, and converts to the `DurationModifier` if required 6. `app/Enums/DurationModifier.php` - Enum for the possible conversions, also used to validated the `convert_to` POST request parameter 7. `app/DTO/DurationResult.php` - Data transfer object, so we aren't parsing around arrays, and needing to assume the array keys exist. 8. `tests/*` Unit and integration tests. ## Room for improvement There are two things I would probably improve, if this was intended for production 1. I'd like to avoid the ternary on CalculateDuration.php:56, although I couldn't think of a quick way to simplify it. Its been a long day. 2. Tests relating to timezones are lacking, due to the aforementioned redundancy. ## Running the code All is well, as all is dockerized. ```sh composer install ./vendor/bin/sail up ``` ```sh ./vendor/bin/sail test ``` ## Testing manually You can the convert_to value to `second`, `minute`, `hour`, `year`, or omit the key entirely. ```sh read -r -d '' VAR << EOM { "start": { "date": "2024-08-01" }, "end": { "date": "2024-08-21" }, "convert_to": null } EOM curl -v \ --data "${VAR}" \ -H "Content-Type: application/json" \ -H "Accept: application/json" \ "http://localhost:80/calculate-duration" ```