CanValidateDateTime.php 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. <?php
  2. /*
  3. * Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
  4. * SPDX-License-Identifier: MIT
  5. */
  6. declare(strict_types=1);
  7. namespace Respect\Validation\Helpers;
  8. use DateTime;
  9. use DateTimeZone;
  10. use function checkdate;
  11. use function date_default_timezone_get;
  12. use function date_parse_from_format;
  13. use function preg_match;
  14. /**
  15. * Helper to handle date/time.
  16. *
  17. * @author Henrique Moody <henriquemoody@gmail.com>
  18. */
  19. trait CanValidateDateTime
  20. {
  21. /**
  22. * Finds whether a value is a valid date/time in a specific format.
  23. */
  24. private function isDateTime(string $format, string $value): bool
  25. {
  26. $exceptionalFormats = [
  27. 'c' => 'Y-m-d\TH:i:sP',
  28. 'r' => 'D, d M Y H:i:s O',
  29. ];
  30. $format = $exceptionalFormats[$format] ?? $format;
  31. $info = date_parse_from_format($format, $value);
  32. if (!$this->isDateTimeParsable($info)) {
  33. return false;
  34. }
  35. if ($this->isDateFormat($format)) {
  36. $formattedDate = DateTime::createFromFormat(
  37. $format,
  38. $value,
  39. new DateTimeZone(date_default_timezone_get())
  40. );
  41. if ($formattedDate === false || $value !== $formattedDate->format($format)) {
  42. return false;
  43. }
  44. return $this->isDateInformation($info);
  45. }
  46. return true;
  47. }
  48. /**
  49. * @param mixed[] $info
  50. */
  51. private function isDateTimeParsable(array $info): bool
  52. {
  53. return $info['error_count'] === 0 && $info['warning_count'] === 0;
  54. }
  55. private function isDateFormat(string $format): bool
  56. {
  57. return preg_match('/[djSFmMnYy]/', $format) > 0;
  58. }
  59. /**
  60. * @param mixed[] $info
  61. */
  62. private function isDateInformation(array $info): bool
  63. {
  64. if ($info['day']) {
  65. return checkdate((int) $info['month'], $info['day'], (int) $info['year']);
  66. }
  67. return checkdate($info['month'] ?: 1, 1, $info['year'] ?: 1);
  68. }
  69. }