Update and fix Strings stringToTime()
Allow parsing of more flexible interval strings including long names (day, hour, minute, second, millisecond), negative values, no spaces between components, and throwing exceptions on invalid input if requested. The following types are now allowed - d|day|days - h|hour|hours - m|min|mins|minute|minutes - s|sec|secs|second|seconds - ms|msec|msecs|msecond|mseconds|millis|millisec|millisecs|millisecond|milliseconds Also fix the milisecond parsing that was done completly wrong the milliseoncds where just added after a "." as decimals without converting them at all. Now the value is divided by 1000 and added to the existing number, and as before only if ms exist The negative check is now included in the main parse regex, so a second regex check is no longer necessary Spaces between values, before or anywhere are now more flexible. Exceptions are thrown if the regex cannot parse anything, or it returns only one master entry and no matches
This commit is contained in:
@@ -225,6 +225,36 @@ foreach ($intervals as $interval) {
|
||||
print "STRINGTOTIME: $reverse_interval: " . DateTime::stringToTime($reverse_interval) . "<br>";
|
||||
}
|
||||
print "<hr>";
|
||||
$interval_strings = [
|
||||
'10d 5h 30m 15s 123456ms',
|
||||
'18999d 0h 38m 10s 1235ms',
|
||||
'18999 d 0 h 38 m 10s 1235ms',
|
||||
'-2h 15m 5s',
|
||||
'45s 500ms',
|
||||
'0s',
|
||||
'0ms',
|
||||
'1s 5ms',
|
||||
'1s 50ms',
|
||||
'1s 500ms',
|
||||
'1s 5000ms',
|
||||
'10day 5hour 30min 15sec 123456millis',
|
||||
'10day 5hour 30min 15sec 123456millisec',
|
||||
'10day 5hour 30min 15sec 123456msec',
|
||||
'-2days 3hours 15minutes 30seconds 250milliseconds',
|
||||
'',
|
||||
' ',
|
||||
'invalid',
|
||||
];
|
||||
foreach ($interval_strings as $interval_string) {
|
||||
print "STRINGTOTIME: $interval_string: " . DateTime::stringToTime($interval_string) . "<br>";
|
||||
try {
|
||||
// test exception
|
||||
DateTime::stringToTime($interval_string, throw_exception:true);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
print "ERROR: " . $e->getMessage() . "<br><pre>" . $e . "</pre><br>";
|
||||
}
|
||||
}
|
||||
print "<hr>";
|
||||
$check_dates = [
|
||||
'2021-05-01',
|
||||
'2021-05-40'
|
||||
|
||||
@@ -395,39 +395,68 @@ class DateTime
|
||||
* does a reverse of the timeStringFormat and converts the string from
|
||||
* xd xh xm xs xms to a timestamp.microtime format
|
||||
*
|
||||
* @param string|int|float $timestring formatted interval
|
||||
* @return string|int|float converted float interval, or string as is
|
||||
* @param string|int|float $timestring formatted interval
|
||||
* @param bool $throw_exception [default=false] if set to true will throw exception
|
||||
* instead of returning input value as is
|
||||
* @return string|int|float converted float interval, or string as is
|
||||
*/
|
||||
public static function stringToTime(string|int|float $timestring): string|int|float
|
||||
{
|
||||
public static function stringToTime(
|
||||
string|int|float $timestring,
|
||||
bool $throw_exception = false
|
||||
): string|int|float {
|
||||
$timestamp = 0;
|
||||
if (!preg_match("/(d|h|m|s|ms)/", (string)$timestring)) {
|
||||
return $timestring;
|
||||
}
|
||||
$timestring = (string)$timestring;
|
||||
// pos for preg match read + multiply factor
|
||||
$timegroups = [2 => 86400, 4 => 3600, 6 => 60, 8 => 1];
|
||||
$matches = [];
|
||||
// if start with -, strip and set negative
|
||||
$negative = false;
|
||||
if (preg_match("/^-/", $timestring)) {
|
||||
$negative = true;
|
||||
$timestring = substr($timestring, 1);
|
||||
}
|
||||
// preg match: 0: full string
|
||||
// 2, 4, 6, 8 are the to need values
|
||||
preg_match("/^((\d+)d ?)?((\d+)h ?)?((\d+)m ?)?((\d+)s ?)?((\d+)ms)?$/", $timestring, $matches);
|
||||
if (
|
||||
!preg_match(
|
||||
"/^\s*(-)?\s*"
|
||||
. "((\d+)\s*d(?:ay(?:s)?)?)?\s*"
|
||||
. "((\d+)\s*h(?:our(?:s)?)?)?\s*"
|
||||
. "((\d+)\s*m(?:in(?:ute)?(?:s)?)?)?\s*"
|
||||
. "((\d+)\s*s(?:ec(?:ond)?(?:s)?)?)?\s*"
|
||||
. "((\d+)\s*m(?:illi)?s(?:ec(?:ond)?(?:s)?)?)?\s*"
|
||||
. "$/",
|
||||
(string)$timestring,
|
||||
$matches
|
||||
)
|
||||
) {
|
||||
if ($throw_exception) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Invalid time string format, cannot parse: "' . (string)$timestring . '"',
|
||||
1
|
||||
);
|
||||
}
|
||||
return $timestring;
|
||||
}
|
||||
if (count($matches) < 2) {
|
||||
if ($throw_exception) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Invalid time string format, no interval value found: "' . (string)$timestring . '"',
|
||||
2
|
||||
);
|
||||
}
|
||||
return $timestring;
|
||||
}
|
||||
// pos for preg match read + multiply factor
|
||||
$timegroups = [3 => 86400, 5 => 3600, 7 => 60, 9 => 1];
|
||||
// if start with -, strip and set negative
|
||||
$negative = false;
|
||||
if (!empty($matches[1])) {
|
||||
$negative = true;
|
||||
}
|
||||
// multiply the returned matches and sum them up. the last one (ms) is added with .
|
||||
foreach ($timegroups as $i => $time_multiply) {
|
||||
if (isset($matches[$i]) && is_numeric($matches[$i])) {
|
||||
$timestamp += (float)$matches[$i] * $time_multiply;
|
||||
}
|
||||
}
|
||||
if (isset($matches[10]) && is_numeric($matches[10])) {
|
||||
$timestamp .= '.' . $matches[10];
|
||||
if (isset($matches[11]) && is_numeric($matches[11])) {
|
||||
// for milliseconds, we need to divide by 1000 and add them
|
||||
$timestamp += (float)($matches[11] / 1000);
|
||||
}
|
||||
if ($negative) {
|
||||
// cast to flaot so we can do a negative multiplication
|
||||
// cast to float so we can do a negative multiplication
|
||||
$timestamp = (float)$timestamp * -1;
|
||||
}
|
||||
return $timestamp;
|
||||
|
||||
Reference in New Issue
Block a user