*/ declare(strict_types = 1); /** * Class for splitting times. */ final class NodaTimeSplitter { const MONTH_NAMES_GERMAN = [ "01" => ['Januar', 'Jan.'], "02" => ['Februar', 'Feb'], "03" => ['März', 'Mrz.'], "04" => ['April', 'Apr.'], "05" => ['Mai'], "06" => ['Juni', 'Jun.'], "07" => ['Juli', 'Jul.'], "08" => ['August', 'Aug.'], "09" => ['September', 'Sep.', 'Sept.'], "10" => ['Oktober', 'Okt.'], "11" => ['November', 'Nov.'], "12" => ['Dezember', 'Dez.'], ]; const MONTH_NAMES_ENGLISH = [ "01" => ['January', 'Jan.'], "02" => ['February', 'Feb'], "03" => ['March', 'Mar.'], "04" => ['April', 'Apr.'], "05" => ['May'], "06" => ['June', 'Jun.'], "07" => ['July', 'Jul.'], "08" => ['August', 'Aug.'], "09" => ['September', 'Sep.', 'Sept.'], "10" => ['October', 'Oct.'], "11" => ['November', 'Nov.'], "12" => ['December', 'Dec.'], ]; const MONTH_NAMES_HUNGARIAN = [ "01" => ['január', 'jan'], "02" => ['február', 'feb'], "03" => ['március', 'mar.', 'már.'], "04" => ['április', 'apr.', 'ápr.'], "05" => ['május', 'maj.', 'máj.'], "06" => ['június', 'jun.', 'jún'], "07" => ['július', 'jul.', 'júl.'], "08" => ['augusztus', 'aug.'], "09" => ['szeptember', 'szp.'], "10" => ['október', 'okt.'], "11" => ['november', 'nov.'], "12" => ['december', 'dec.'], ]; const STRINGS_TO_CLEAN = [ "között" => "", "nach Christus" => "", "n. Christus" => "", "nach Chr." => "", "n. Chr." => "", "n.Chr." => "", // To clean "v.Chr." => "v. Chr.", "v. Chr" => "v. Chr.", "vor Christus" => "v. Chr.", ]; const STRINGS_TO_CLEAN_START = [ "V. " => "5. ", "IV. " => "4. ", "III. " => "3. ", "II. " => "2. ", "I. " => "1. ", ]; const STOP_STRINGS_GERMAN = [ "-", ",", ";", ":", "/", "(", ")", "[", "]", ", ", " und ", "nach ", "um ", "ca.", "ab ", "seit ", "bis ", "vor ", "anfang ", "ende ", ]; const STOP_STRINGS_HUNGARIAN = [ "-", ",", ";", ":", "/", "(", ")", "[", "]", "ca.", ", ", "-ig", "és", "eleje", "között", "töl", "tól", "januárig", "februárig", "márciusig", "vége", "végén", "áprilisig", "májusig", "júniusig", "júliusig", "augusztusig", "szeptemberig", "októberig", "novemberig", "decemberig", ]; /** * Cleans input strings by trimming obsolete stuff. * * @param string $input Input date name. * * @return string */ private static function clean_input(string $input):string { while (\strpos($input, " -") !== false) $input = \str_replace(" -", "-", $input); while (\strpos($input, "- ") !== false) $input = \str_replace("- ", "-", $input); $input = \strtr($input, self::STRINGS_TO_CLEAN); foreach (self::STRINGS_TO_CLEAN_START as $toCleanFrom => $toCleanTo) { if (strpos($input, $toCleanFrom) === 0) { $input = \str_replace($toCleanFrom, $toCleanTo, $input); } } while (strpos($input, "..") !== false) $input = \str_replace("..", ".", $input); return trim($input, ", [](){}"); } /** * Checks if a string is really numeric, not numeric + space, dot. * * @param string $input Input string. * * @return boolean */ private static function is_numeric(string $input):bool { if (\is_numeric($input) and \strpos($input, " ") === false and \strpos($input, ".") === false ) { return true; } return false; } /** * Validates a time substr. * * @param string $datum Date. * @param integer $start Start of substr. * @param integer $end End of substr. * * @return string */ private static function validateDateSubstr(string $datum, int $start, int $end = 10000):string { if ($start !== 0 && !\in_array(\substr($datum, $start - 1, 1), ["-", " ", "."], true) ) { return ""; } $output = \substr($datum, $start, $end); if (self::is_numeric($output)) return $output; return ""; } /** * Generates new time name based on moda. * * @param array $moda Date strings. * * @return string */ public static function timePartsToTimeName(array $moda):string { if (!empty($moda[5]) and $moda[5] === "Vor" and $moda[0] === "?") { if (empty(trim($moda[2], "0 "))) $moda[1] = \strval(\intval($moda[1]) + 1); $moda[0] = $moda[1]; $prefix = "Vor "; } else if (!empty($moda[5]) and $moda[5] === "Nach" and $moda[1] === "?") { if (empty(trim($moda[2], "0 "))) $moda[0] = \strval(\intval($moda[0]) - 1); $moda[1] = $moda[0]; $prefix = "Nach "; } else if ($moda[0] === "?") { $prefix = "Bis "; $moda[0] = $moda[1]; } else if ($moda[1] === "?") { $prefix = "Seit "; $moda[1] = $moda[0]; } else $prefix = ""; $moda[0] = \intval($moda[0]); $moda[1] = \intval($moda[1]); if ($moda[0] < 0 && $moda[1] < 0) { $suffix = " v. Chr."; } else if ($moda[1] < 1000) { $suffix = " n. Chr."; } else $suffix = ""; $moda[0] = \abs($moda[0]); $moda[1] = \abs($moda[1]); if ($moda[0] !== $moda[1]) { return "{$prefix}{$moda[0]}-{$moda[1]}{$suffix}"; } // A single day of a given month of a given (single) year else if (\intval($moda[2]) !== 0 and \intval($moda[3]) !== 0) { return "{$prefix}{$moda[3]}.{$moda[2]}.{$moda[0]}{$suffix}"; } // A single year else if ($moda[0] === $moda[1] && trim((string)$moda[2], " 0") === "" && trim((string)$moda[3], " 0") === "") { return "{$prefix}{$moda[0]}{$suffix}"; } // Single month of a given year else if ($moda[0] === $moda[1] && trim((string)$moda[2], " 0") !== "" && trim((string)$moda[3], " 0") === "") { $fmt = new IntlDateFormatter( 'de-DE', IntlDateFormatter::FULL, IntlDateFormatter::FULL, null, IntlDateFormatter::GREGORIAN, 'MMMM Y' ); try { return $prefix . $fmt->format(MD_STD::strtotime("{$moda[0]}-{$moda[2]}-10 01:01:01")) . $suffix; } catch (MDInvalidInputDate $e) { return ""; } } return ""; } /** * Generates counting year - the middle between start and end year. * * @param array $moda Date strings. * * @return integer */ public static function timePartsToCountingYear(array $moda):int { if ($moda[0] === "?") { if (!empty($moda[5]) and $moda[5] === "Vor" and empty(trim($moda[2], " 0"))) { return \abs(\intval($moda[1])) + 1; } return \abs(\intval($moda[1])); } if ($moda[1] === "?") { if (!empty($moda[5]) and $moda[5] === "Nach" and empty(trim($moda[2], " 0"))) { return \abs(\intval($moda[0])) - 1; } return \abs(\intval($moda[0])); } return \abs((int)\ceil(\intval($moda[1]) - ((\intval($moda[1]) - \intval($moda[0])) / 2))); } /** * Generates HTML for linking disassembly of times for a single day. * * @param integer $znum Time ID. * @param array $moda Date strings. * @param MDTlLoader $tlLoader Translation loader. * * @return string */ public static function generateDisassemblyForDay(int $znum, array $moda, MDTlLoader $tlLoader):string { $zaehlzeit_jahr = self::pad_to_four((string)self::timePartsToCountingYear($moda)); // Wenn Datum in Form von tt.mm.jjjj, dann biete zerlegen an $output = '
'; $output .= ''; $output .= ''; $output .= ''; $output .= ''; $output .= '
' . $tlLoader->tl("tempi", "tempi", "time_tool") . '+'; if (!empty($newTimeName)) { $output .= $newTimeName; } else { if (!empty(trim($moda[3], " 0")) and !empty(trim($moda[2], " 0"))) $output .= $moda[3] . '.' . $moda[2] . '.' . $moda[0]; else if ($moda[0] !== $moda[1]) $output .= $moda[0] . "-" . $moda[1]; else if (!empty(trim($moda[2], " 0"))) $output .= "{$moda[2]}.{$moda[0]}"; else $output .= $moda[0]; } $output .= ' - ' . $tlLoader->tl("tempi", "tempi", "time_disassemble") . '
'; return $output; } /** * Checks if any string of a list occurs in the haystack input string. * * @param string $haystack Haystack. * @param array $needles Needles. * * @return boolean */ private static function stri_occurs(string $haystack, array $needles):bool { foreach ($needles as $needle) { if (stripos($haystack, $needle) !== false) return true; } return false; } /** * Pads to four digits. E.g. 20 > 0020. * * @param string $input Input string. * * @return string */ public static function pad_to_four(string $input):string { return \substr("0000" . $input, -4); } /** * Pads to four digits. E.g. 2 > 02. * * @param string $input Input string. * * @return string */ public static function pad_to_two(string $input):string { return \substr("00" . $input, -2); } /** * Translate German month to two digits number. * * @param string $datum Date. * * @return array */ public static function is_valid_date(string $datum):array { $datum = self::clean_input($datum); if (\preg_match("/\ v\.\ Chr\.$/", $datum)) { if ($output = self::attempt_splitting(\substr($datum, 0, -8))) { $start = \strval(-1 * \intval($output[1])); $end = \strval(-1 * \intval($output[0])); if (\intval($start) > \intval($end)) { $startToSet = $end; $end = $start; $start = $startToSet; } return [$start, $end, $output[2], $output[3], '-', ""]; } } if (\preg_match("/^[0-9][0-9][0-9][0-9]\ bis [0-9][0-9][0-9][0-9]$/", $datum)) { $start = \substr($datum, 0, 4); $end = \substr($datum, -4); return [$start, $end, "00", "00", "+", ""]; } $datum = \str_replace(". ", ".", $datum); if (self::stri_occurs($datum, self::STOP_STRINGS_GERMAN)) { return []; } if (strlen($datum) <= 6) return []; if (strlen($datum) <= 9) $use_day = false; else $use_day = true; if (self::is_numeric((string)\substr($datum, -4))) $year = \substr($datum, -4); // Further code requires a year to be present, skip if none is set if (empty($year)) return []; foreach (self::MONTH_NAMES_ENGLISH as $monthVal => $monthValidNames) { if (self::stri_occurs($datum, $monthValidNames)) { if (!empty($monat)) break; $monat = (string)$monthVal; } } foreach (self::MONTH_NAMES_GERMAN as $monthVal => $monthValidNames) { if (self::stri_occurs($datum, $monthValidNames)) { if (!empty($monat)) break; $monat = (string)$monthVal; } } if (empty($monat) and self::is_numeric((string)\substr($datum, 3, 2))) $monat = \substr($datum, 3, 2); if (self::is_numeric((string)\substr($datum, 0, 2))) { $day = \substr($datum, 0, 2); } else if (\in_array(\substr($datum, 1, 1), [".", " "]) && self::is_numeric((string)\substr($datum, 0, 1))) { $day = "0" . \substr($datum, 0, 1); } if (!empty($year) and !empty($monat) and !empty($day) and $use_day) { return [$year, $year, $monat, $day, '+', ""]; } else if (!empty($year) and !empty($monat)) { return [$year, $year, $monat, "00", '+', ""]; } return []; } /** * Translate Hungarian month to two digits number. * * @param string $datum Date. * * @return array */ public static function is_valid_date_hungarian(string $datum):array { $datum = self::clean_input($datum); if (\preg_match("/^Kr\.\ e\.\ /", $datum)) { if ($output = self::attempt_splitting(\substr($datum, 7))) { $start = \strval(-1 * \intval($output[1])); $end = \strval(-1 * \intval($output[0])); if (\intval($start) > \intval($end)) { $startToSet = $end; $end = $start; $start = $startToSet; } return [$start, $end, $output[2], $output[3], '-', ""]; } } if (\preg_match("/^[0-9][0-9][0-9][0-9]\-t(ő|ó)l(\ |\-)[0-9][0-9][0-9][0-9]\-ig$/", $datum)) { $start = \substr($datum, 0, 4); $end = \substr($datum, -7, 4); return [$start, $end, "00", "00", "+", ""]; } if (self::stri_occurs($datum, self::STOP_STRINGS_HUNGARIAN)) { return []; } // // Rest: Only those entries, where there are spelled out months // if (strlen($datum) <= 9) return []; // The year is only parse-able if it is a four digit year at the start if (self::is_numeric((string)\substr($datum, 0, 4))) { $year = \substr($datum, 0, 4); } // Further code requires a year to be present, skip if none is set if (empty($year)) return []; foreach (self::MONTH_NAMES_HUNGARIAN as $monthVal => $monthValidNames) { if (self::stri_occurs($datum, $monthValidNames)) { if (!empty($monat)) return []; $monat = (string)$monthVal; } } if (empty($monat) and self::is_numeric((string)\substr($datum, 5, 2))) $monat = \substr($datum, 5, 2); else if (empty($monat) and self::is_numeric((string)\substr($datum, 6, 2))) $monat = \substr($datum, 6, 2); $day = self::validateDateSubstr($datum, -2); if (empty($day)) $day = self::validateDateSubstr($datum, -3, 2); if (empty($day)) $day = self::validateDateSubstr($datum, -4, 2); if (empty($day)) $day = self::validateDateSubstr($datum, -5, 2); if (empty($day)) $day = self::validateDateSubstr($datum, -6, 2); if (empty($day)) { if (\substr($datum, -2, 1) === " " and self::is_numeric((string)\substr($datum, -1, 1))) { $day = "0" . \substr($datum, -1, 1); } else if (\substr($datum, -3, 1) === " " and self::is_numeric((string)\substr($datum, -2, 1))) { $day = "0" . \substr($datum, -2, 1); } } if (!empty($year) and !empty($monat) and !empty($day)) { return [$year, $year, $monat, $day, '+', ""]; } else if (!empty($year) and !empty($monat)) { return [$year, $year, $monat, "00", '+', ""]; } return []; } /** * Translate German month to two digits number. * * @param string $datum Date. * * @return array */ public static function is_valid_date_by_php(string $datum):array { $datum = self::clean_input($datum); if (!($timeInt = \strtotime($datum))) { return []; } return [\date("Y", $timeInt), \date("m", $timeInt), \date("d", $timeInt), '+', ""]; } /** * Checks if an input date is a timespan. * * @param string $datum Input date. * * @return array */ public static function is_timespan(string $datum):array { $datum = self::clean_input($datum); // 10000-20000 if (!empty(\preg_match("/^[0-9]{5}(\-|\/)[0-9]{5}$/", $datum))) { $start = \substr($datum, 0, 5); $end = \substr($datum, 6, 5); return [$start, $end, "00", "00", "+", ""]; } // 0000-0000 if (\preg_match("/^[0-9]{4}(\-|\/)[0-9]{4}(\.|)$/", $datum)) { $start = \substr($datum, 0, 4); $end = \substr($datum, 5, 4); return [$start, $end, "00", "00", "+", ""]; } if (\preg_match("/^[0-9]\.[0-9][0-9][0-9](\-|\/)[0-9]\.[0-9][0-9][0-9]$/", $datum)) { $datum = \str_replace(".", "", $datum); $start = \substr($datum, 0, 4); $end = \substr($datum, 5, 4); return [$start, $end, "00", "00", "+", ""]; } // German TT.MM.JJJJ / TT.MM.JJJ / TT.MM.JJ / TT.MM.J if (\preg_match("/^[0-9][0-9]\.[0-9][0-9]\.([0-9][0-9][0-9][0-9]|[0-9][0-9][0-9]|[0-9][0-9]|[0-9])$/", $datum)) { // German T.MM.JJJJ $start = \substr($datum, 6, 4); $month = \substr($datum, 3, 2); $day = \substr($datum, 0, 2); return [$start, $start, $month, $day, "+", ""]; } // German TT.M.JJJJ / TT.M.JJJ / TT.M.JJ / TT.M.J if (\preg_match("/^[0-9][0-9]\.[0-9]\.([0-9][0-9][0-9][0-9]|[0-9][0-9][0-9]|[0-9][0-9]|[0-9])$/", $datum)) { // German T.MM.JJJJ $start = \substr($datum, 5, 4); $month = "0" . \substr($datum, 3, 1); $day = \substr($datum, 0, 2); return [$start, $start, $month, $day, "+", ""]; } // German T.MM.JJJJ / T.MM.JJJ / T.MM.JJ / T.MM.J if (\preg_match("/^[0-9]\.[0-9][0-9]\.([0-9][0-9][0-9][0-9]|[0-9][0-9][0-9]|[0-9][0-9]|[0-9])$/", $datum)) { $start = \substr($datum, 5, 4); $month = \substr($datum, 2, 2); $day = "0" . \substr($datum, 0, 1); return [$start, $start, $month, $day, "+", ""]; } // German T.M.JJJJ / T.M.JJJ / T.M.JJ / T.M.J if (\preg_match("/^[0-9]\.[0-9]\.([0-9][0-9][0-9][0-9]|[0-9][0-9][0-9]|[0-9][0-9]|[0-9])$/", $datum)) { $start = \substr($datum, 4, 4); $month = "0" . \substr($datum, 2, 1); $day = "0" . \substr($datum, 0, 1); return [$start, $start, $month, $day, "+", ""]; } // Intl': 2020-12-20 if (\preg_match("/^[0-9]{4}\-[0-9]{2}\-[0-9]{2}$/", $datum)) { // German Y-m $start = \substr($datum, 0, 4); $month = \substr($datum, 5, 2); if (\intval($month) < 13) { $day = \substr($datum, 8, 2); return [$start, $start, $month, $day, "+", ""]; } else { unset($start, $month); } } // Intl': 2020-12 if (\preg_match("/^[0-9]{4}\-[0-9]{2}$/", $datum)) { // German Y-m $start = \substr($datum, 0, 4); $month = \substr($datum, 5, 2); if (\intval($month) < 13) { return [$start, $start, $month, "00", "+", ""]; } else { unset($start, $month); } } // German MM.JJJJ if (\preg_match("/^[0-9]{2}\.[0-9]{4}$/", $datum)) { // German Y-m $start = \substr($datum, 3, 4); $month = \substr($datum, 0, 2); return [$start, $start, $month, "00", "+", ""]; } if (\preg_match("/^[0-9]\.[0-9]{4}$/", $datum)) { // German Y-m $start = \substr($datum, 2, 4); $month = "0" . \substr($datum, 0, 1); return [$start, $start, $month, "00", "+", ""]; } if (\preg_match("/^[0-9]{4}\.[0-9]{2}\.[0-9]{1,2}(\.|)$/", $datum)) { // Hungarian Y-m-d $start = \substr($datum, 0, 4); $month = \substr($datum, 5, 2); $day = self::pad_to_two(\substr($datum, 8, 2)); if (\intval($month) < 13) return [$start, $start, $month, $day, "+", ""]; } if (\preg_match("/^[0-9]{4}\.[0-9]{2}(\.|)$/", $datum)) { // Hungarian Y-m $start = \substr($datum, 0, 4); $month = \substr($datum, 5, 2); if (\intval($month) < 13) return [$start, $start, $month, "00", "+", ""]; } if (\preg_match("/^[0-9]{4}\-[0-9]{2}$/", $datum)) { // Time spans: 1945-46 $start = \substr($datum, 0, 4); $endDigits = \substr($datum, 5, 2); if (\intval($endDigits) > 12) return [$start, \substr($datum, 0, 2) . $endDigits, "00", "00", "+", ""]; } // 01.01.1920-31.12.1930 if (\preg_match("/^01\.01\.[0-9]{4}\-31\.12\.[0-9]{4}$/", $datum)) { // Hungarian Y-m $start = \substr($datum, 6, 4); $end = \substr($datum, -4); return [$start, $end, "00", "00", "+", ""]; } // 303-305 (n. Chr.) if (\preg_match("/^[0-9]{3}\-[0-9]{3}$/", $datum)) { // Hungarian Y-m $start = \substr($datum, 0, 3); $end = \substr($datum, -3); return ["0" . $start, "0" . $end, "00", "00", "+", ""]; } // 1720-120 if (\preg_match("/^[0-9]{4}\-[0-9]{3}$/", $datum)) { // Hungarian Y-m $start = \substr($datum, 0, 4); $end = \substr($datum, -3); return ["0" . $start, "0" . $end, "00", "00", "+", ""]; } // 20-30 (n. Chr.) if (\preg_match("/^[0-9]{2}\-[0-9]{2}$/", $datum)) { // 20-40 (n. Chr.) $start = \substr($datum, 0, 2); $end = \substr($datum, -2); return ["00" . $start, "00" . $end, "00", "00", "+", ""]; } // 1920 if (\preg_match("/^[0-9]{4}(\.|)$/", $datum)) { $start = \substr($datum, 0, 4); return [$start, $start, "00", "00", "+", ""]; } // 1920 if (\preg_match("/^[0-9]{3}$/", $datum)) { $start = "0" . \substr($datum, 0, 3); return [$start, $start, "00", "00", "+", ""]; } if (\preg_match("/^[0-9]{2}$/", $datum)) { $start = "00" . \substr($datum, 0, 2); return [$start, $start, "00", "00", "+", ""]; } // Special case for SMB: YYYY, MM. DD and YYYY, MM. if (\preg_match("/^[0-9]{4}\,\ [0-9]{2}\.(|\ [0-9]{2})$/", $datum)) { $start = \substr($datum, 0, 4); $month = \substr($datum, 6, 2); $day = self::pad_to_two(\substr($datum, 10, 2)); return [$start, $start, $month, $day, "+", ""]; } return []; } /** * Checks if an input date is an incomplete date: Before 1920, after 1930. * * @param string $datum Input date. * * @return array */ public static function is_incomplete_date(string $datum):array { $datum = self::clean_input($datum); if (\preg_match("/^[0-9]{4}\.[0-9]{2}\.[0-9]{2}(\.|)\-$/", $datum)) { // Hungarian Y-m $start = \substr($datum, 0, 4); $month = \substr($datum, 5, 2); $day = \substr($datum, 8, 2); return [$start, "?", $month, $day, "+", ""]; } if (\preg_match("/^[0-9]{4}\.[0-9]{2}(\.|)\-$/", $datum)) { // Hungarian Y-m $start = \substr($datum, 0, 4); $month = \substr($datum, 5, 2); return [$start, "?", $month, "00", "+", ""]; } if (\preg_match("/^[0-9]{4}\-$/", $datum)) { // Hungarian Y- $start = \substr($datum, 0, 4); return [$start, "?", "00", "00", "+", ""]; } if (\preg_match("/^\-[0-9]{4}\.[0-9]{2}\.[0-9]{2}$/", $datum)) { // Hungarian Y-m $start = \substr($datum, 1, 4); $month = \substr($datum, 6, 2); $day = \substr($datum, 9, 2); return ["?", $start, $month, $day, "+", ""]; } if (\preg_match("/^\-[0-9]{4}\.[0-9]{2}$/", $datum)) { // Hungarian Y-m $start = \substr($datum, 1, 4); $month = \substr($datum, 6, 2); return ["?", $start, $month, "00", "+", ""]; } if (\preg_match("/^\-[0-9]{4}$/", $datum)) { // Hungarian -Y $start = \substr($datum, 1, 4); return ["?", $start, "00", "00", "+", ""]; } if (\preg_match("/^(Nach|nach)\ /", $datum)) { if (($spacePos = \strpos($datum, " ")) === false) { return []; } if ($output = self::attempt_splitting(\substr($datum, $spacePos))) { // Handle cases like "Nach 60er Jahre" with divergent start and end year if ($output[1] !== $output[0] and \intval($output[1]) > \intval($output[0])) { $output[0] = $output[1]; } $output[1] = "?"; if (empty(trim($output[2], "0 .,"))) $output[0] = \strval(\intval($output[0]) + 1); $output[5] = "Nach"; return $output; } } if (\preg_match("/\ (\(nach|nach)$/", $datum)) { if (($spacePos = \strpos($datum, " ")) === false) { return []; } if ($output = self::attempt_splitting(\substr($datum, 0, $spacePos))) { // Handle cases like "Nach 60er Jahre" with divergent start and end year if ($output[1] !== $output[0] and \intval($output[1]) > \intval($output[0])) { $output[0] = $output[1]; } $output[1] = "?"; if (empty(trim($output[2], "0 .,"))) $output[0] = \strval(\intval($output[0]) + 1); $output[5] = "Nach"; return $output; } } if (\preg_match("/^(Vor|vor)\ /", $datum)) { if (($spacePos = \strpos($datum, " ")) === false) { return []; } if ($output = self::attempt_splitting(\substr($datum, $spacePos))) { $output[0] = "?"; if (empty(trim($output[2], "0 .,"))) $output[1] = \strval(\intval($output[1]) - 1); $output[5] = "Vor"; return $output; } } if (\preg_match("/\ (\(vor|\(Vor|vor)$/", $datum)) { if (($spacePos = \strpos($datum, " ")) === false) { return []; } if ($output = self::attempt_splitting(\substr($datum, 0, $spacePos))) { $output[0] = "?"; if (empty(trim($output[2], "0 .,"))) $output[1] = \strval(\intval($output[1]) - 1); $output[5] = "Vor"; return $output; } } if (\preg_match("/^(Ab|Seit|seit)\ /", $datum)) { if (($spacePos = \strpos($datum, " ")) === false) { return []; } if ($output = self::attempt_splitting(\substr($datum, $spacePos))) { $output[1] = "?"; return $output; } } // Endings beginning with a space if (\preg_match("/(\-től|\-tól)$/", $datum)) { if (($spacePos = strrpos($datum, "-")) === false) { return []; } if ($output = self::attempt_splitting(\substr($datum, 0, $spacePos))) { $output[1] = "?"; return $output; } } if (\preg_match("/^(Bis|bis)\ /", $datum)) { if (($spacePos = \strpos($datum, " ")) === false) { return []; } if ($output = self::attempt_splitting(\substr($datum, $spacePos))) { $output[0] = "?"; return $output; } } // Endings beginning with a space if (\preg_match("/ (\(bis)$/", $datum)) { if (($spacePos = strrpos($datum, " ")) === false) { return []; } if ($output = self::attempt_splitting(\substr($datum, 0, $spacePos))) { $output[0] = "?"; return $output; } } if (\preg_match("/\-ig(\.|)$/", $datum)) { if (($spacePos = strrpos($datum, "-")) === false) { return []; } if ($output = self::attempt_splitting(\substr($datum, 0, $spacePos))) { $output[0] = "?"; return $output; } } return []; } /** * Negotiates century spans before times. * * @param string $start Begin time. * @param string $end End time. * * @return array */ public static function negotiate_century_span_bce_ce(string $start, string $end):array { $start = \intval($start); $end = \intval($end); if ($start < $end) { return [(string)($start - 1) . "01", $end . "00", "00", "00", "+", ""]; } return [(string)($start) . "00", ($end - 1) . "01", "00", "00", "+", ""]; } /** * Checks if an input date is a century. * * @param string $datum Input date. * * @return array */ public static function is_century(string $datum):array { $datum = self::clean_input($datum); $bcBceIndicator = '+'; // 17. Jahrhundert if (\preg_match("/^[0-9]{2}\.\ (Jh\.|Jhd(|\.)|Jhdt(|\.)|Jahrhundert|sz|század)$/", $datum)) { if ($centuryNo = \intval(\substr($datum, 0, 2))) { $centuryNo--; return [(string)$centuryNo . "01", \strval($centuryNo + 1) . "00", "00", "00", $bcBceIndicator, ""]; } } // 17th century if (\preg_match("/^[0-9]{2}th century$/", $datum)) { if ($centuryNo = \intval(\substr($datum, 0, 2))) { $centuryNo--; return [(string)$centuryNo . "01", \strval($centuryNo + 1) . "00", "00", "00", $bcBceIndicator, ""]; } } // 1. Jahrhundert if (\preg_match("/^[0-9]\.\ (Jh\.|Jahrhundert|sz|század)$/", $datum)) { if ($centuryNo = \intval(\substr($datum, 0, 1))) { $centuryNo--; return [(string)$centuryNo . "01", \strval($centuryNo + 1) . "00", "00", "00", $bcBceIndicator, ""]; } } // 17.-18. Jahrhundert if (\preg_match("/^[0-9]{2}(\.|)(|\ Jh\.||\ Jahrhundert||\ sz||\ század)(\-|\/)[0-9]{2}\.\ (Jh\.|Jahrhundert|sz|század)$/", $datum)) { if (\strpos($datum, '/') !== false) { $datum = str_replace('/', '-', $datum); } if (($dashPos = \strpos($datum, "-")) !== false) { return self::negotiate_century_span_bce_ce(\substr($datum, 0, 2), \substr($datum, $dashPos + 1, 2)); } } // 1.-12. Jahrhundert if (\preg_match("/^[0-9](\.|)(|\ Jh\.||\ Jahrhundert||\ sz||\ század)\-[0-9]{2}\.\ (Jh\.|Jahrhundert|sz|század)$/", $datum)) { if (($dashPos = \strpos($datum, "-")) !== false) { return self::negotiate_century_span_bce_ce(\substr($datum, 0, 1), \substr($datum, $dashPos + 1, 2)); } } // 1.-2. Jahrhundert if (\preg_match("/^[0-9](\.|)(|\ Jh\.||\ Jahrhundert||\ sz||\ század)\-[0-9]\.\ (Jh\.|Jahrhundert|sz|század)$/", $datum)) { if (($dashPos = \strpos($datum, "-")) !== false) { return self::negotiate_century_span_bce_ce(\substr($datum, 0, 1), \substr($datum, $dashPos + 1, 1)); } } // 1-2. Jahrhundert if (\preg_match("/^[0-9](\.|)(|\ Jh\.||\ Jahrhundert||\ sz||\ század)\-[0-9]\.\ (Jh\.|Jahrhundert|sz|század)$/", $datum)) { if (($dashPos = \strpos($datum, "-")) !== false) { return self::negotiate_century_span_bce_ce(\substr($datum, 0, 1), \substr($datum, $dashPos + 1, 1)); } } return []; } /** * Checks if an input date is a decade. * * @param string $datum Input date. * * @return array */ public static function is_decade(string $datum):array { $datum = self::clean_input($datum); $bcBceIndicator = '+'; if (\preg_match("/^[0-9]0(er|er\ Jahre|\-es\ évek|\-as\ \évek)$/", $datum)) { $start = "19" . \substr($datum, 0, 2); $ende = (string)(\intval($start) + 9); return [$start, $ende, "00", "00", $bcBceIndicator, ""]; } if (\preg_match("/^[0-9]{3}0(s|er|er\ Jahre|\-es\ évek|\-as\ \évek)$/", $datum)) { $start = \substr($datum, 0, 4); $ende = (string)(\intval($start) + 9); return [$start, $ende, "00", "00", $bcBceIndicator, ""]; } return []; } /** * Checks if the string is a time span with given start and end dates. * * @param string $datum Date. * * @return array> */ public static function check_is_timespan_from_till(string $datum):array { if (substr_count($datum, '-') !== 1) return []; list($start_str, $end_str) = explode('-', $datum); if (empty($start = self::attempt_splitting($start_str))) { return []; } if (empty($end = self::attempt_splitting($end_str))) { return []; } return [$start, $end]; } /** * Checks if the string is a time span with given start and end dates. * * @param string $datum Date. * * @return array */ public static function attempt_splitting_from_till(string $datum):array { // Skip 1200-1300 if (!empty(self::attempt_splitting($datum))) return []; if (strlen($datum) === 9 and substr($datum, 4, 1) !== '-') return []; if (empty($startEnd = self::check_is_timespan_from_till($datum))) { return []; } list($start, $end) = $startEnd; if ($start[4] === '-') return []; try { $startDate = new DateTime($start[4] . $start[0] . '-' . $start[2] . '-' . $start[3]); $endDate = new DateTime($end[4] . $end[1] . '-' . $end[2] . '-' . $end[3]); } catch (Exception $e) { return []; } $interval = $startDate->diff($endDate); $days_diff = (int)$interval->format('%a'); $middle_substraction = round($days_diff / 2); if (!($startDateTimestamp = strtotime($startDate->format('Y-m-d')))) return []; if (!($middleDayTimestamp = strtotime('+' . $middle_substraction . ' days', $startDateTimestamp))) return []; $middle_day = date('Y-m-d', $middleDayTimestamp); $start_name = self::timePartsToTimeName($start); $end_name = self::timePartsToTimeName($end); if (strlen($start_name) === 9 and substr($start_name, 4, 1) === '-') $start_name = substr($start_name, 0, 4); if (strlen($end_name) === 9 and substr($end_name, 4, 1) === '-') $end_name = substr($end_name, 5, 4); $output = [ "start_name" => $start_name, "end_name" => $end_name, "start_year" => $start[0], "end_year" => $end[1], "counting_time_year" => substr($middle_day, 0, 4), "counting_time_month" => substr($middle_day, 5, 2), "counting_time_day" => substr($middle_day, 8, 2), "counting_time_bcce" => "+", ]; return $output; } /** * Wrapper to check if any splitting command works. * * @param string $datum Input date. * * @return array */ public static function attempt_splitting(string $datum):array { $moda = NodaTimeSplitter::is_timespan($datum); if (!$moda) $moda = NodaTimeSplitter::is_incomplete_date($datum); if (!$moda) $moda = NodaTimeSplitter::is_valid_date($datum); if (!$moda) $moda = NodaTimeSplitter::is_valid_date_hungarian($datum); if (!$moda) $moda = NodaTimeSplitter::is_century($datum); if (!$moda) $moda = NodaTimeSplitter::is_decade($datum); if (!empty($moda)) { if ((int)$moda[2] > 12 || (int)$moda[3] > 31) { return []; } } return $moda; } }