Skip to content

Commit b2a1bc8

Browse files
authored
Adicionando suporte a mais tipos de data (#31)
Adicionando validação de datas no formato iso e iso básico sem o "z" que indica o timezone
1 parent 73a2ef2 commit b2a1bc8

11 files changed

Lines changed: 213 additions & 28 deletions

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ composer require brunoconte3/dev-utils
2020
Or add to your `composer.json`:
2121

2222
```json
23-
"brunoconte3/dev-utils": "2.11.0"
23+
"brunoconte3/dev-utils": "2.12.0"
2424
```
2525

2626
## Data Validation Example
@@ -138,6 +138,8 @@ maxWidth and requiredFile, you can set the minimum and maximum size (bytes) of t
138138
- companyIdentification: `Validates if the CNPJ is valid, passing CNPJ with or without mask`
139139
- dateAmerican: `Validates if the American date is valid`
140140
- dateBrazil: `Validates if the Brazilian date is valid`
141+
- dateIso8601: `Validates dates in ISO 8601 format, e.g.: 2025-11-20T10:30:00Z`
142+
- dateUTCWithoutTimezone: `Validates dates in UTC format without the letter Z, e.g.: 2025-11-20T10:30:00`
141143
- dateNotFuture: `Validates if the date not greater than date current (accepts Brazilian or American format)`
142144
- ddd: `Validates ddd informed in YYY or YY format, by UF or in general` `Ex: ddd:pr, ddd do Paraná/Brazil, or just ddd`
143145
- email: `Check if it's a valid email`
@@ -444,6 +446,8 @@ use DevUtils\ValidateDate;
444446
ValidateDate::validateDateBrazil('29/04/2021'); //Return boolean [Format dd/mm/yyyy]
445447
ValidateDate::validateDateAmerican('2021-04-29'); //Return boolean [Format yyyy-mm-dd]
446448
ValidateDate::validateTimeStamp('2021-04-29 11:17:12'); //Return boolean [Format yyyy-mm-dd hh:mm:ss]
449+
ValidateDate::validateDateIso8601('2025-11-20T10:30:00Z'); //Return boolean [Format ISO 8601: 2025-11-20T10:30:00Z]
450+
ValidateDate::validateDateUTCWithoutTimezone('2025-11-20T10:30:00'); //Return boolean [Format UTC without Z: 2025-11-20T10:30:00]
447451

448452
use DevUtils\ValidateHour;
449453
ValidateHour::validateHour('08:50'); //Return boolean [Format YY:YY]

src/Arrays.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
namespace DevUtils;
66

7-
use DevUtils\Format;
8-
97
class Arrays
108
{
119
public static function searchKey(array $array, string $key): ?int

src/DependencyInjection/FormatAux.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace DevUtils\DependencyInjection;
44

5-
use DevUtils\Format;
65
use InvalidArgumentException;
76

87
abstract class FormatAux

src/DependencyInjection/TraitRule.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ private function methodsNoRuleValue(): array
1414
'validateIntegerTyped', 'validateNumeric', 'validateNumMonth', 'validateFileName',
1515
'validateFileUploadMandatory', 'validateDateBrazil', 'validateDateAmerican', 'validateHour',
1616
'validateTimestamp', 'validateWeekend', 'validateArray', 'validateFieldMandatory', 'validateBoolean',
17-
'validateFloating', 'validateJson', 'validateDateNotFuture',
17+
'validateFloating', 'validateJson', 'validateDateNotFuture', 'validateDateIso8601',
18+
'validateDateUTCWithoutTimezone',
1819
];
1920
}
2021

@@ -44,6 +45,8 @@ private static function functionsValidationAtoL(): array
4445
'ip' => 'validateIp',
4546
'json' => 'validateJson',
4647
'lower' => 'validateLower',
48+
'dateIso8601' => 'validateDateIso8601',
49+
'dateUTCWithoutTimezone' => 'validateDateUTCWithoutTimezone',
4750
];
4851
}
4952

src/DependencyInjection/TraitRuleDate.php

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@
22

33
namespace DevUtils\DependencyInjection;
44

5-
use DevUtils\{
6-
Format,
7-
ValidateDate,
8-
ValidateHour,
9-
};
5+
use DevUtils\Format;
6+
use DevUtils\ValidateDate;
7+
use DevUtils\ValidateHour;
108

119
trait TraitRuleDate
1210
{
@@ -67,4 +65,22 @@ protected function validateDateNotFuture(string $field = '', string $value = '',
6765
"O campo $field não pode ser uma data maior que a atual";
6866
}
6967
}
68+
69+
protected function validateDateIso8601(string $field = '', string $value = '', ?string $message = ''): void
70+
{
71+
if (!ValidateDate::validateDateIso8601($value)) {
72+
$this->errors[$field] = !empty($message) ? $message : "O campo $field não é uma data válida!";
73+
}
74+
}
75+
76+
77+
protected function validateDateUTCWithoutTimezone(
78+
string $field = '',
79+
string $value = '',
80+
?string $message = ''
81+
): void {
82+
if (!ValidateDate::validateDateUTCWithoutTimezone($value)) {
83+
$this->errors[$field] = !empty($message) ? $message : "O campo $field não é uma data válida!";
84+
}
85+
}
7086
}

src/DependencyInjection/TraitRuleString.php

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@
22

33
namespace DevUtils\DependencyInjection;
44

5-
use DevUtils\{
6-
Format,
7-
ValidateCnpj,
8-
ValidateCpf,
9-
ValidatePhone,
10-
ValidateString,
11-
};
125
use DevUtils\DependencyInjection\data\DataDdds;
6+
use DevUtils\Format;
137
use DevUtils\resource\Common;
8+
use DevUtils\ValidateCnpj;
9+
use DevUtils\ValidateCpf;
10+
use DevUtils\ValidatePhone;
11+
use DevUtils\ValidateString;
1412

1513
trait TraitRuleString
1614
{

src/Format.php

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,8 @@
22

33
namespace DevUtils;
44

5-
use DevUtils\{
6-
ValidateDate,
7-
ValidatePhone,
8-
ValidateFile,
9-
};
10-
use DevUtils\DependencyInjection\{
11-
FormatAux,
12-
StrfTime,
13-
};
5+
use DevUtils\DependencyInjection\FormatAux;
6+
use DevUtils\DependencyInjection\StrfTime;
147
use Exception;
158
use InvalidArgumentException;
169

src/ValidateDate.php

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,85 @@ public static function validateDateNotFuture(string $dateAmerican): bool
8080
}
8181
return true;
8282
}
83+
84+
public static function validateDateUTCWithoutTimezone(string $date): bool
85+
{
86+
$format = 'Y-m-d\TH:i:s';
87+
$d = DateTime::createFromFormat($format, $date);
88+
return $d && $d->format($format) === $date;
89+
}
90+
91+
public static function validateDateIso8601(string $input): bool
92+
{
93+
if (empty($input)) {
94+
return false;
95+
}
96+
return self::isCalendarDateTime($input) || self::isDuration($input) || self::isWeekDate($input)
97+
|| self::isOrdinalDate($input) || self::isInterval($input);
98+
}
99+
100+
private static function isCalendarDateTime(string $input): bool
101+
{
102+
$pattern = '/^\d{4}((-?\d{2})(-?\d{2})?)?(T\d{2}(:?\d{2}(:?\d{2}(\.\d+)?)?)?(Z|[+-]\d{2}(:?\d{2})?)?)?$/';
103+
if (!preg_match($pattern, $input)) {
104+
return false;
105+
}
106+
try {
107+
$date = new \DateTime($input);
108+
if (str_contains($input, '-')) {
109+
$parts = explode('T', $input)[0];
110+
if (count(explode('-', $parts)) === 3 && $date->format('Y-m-d') !== $parts) {
111+
return false;
112+
}
113+
}
114+
return true;
115+
} catch (\Exception) {
116+
return false;
117+
}
118+
}
119+
120+
private static function isWeekDate(string $input): bool
121+
{
122+
$pattern = '/^(\d{4})-?W(0[1-9]|[1-4][0-9]|5[0-3])(-?([1-7]))?$/';
123+
if (!preg_match($pattern, $input, $matches)) {
124+
return false;
125+
}
126+
$year = (int)$matches[1];
127+
$week = (int)$matches[2];
128+
if ($week === 53) {
129+
$date = new \DateTime();
130+
$date->setISODate($year, 53);
131+
return $date->format('W') === '53';
132+
}
133+
return true;
134+
}
135+
136+
private static function isOrdinalDate(string $input): bool
137+
{
138+
if (!preg_match('/^(\d{4})-?(\d{3})$/', $input, $matches)) {
139+
return false;
140+
}
141+
$year = (int)$matches[1];
142+
$dayOfYear = (int)$matches[2];
143+
$isLeap = ($year % 4 === 0 && ($year % 100 !== 0 || $year % 400 === 0));
144+
return $dayOfYear >= 1 && $dayOfYear <= ($isLeap ? 366 : 365);
145+
}
146+
147+
private static function isDuration(string $input): bool
148+
{
149+
$pattern = '/^P(?!$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?$/';
150+
return (bool) preg_match($pattern, $input);
151+
}
152+
153+
private static function isInterval(string $input): bool
154+
{
155+
if (!str_contains($input, '/')) {
156+
return false;
157+
}
158+
$parts = explode('/', $input);
159+
if (count($parts) !== 2) {
160+
return false;
161+
}
162+
return (self::validateDateIso8601($parts[0]) && self::validateDateIso8601($parts[1]));
163+
}
83164
}

src/ValidatePhone.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
namespace DevUtils;
44

5-
use DevUtils\Format;
6-
75
class ValidatePhone
86
{
97
public static function validate(string $phone): bool

tests/UnitRuleTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,4 +759,30 @@ public function testMinHeight(): void
759759
self::assertFalse(extension_loaded('gd'));
760760
}
761761
}
762+
763+
public function testDateUTCWithoutTimezone(): void
764+
{
765+
$array = [
766+
'dateError' => '2024-13-01T12:00:00',
767+
'dateValid' => '2024-12-01T12:00:00',
768+
];
769+
$rules = [
770+
'dateError' => 'dateUTCWithoutTimezone',
771+
'dateValid' => 'dateUTCWithoutTimezone',
772+
];
773+
self::assertErrorCount(1, $array, $rules);
774+
}
775+
776+
public function testDateIso8601(): void
777+
{
778+
$array = [
779+
'dateError' => '2024-13-01T12:00:00+00:00',
780+
'dateValid' => '2024-12-01T12:00:00+00:00',
781+
];
782+
$rules = [
783+
'dateError' => 'dateIso8601',
784+
'dateValid' => 'dateIso8601',
785+
];
786+
self::assertErrorCount(1, $array, $rules);
787+
}
762788
}

0 commit comments

Comments
 (0)