Add src files for CoreLibs composer all package
This commit is contained in:
412
src/Combined/ArrayHandler.php
Normal file
412
src/Combined/ArrayHandler.php
Normal file
@@ -0,0 +1,412 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* array search and transform functions
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Combined;
|
||||
|
||||
class ArrayHandler
|
||||
{
|
||||
/**
|
||||
* searches key = value in an array / array
|
||||
* only returns the first one found
|
||||
*
|
||||
* @param string|int $needle needle (search for)
|
||||
* @param array<mixed> $haystack haystack (search in)
|
||||
* @param string|null $key_search_for the key to look out for, default empty
|
||||
* @return array<mixed> array with the elements where
|
||||
* the needle can be found in the
|
||||
* haystack array
|
||||
*/
|
||||
public static function arraySearchRecursive($needle, array $haystack, ?string $key_search_for = null): array
|
||||
{
|
||||
$path = [];
|
||||
if (!is_array($haystack)) {
|
||||
$haystack = [];
|
||||
}
|
||||
if (
|
||||
$key_search_for != null &&
|
||||
array_key_exists($key_search_for, $haystack) &&
|
||||
$needle === $haystack[$key_search_for]
|
||||
) {
|
||||
$path[] = $key_search_for;
|
||||
} else {
|
||||
foreach ($haystack as $key => $val) {
|
||||
if (
|
||||
is_scalar($val) &&
|
||||
$val === $needle &&
|
||||
empty($key_search_for)
|
||||
) {
|
||||
$path[] = $key;
|
||||
break;
|
||||
} elseif (
|
||||
is_scalar($val) &&
|
||||
!empty($key_search_for) &&
|
||||
$key === $key_search_for &&
|
||||
$val === $needle
|
||||
) {
|
||||
$path[] = $key;
|
||||
break;
|
||||
} elseif (
|
||||
is_array($val) &&
|
||||
$path = self::arraySearchRecursive(
|
||||
$needle,
|
||||
(array)$val,
|
||||
// to avoid PhanTypeMismatchArgumentNullable
|
||||
($key_search_for === null ? $key_search_for : (string)$key_search_for)
|
||||
)
|
||||
) {
|
||||
array_unshift($path, $key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* recursive array search function, which returns all found not only the first one
|
||||
*
|
||||
* @param string|int $needle needle (search for)
|
||||
* @param array<mixed> $haystack haystack (search in)
|
||||
* @param string|int $key_search_for the key to look for in
|
||||
* @param bool $old [true], if set to false will
|
||||
* return new flat layout
|
||||
* @param array<mixed>|null $path recursive call for previous path
|
||||
* @return array<mixed>|null all array elements paths where
|
||||
* the element was found
|
||||
*/
|
||||
public static function arraySearchRecursiveAll(
|
||||
$needle,
|
||||
array $haystack,
|
||||
$key_search_for,
|
||||
bool $old = true,
|
||||
?array $path = null
|
||||
): ?array {
|
||||
// init if not set on null
|
||||
if ($path === null) {
|
||||
$path = [
|
||||
'level' => 0,
|
||||
'work' => []
|
||||
];
|
||||
} else {
|
||||
// init sub sets if not set
|
||||
if (!isset($path['level'])) {
|
||||
$path['level'] = 0;
|
||||
}
|
||||
if (!isset($path['work'])) {
|
||||
$path['work'] = [];
|
||||
}
|
||||
}
|
||||
// should not be needed because it would trigger a php mehtod error
|
||||
if (!is_array($haystack)) {
|
||||
$haystack = [];
|
||||
}
|
||||
|
||||
// go through the array,
|
||||
foreach ($haystack as $_key => $_value) {
|
||||
if (
|
||||
is_scalar($_value) &&
|
||||
$_value === $needle &&
|
||||
empty($key_search_for)
|
||||
) {
|
||||
// only value matches
|
||||
$path['work'][$path['level'] ?? 0] = $_key;
|
||||
$path['found'][] = $path['work'];
|
||||
} elseif (
|
||||
is_scalar($_value) &&
|
||||
!empty($key_search_for) &&
|
||||
$_key === $key_search_for &&
|
||||
$_value === $needle
|
||||
) {
|
||||
// key and value matches
|
||||
$path['work'][$path['level'] ?? 0] = $_key;
|
||||
$path['found'][] = $path['work'];
|
||||
} elseif (is_array($_value)) {
|
||||
// add position to working
|
||||
$path['work'][$path['level'] ?? 0] = $_key;
|
||||
// we will up a level
|
||||
$path['level'] += 1;
|
||||
// call recursive
|
||||
$path = self::arraySearchRecursiveAll($needle, $_value, $key_search_for, $old, $path);
|
||||
}
|
||||
}
|
||||
// be 100% sure the array elements are set
|
||||
$path['level'] = $path['level'] ?? 0;
|
||||
$path['work'] = $path['work'] ?? [];
|
||||
// cut all that is >= level
|
||||
array_splice($path['work'], $path['level']);
|
||||
// step back a level
|
||||
$path['level'] -= 1;
|
||||
if ($old === false && $path['level'] == -1) {
|
||||
return $path['found'] ?? [];
|
||||
} else {
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* array search simple. looks for key, value combination, if found, returns true
|
||||
* on default does not strict check, so string '4' will match int 4 and vica versa
|
||||
*
|
||||
* @param array<mixed> $array search in as array
|
||||
* @param string|int $key key (key to search in)
|
||||
* @param string|int $value value (what to find)
|
||||
* @param bool $strict [false], if set to true, will strict check key/value
|
||||
* @return bool true on found, false on not found
|
||||
*/
|
||||
public static function arraySearchSimple(array $array, $key, $value, bool $strict = false): bool
|
||||
{
|
||||
if (!is_array($array)) {
|
||||
$array = [];
|
||||
}
|
||||
foreach ($array as $_key => $_value) {
|
||||
// if value is an array, we search
|
||||
if (is_array($_value)) {
|
||||
// call recursive, and return result if it is true, else continue
|
||||
if (($result = self::arraySearchSimple($_value, $key, $value, $strict)) !== false) {
|
||||
return $result;
|
||||
}
|
||||
} elseif ($strict === false && $_key == $key && $_value == $value) {
|
||||
return true;
|
||||
} elseif ($strict === true && $_key === $key && $_value === $value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// no true returned, not found
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* correctly recursive merges as an array as array_merge_recursive
|
||||
* just glues things together
|
||||
* array first array to merge
|
||||
* array second array to merge
|
||||
* ... etc
|
||||
* bool key flag: true: handle keys as string or int
|
||||
* default false: all keys are string
|
||||
*
|
||||
* @return array<mixed>|bool merged array
|
||||
*/
|
||||
public static function arrayMergeRecursive()
|
||||
{
|
||||
// croak on not enough arguemnts (we need at least two)
|
||||
if (func_num_args() < 2) {
|
||||
trigger_error(__FUNCTION__ . ' needs two or more array arguments', E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
// default key is not string
|
||||
$key_is_string = false;
|
||||
$arrays = func_get_args();
|
||||
// if last is not array, then assume it is trigger for key is always string
|
||||
if (!is_array(end($arrays))) {
|
||||
if (array_pop($arrays)) {
|
||||
$key_is_string = true;
|
||||
}
|
||||
}
|
||||
// check that arrays count is at least two, else we don't have enough to do anything
|
||||
if (count($arrays) < 2) {
|
||||
trigger_error(__FUNCTION__ . ' needs two or more array arguments', E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
$merged = [];
|
||||
while ($arrays) {
|
||||
$array = array_shift($arrays);
|
||||
if (!is_array($array)) {
|
||||
trigger_error(__FUNCTION__ . ' encountered a non array argument', E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
if (!$array) {
|
||||
continue;
|
||||
}
|
||||
foreach ($array as $key => $value) {
|
||||
// if string or if key is assumed to be string do key match
|
||||
// else add new entry
|
||||
if (is_string($key) || $key_is_string === false) {
|
||||
if (is_array($value) && array_key_exists($key, $merged) && is_array($merged[$key])) {
|
||||
// $merged[$key] = call_user_func(__METHOD__, $merged[$key], $value, $key_is_string);
|
||||
$merged[$key] = self::arrayMergeRecursive($merged[$key], $value, $key_is_string);
|
||||
} else {
|
||||
$merged[$key] = $value;
|
||||
}
|
||||
} else {
|
||||
$merged[] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $merged;
|
||||
}
|
||||
|
||||
/**
|
||||
* correct array_diff that does an actualy difference between two arrays.
|
||||
* array_diff only checks elements from A that are not in B, but not the
|
||||
* other way around.
|
||||
* Note that like array_diff this only checks first level values not keys
|
||||
*
|
||||
* @param array<mixed> $a array to compare a
|
||||
* @param array<mixed> $b array to compare b
|
||||
* @return array<mixed> array with missing elements from a & b
|
||||
*/
|
||||
public static function arrayDiff(array $a, array $b): array
|
||||
{
|
||||
$intersect = array_intersect($a, $b);
|
||||
return array_merge(array_diff($a, $intersect), array_diff($b, $intersect));
|
||||
}
|
||||
|
||||
/**
|
||||
* search for the needle array elements in haystack and
|
||||
* return the ones found as an array,
|
||||
* is there nothing found, it returns FALSE (boolean)
|
||||
*
|
||||
* @param array<mixed> $needle elements to search for
|
||||
* @param array<mixed> $haystack array where the $needle elements should
|
||||
* be searched int
|
||||
* @return array<mixed>|bool either the found elements or
|
||||
* false for nothing found or error
|
||||
*/
|
||||
public static function inArrayAny(array $needle, array $haystack)
|
||||
{
|
||||
$found = [];
|
||||
foreach ($needle as $element) {
|
||||
if (in_array($element, $haystack)) {
|
||||
$found[] = $element;
|
||||
}
|
||||
}
|
||||
if (count($found) == 0) {
|
||||
return false;
|
||||
} else {
|
||||
return $found;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* creates out of a normal db_return array an assoc array
|
||||
*
|
||||
* @param array<mixed> $db_array return array from the database
|
||||
* @param string|int|bool $key key set, false for not set
|
||||
* @param string|int|bool $value value set, false for not set
|
||||
* @param bool $set_only flag to return all (default), or set only
|
||||
* @return array<mixed> associative array
|
||||
*/
|
||||
public static function genAssocArray(array $db_array, $key, $value, bool $set_only = false): array
|
||||
{
|
||||
$ret_array = [];
|
||||
// do this to only run count once
|
||||
for ($i = 0, $iMax = count($db_array); $i < $iMax; $i++) {
|
||||
// if no key then we make an order reference
|
||||
if (
|
||||
$key !== false &&
|
||||
$value !== false &&
|
||||
(($set_only && !empty($db_array[$i][$value])) ||
|
||||
(!$set_only && isset($db_array[$i][$value]))) &&
|
||||
!empty($db_array[$i][$key])
|
||||
) {
|
||||
$ret_array[$db_array[$i][$key]] = $db_array[$i][$value];
|
||||
} elseif (
|
||||
$key === false && $value !== false &&
|
||||
isset($db_array[$i][$value])
|
||||
) {
|
||||
$ret_array[] = $db_array[$i][$value];
|
||||
} elseif (
|
||||
$key !== false && $value === false &&
|
||||
!empty($db_array[$i][$key])
|
||||
) {
|
||||
$ret_array[$db_array[$i][$key]] = $i;
|
||||
}
|
||||
}
|
||||
return $ret_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* converts multi dimensional array to a flat array
|
||||
* does NOT preserve keys
|
||||
*
|
||||
* @param array<mixed> $array multi dimensionial array
|
||||
* @return array<mixed> flattened array
|
||||
*/
|
||||
public static function flattenArray(array $array): array
|
||||
{
|
||||
$return = [];
|
||||
array_walk_recursive(
|
||||
$array,
|
||||
function ($value) use (&$return) {
|
||||
$return[] = $value;
|
||||
}
|
||||
);
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* will loop through an array recursivly and write the array keys back
|
||||
*
|
||||
* @param array<mixed> $array multidemnsional array to flatten
|
||||
* @param array<mixed> $return recoursive pass on array of keys
|
||||
* @return array<mixed> flattened keys array
|
||||
*/
|
||||
public static function flattenArrayKey(array $array, array $return = []): array
|
||||
{
|
||||
foreach ($array as $key => $sub) {
|
||||
$return[] = $key;
|
||||
if (is_array($sub) && count($sub) > 0) {
|
||||
$return = self::flattenArrayKey($sub, $return);
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* as above will flatten an array, but in this case only the outmost
|
||||
* leave nodes, all other keyswill be skipped
|
||||
*
|
||||
* @param array<mixed> $array multidemnsional array to flatten
|
||||
* @return array<mixed> flattened keys array
|
||||
*/
|
||||
public static function flattenArrayKeyLeavesOnly(array $array): array
|
||||
{
|
||||
$return = [];
|
||||
array_walk_recursive(
|
||||
$array,
|
||||
function ($value, $key) use (&$return) {
|
||||
$return[] = $key;
|
||||
}
|
||||
);
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* searches for key -> value in an array tree and writes the value one level up
|
||||
* this will remove this leaf will all other values
|
||||
*
|
||||
* @param array<mixed> $array nested array
|
||||
* @param string|int $search key to find that has no sub leaf
|
||||
* and will be pushed up
|
||||
* @return array<mixed> modified, flattened array
|
||||
*/
|
||||
public static function arrayFlatForKey(array $array, $search): array
|
||||
{
|
||||
if (!is_array($array)) {
|
||||
$array = [];
|
||||
}
|
||||
foreach ($array as $key => $value) {
|
||||
// if it is not an array do just nothing
|
||||
if (!is_array($value)) {
|
||||
continue;
|
||||
}
|
||||
// probe it has search key
|
||||
if (isset($value[$search])) {
|
||||
// set as current
|
||||
$array[$key] = $value[$search];
|
||||
} else {
|
||||
// call up next node down
|
||||
// $array[$key] = call_user_func(__METHOD__, $value, $search);
|
||||
$array[$key] = self::arrayFlatForKey($value, $search);
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
|
||||
// __END__
|
||||
452
src/Combined/DateTime.php
Normal file
452
src/Combined/DateTime.php
Normal file
@@ -0,0 +1,452 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* date convert and check functions
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Combined;
|
||||
|
||||
use Exception;
|
||||
|
||||
class DateTime
|
||||
{
|
||||
/** @var array<int,string> */
|
||||
public const DAY_SHORT = [
|
||||
1 => 'Mon',
|
||||
2 => 'Tue',
|
||||
3 => 'Wed',
|
||||
4 => 'Thu',
|
||||
5 => 'Fri',
|
||||
6 => 'Sat',
|
||||
7 => 'Sun',
|
||||
];
|
||||
/** @var array<int,string> */
|
||||
public const DAY_LONG = [
|
||||
1 => 'Monday',
|
||||
2 => 'Tuesday',
|
||||
3 => 'Wednesday',
|
||||
4 => 'Thursday',
|
||||
5 => 'Friday',
|
||||
6 => 'Saturday',
|
||||
7 => 'Sunday',
|
||||
];
|
||||
/** @var array<int,string> */
|
||||
public const MONTH_LONG = [
|
||||
1 => 'January',
|
||||
2 => 'February',
|
||||
3 => 'March',
|
||||
4 => 'April',
|
||||
5 => 'May',
|
||||
6 => 'June',
|
||||
7 => 'July',
|
||||
8 => 'August',
|
||||
9 => 'September',
|
||||
10 => 'October',
|
||||
11 => 'November',
|
||||
12 => 'December',
|
||||
];
|
||||
/** @var array<int,string> */
|
||||
public const MONTH_SHORT = [
|
||||
1 => 'Jan',
|
||||
2 => 'Feb',
|
||||
3 => 'Mar',
|
||||
4 => 'Apr',
|
||||
5 => 'May',
|
||||
6 => 'Jun',
|
||||
7 => 'Jul',
|
||||
8 => 'Aug',
|
||||
9 => 'Sep',
|
||||
10 => 'Oct',
|
||||
11 => 'Nov',
|
||||
12 => 'Dec',
|
||||
];
|
||||
|
||||
/**
|
||||
* a simple wrapper for the date format
|
||||
* if an invalid timestamp is give zero timestamp unix time is used
|
||||
*
|
||||
* @param int|float $timestamp unix timestamp
|
||||
* @param bool $show_micro show the micro time (default false)
|
||||
* @param bool $micro_as_float Add the micro time with . instead
|
||||
* of ms (default false)
|
||||
* @return string formated date+time in Y-M-D h:m:s ms
|
||||
*/
|
||||
public static function dateStringFormat(
|
||||
$timestamp,
|
||||
bool $show_micro = false,
|
||||
bool $micro_as_float = false
|
||||
): string {
|
||||
// split up the timestamp, assume . in timestamp
|
||||
// array pad $ms if no microtime
|
||||
list ($timestamp, $ms) = array_pad(explode('.', (string)round($timestamp, 4)), 2, null);
|
||||
$string = date("Y-m-d H:i:s", (int)$timestamp);
|
||||
if ($show_micro && $ms) {
|
||||
if ($micro_as_float == false) {
|
||||
$string .= ' ' . $ms . 'ms';
|
||||
} else {
|
||||
$string .= '.' . $ms;
|
||||
}
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* formats a timestamp into interval, not into a date
|
||||
*
|
||||
* @param string|int|float $timestamp interval in seconds and optional
|
||||
* float micro seconds
|
||||
* @param bool $show_micro show micro seconds, default true
|
||||
* @return string interval formatted string or string as is
|
||||
*/
|
||||
public static function timeStringFormat($timestamp, bool $show_micro = true): string
|
||||
{
|
||||
// check if the timestamp has any h/m/s/ms inside, if yes skip
|
||||
if (!preg_match("/(h|m|s|ms)/", (string)$timestamp)) {
|
||||
list($timestamp, $ms) = array_pad(explode('.', (string)round((float)$timestamp, 4)), 2, null);
|
||||
// if negative remember
|
||||
$negative = false;
|
||||
if ((int)$timestamp < 0) {
|
||||
$negative = true;
|
||||
}
|
||||
$timestamp = abs((float)$timestamp);
|
||||
$timegroups = [86400, 3600, 60, 1];
|
||||
$labels = ['d', 'h', 'm', 's'];
|
||||
$time_string = '';
|
||||
// if timestamp is zero, return zero string
|
||||
if ($timestamp == 0) {
|
||||
$time_string = '0s';
|
||||
} else {
|
||||
for ($i = 0, $iMax = count($timegroups); $i < $iMax; $i++) {
|
||||
$output = floor((float)$timestamp / $timegroups[$i]);
|
||||
$timestamp = (float)$timestamp % $timegroups[$i];
|
||||
// output has days|hours|min|sec
|
||||
if ($output || $time_string) {
|
||||
$time_string .= $output . $labels[$i] . (($i + 1) != count($timegroups) ? ' ' : '');
|
||||
}
|
||||
}
|
||||
}
|
||||
// only add ms if we have an ms value
|
||||
if ($ms !== null) {
|
||||
// if we have ms and it has leading zeros, remove them, but only if it is nut just 0
|
||||
$ms = preg_replace("/^0+(\d+)$/", '${1}', $ms);
|
||||
if (!is_string($ms) || empty($ms)) {
|
||||
$ms = '0';
|
||||
}
|
||||
// add ms if there
|
||||
if ($show_micro) {
|
||||
$time_string .= ' ' . $ms . 'ms';
|
||||
} elseif (!$time_string) {
|
||||
$time_string .= $ms . 'ms';
|
||||
}
|
||||
}
|
||||
if ($negative) {
|
||||
$time_string = '-' . $time_string;
|
||||
}
|
||||
} else {
|
||||
$time_string = $timestamp;
|
||||
}
|
||||
return (string)$time_string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public static function stringToTime($timestring)
|
||||
{
|
||||
$timestamp = 0;
|
||||
if (preg_match("/(d|h|m|s|ms)/", (string)$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);
|
||||
// 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 ($negative) {
|
||||
// cast to flaot so we can do a negative multiplication
|
||||
$timestamp = (float)$timestamp * -1;
|
||||
}
|
||||
return $timestamp;
|
||||
} else {
|
||||
return $timestring;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns long or short day of week name based on ISO day of week number
|
||||
* 1: Monday
|
||||
* ...
|
||||
* 7: Sunday
|
||||
*
|
||||
* @param int $isodow 1: Monday, 7: Sunday
|
||||
* @param bool $long Default false 'Mon', if true 'Monday'
|
||||
* @return string Day of week string either short 'Mon' or long 'Monday'
|
||||
*/
|
||||
public static function setWeekdayNameFromIsoDow(int $isodow, bool $long = false): string
|
||||
{
|
||||
// if not valid, set to invalid
|
||||
if ($isodow < 1 || $isodow > 7) {
|
||||
return $long ? 'Invalid' : 'Inv';
|
||||
}
|
||||
return date($long ? 'l' : 'D', strtotime("Sunday +{$isodow} days") ?: null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the day of week Name from date
|
||||
*
|
||||
* @param string $date Any valid date
|
||||
* @param bool $long Default false 'Mon', if true 'Monday'
|
||||
* @return string Day of week string either short 'Mon' or long 'Monday'
|
||||
*/
|
||||
public static function setWeekdayNameFromDate(string $date, bool $long = false): string
|
||||
{
|
||||
if (!self::checkDate($date)) {
|
||||
return $long ? 'Invalid' : 'Inv';
|
||||
}
|
||||
return date($long ? 'l' : 'D', strtotime($date) ?: null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the day of week Name from date
|
||||
*
|
||||
* @param string $date Any valid date
|
||||
* @return int ISO Weekday number 1: Monday, 7: Sunday, -1 for invalid date
|
||||
*/
|
||||
public static function setWeekdayNumberFromDate(string $date): int
|
||||
{
|
||||
if (!self::checkDate($date)) {
|
||||
return -1;
|
||||
}
|
||||
return (int)date('N', strtotime($date) ?: null);
|
||||
}
|
||||
|
||||
/**
|
||||
* splits & checks date, wrap around for check_date function
|
||||
*
|
||||
* @param string $date a date string in the format YYYY-MM-DD
|
||||
* @return bool true if valid date, false if date not valid
|
||||
*/
|
||||
public static function checkDate($date): bool
|
||||
{
|
||||
if (!$date) {
|
||||
return false;
|
||||
}
|
||||
list ($year, $month, $day) = array_pad(
|
||||
preg_split("/[\/-]/", $date) ?: [],
|
||||
3,
|
||||
null
|
||||
);
|
||||
if (!$year || !$month || !$day) {
|
||||
return false;
|
||||
}
|
||||
if (!checkdate((int)$month, (int)$day, (int)$year)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* splits & checks date, wrap around for check_date function
|
||||
*
|
||||
* @param string $datetime date (YYYY-MM-DD) + time (HH:MM:SS), SS can be dropped
|
||||
* @return bool true if valid date, false if date not valid
|
||||
*/
|
||||
public static function checkDateTime(string $datetime): bool
|
||||
{
|
||||
if (!$datetime) {
|
||||
return false;
|
||||
}
|
||||
// catch last overflow if sec has - in front
|
||||
list ($year, $month, $day, $hour, $min, $sec, $sec_overflow) = array_pad(
|
||||
preg_split("/[\/\- :]/", $datetime) ?: [],
|
||||
7,
|
||||
null
|
||||
);
|
||||
if (!$year || !$month || !$day) {
|
||||
return false;
|
||||
}
|
||||
if (!checkdate((int)$month, (int)$day, (int)$year)) {
|
||||
return false;
|
||||
}
|
||||
if (!is_numeric($hour) || !is_numeric($min)) {
|
||||
return false;
|
||||
}
|
||||
if (!empty($sec) && !is_numeric($sec)) {
|
||||
return false;
|
||||
}
|
||||
if (!empty($sec) && ($sec < 0 || $sec > 60)) {
|
||||
return false;
|
||||
};
|
||||
// in case we have - for seconds
|
||||
if (!empty($sec_overflow)) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
($hour < 0 || $hour > 24) ||
|
||||
($min < 0 || $min > 60)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* compares two dates, tries to convert them via strtotime to timestamps
|
||||
* returns int/bool in:
|
||||
* -1 if the first date is smaller the last
|
||||
* 0 if both are equal
|
||||
* 1 if the first date is bigger than the last
|
||||
* false if date validation/conversion failed
|
||||
*
|
||||
* @param string $start_date start date string in YYYY-MM-DD
|
||||
* @param string $end_date end date string in YYYY-MM-DD
|
||||
* @return int|bool false on error
|
||||
* or int -1 (s<e)/0 (s=e)/1 (s>e) as difference
|
||||
*/
|
||||
public static function compareDate($start_date, $end_date)
|
||||
{
|
||||
// pre check for empty or wrong
|
||||
if ($start_date == '--' || $end_date == '--' || !$start_date || !$end_date) {
|
||||
return false;
|
||||
}
|
||||
// if invalid, quit
|
||||
if (($start_timestamp = strtotime($start_date)) === false) {
|
||||
return false;
|
||||
}
|
||||
if (($end_timestamp = strtotime($end_date)) === false) {
|
||||
return false;
|
||||
}
|
||||
// convert anything to Y-m-d and then to timestamp
|
||||
// this is to remove any time parts
|
||||
$start_timestamp = strtotime(date('Y-m-d', $start_timestamp));
|
||||
$end_timestamp = strtotime(date('Y-m-d', $end_timestamp));
|
||||
// compare, or end with false
|
||||
if ($start_timestamp < $end_timestamp) {
|
||||
return -1;
|
||||
} elseif ($start_timestamp == $end_timestamp) {
|
||||
return 0;
|
||||
} elseif ($start_timestamp > $end_timestamp) {
|
||||
return 1;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* compares the two dates + times. if seconds missing in one set,
|
||||
* adds :00, converts date + times via strtotime to timestamps
|
||||
* returns int/bool in:
|
||||
* -1 if the first date is smaller the last
|
||||
* 0 if both are equal
|
||||
* 1 if the first date is bigger than the last
|
||||
* false if date/times validation/conversion failed
|
||||
*
|
||||
* @param string $start_datetime start date/time in YYYY-MM-DD HH:mm:ss
|
||||
* @param string $end_datetime end date/time in YYYY-MM-DD HH:mm:ss
|
||||
* @return int|bool false for error
|
||||
* or -1 (s<e)/0 (s=e)/1 (s>e) as difference
|
||||
*/
|
||||
public static function compareDateTime($start_datetime, $end_datetime)
|
||||
{
|
||||
// pre check for empty or wrong
|
||||
if ($start_datetime == '--' || $end_datetime == '--' || !$start_datetime || !$end_datetime) {
|
||||
return false;
|
||||
}
|
||||
// quit if invalid timestamp
|
||||
if (($start_timestamp = strtotime($start_datetime)) === false) {
|
||||
return false;
|
||||
}
|
||||
if (($end_timestamp = strtotime($end_datetime)) === false) {
|
||||
return false;
|
||||
}
|
||||
// compare, or return false
|
||||
if ($start_timestamp < $end_timestamp) {
|
||||
return -1;
|
||||
} elseif ($start_timestamp == $end_timestamp) {
|
||||
return 0;
|
||||
} elseif ($start_timestamp > $end_timestamp) {
|
||||
return 1;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* calculates the days between two dates
|
||||
* return: overall days, week days, weekend days as array 0...2 or named
|
||||
* as overall, weekday and weekend
|
||||
*
|
||||
* @param string $start_date valid start date (y/m/d)
|
||||
* @param string $end_date valid end date (y/m/d)
|
||||
* @param bool $return_named return array type, false (default), true for named
|
||||
* @return array<mixed> 0/overall, 1/weekday, 2/weekend
|
||||
*/
|
||||
public static function calcDaysInterval($start_date, $end_date, bool $return_named = false): array
|
||||
{
|
||||
// pos 0 all, pos 1 weekday, pos 2 weekend
|
||||
$days = [];
|
||||
// if anything invalid, return 0,0,0
|
||||
try {
|
||||
$start = new \DateTime($start_date);
|
||||
$end = new \DateTime($end_date);
|
||||
} catch (Exception $e) {
|
||||
if ($return_named === true) {
|
||||
return [
|
||||
'overall' => 0,
|
||||
'weekday' => 0,
|
||||
'weekend' => 0,
|
||||
];
|
||||
} else {
|
||||
return [0, 0, 0];
|
||||
}
|
||||
}
|
||||
// so we include the last day too, we need to add +1 second in the time
|
||||
$end->setTime(0, 0, 1);
|
||||
// if end date before start date, only this will be filled
|
||||
$days[0] = $end->diff($start)->days;
|
||||
$days[1] = 0;
|
||||
$days[2] = 0;
|
||||
// get period for weekends/weekdays
|
||||
$period = new \DatePeriod($start, new \DateInterval('P1D'), $end);
|
||||
foreach ($period as $dt) {
|
||||
$curr = $dt->format('D');
|
||||
if ($curr == 'Sat' || $curr == 'Sun') {
|
||||
$days[2] ++;
|
||||
} else {
|
||||
$days[1] ++;
|
||||
}
|
||||
}
|
||||
if ($return_named === true) {
|
||||
return [
|
||||
'overall' => $days[0],
|
||||
'weekday' => $days[1],
|
||||
'weekend' => $days[2],
|
||||
];
|
||||
} else {
|
||||
return $days;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// __END__
|
||||
Reference in New Issue
Block a user