Simple problems require simple solutions
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

108 lines
3.3 KiB

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