986 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			986 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?PHP
 | |
| /**
 | |
|  * Splits nodac times.
 | |
|  *
 | |
|  * @author Joshua Ramon Enslin <joshua@museum-digital.de>
 | |
|  */
 | |
| 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",
 | |
|         "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<string> $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}";
 | |
|         }
 | |
|         else if (\intval($moda[2]) !== 0 and \intval($moda[3]) !== 0) {
 | |
|             return "{$prefix}{$moda[3]}.{$moda[2]}.{$moda[0]}{$suffix}";
 | |
|         }
 | |
|         else if ($moda[0] === $moda[1] && trim((string)$moda[2], " 0") === "" && trim((string)$moda[3], " 0") === "") {
 | |
|             return "{$prefix}{$moda[0]}{$suffix}";
 | |
|         }
 | |
|         else if ($moda[0] === $moda[1] && trim((string)$moda[2], " 0") !== "" && trim((string)$moda[3], " 0") === "") {
 | |
|             setlocale(LC_TIME, NodaTimeAutotranslater::LANGS_TO_LOCALES['de']);
 | |
|             return $prefix . strftime(getMonthFormatByLang("de"), MD_STD::strtotime("{$moda[0]}-{$moda[2]}-01 01:01:01")) . $suffix;
 | |
|         }
 | |
| 
 | |
|         return "";
 | |
| 
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Generates counting year - the middle between start and end year.
 | |
|      *
 | |
|      * @param array<string> $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<string> $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 = '<hr>';
 | |
|         $output .= '<table>';
 | |
|         $output .= '<tr><td width="250px">' . $tlLoader->tl("tempi", "tempi", "time_tool") . '</td>';
 | |
|         $output .= '<td><a href="tempi_md/zeit_cha.php?znum=' . $znum . '&kontrolle=todo';
 | |
|         if (($newTimeName = self::timePartsToTimeName($moda)) !== "") {
 | |
|             $output .= "&zeit_name_neu={$newTimeName}";
 | |
|         }
 | |
|         $output .= '&zeit_beginn_neu=' . $moda[0] . '&zeit_ende_neu=' . $moda[1] . '&zeit_zaehlzeit_vorzeichen_neu=' . urlencode($moda[4]) . '&zeit_zaehlzeit_jahr_neu=' . $zaehlzeit_jahr . '&zeit_zaehlzeit_monat_neu=' . $moda[2] . '&zeit_zaehlzeit_tag_neu=' . $moda[3] . '&zeit_status_neu=%2B" class="icons iconsBell buttonLike" id="splitTimeLink">+';
 | |
| 
 | |
|         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") . '</a></td>';
 | |
|         $output .= '</tr>';
 | |
|         $output .= '</table>';
 | |
| 
 | |
|         return $output;
 | |
| 
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Checks if any string of a list occurs in the haystack input string.
 | |
|      *
 | |
|      * @param string        $haystack Haystack.
 | |
|      * @param array<string> $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<string>
 | |
|      */
 | |
|     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], '-', ""];
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         $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;
 | |
| 
 | |
|         foreach (self::MONTH_NAMES_ENGLISH as $monthVal => $monthValidNames) {
 | |
|             if (self::stri_occurs($datum, $monthValidNames)) {
 | |
|                 if (!empty($monat)) return [];
 | |
|                 $monat = (string)$monthVal;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         foreach (self::MONTH_NAMES_GERMAN 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, 3, 2))) $monat = \substr($datum, 3, 2);
 | |
| 
 | |
|         if (self::is_numeric((string)\substr($datum, 0, 2))) $day = \substr($datum, 0, 2);
 | |
|         else if (\substr($datum, 1, 1) === "." and self::is_numeric((string)\substr($datum, 0, 1))) $day = "0" . \substr($datum, 0, 1);
 | |
| 
 | |
|         if (self::is_numeric((string)\substr($datum, -4))) $year = \substr($datum, -4);
 | |
| 
 | |
|         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<string>
 | |
|      */
 | |
|     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 [];
 | |
|         }
 | |
| 
 | |
|         if (strlen($datum) <= 9) 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 (\substr($datum, -2, 1) === " " and self::is_numeric((string)\substr($datum, -1, 1))) {
 | |
|             $day = "0" . \substr($datum, -1, 1);
 | |
|         }
 | |
|         else if ((empty($day)) and \substr($datum, -3, 1) === " " and self::is_numeric((string)\substr($datum, -2, 1))) {
 | |
|             $day = "0" . \substr($datum, -2, 1);
 | |
|         }
 | |
| 
 | |
|         if (self::is_numeric((string)\substr($datum, 0, 4))) $year = \substr($datum, 0, 4);
 | |
| 
 | |
|         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<string>
 | |
|      */
 | |
|     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<string>
 | |
|      */
 | |
|     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<string>
 | |
|      */
 | |
|     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)$/", $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<string>
 | |
|      */
 | |
|     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<string>
 | |
|      */
 | |
|     public static function is_century(string $datum):array {
 | |
| 
 | |
|         $datum = self::clean_input($datum);
 | |
|         $bcBceIndicator = '+';
 | |
| 
 | |
|         // 17. Jahrhundert
 | |
|         if (\preg_match("/^[0-9][0-9]\.\ (Jh\.|Jahrhundert|sz|század)$/", $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 (($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<string>
 | |
|      */
 | |
|     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(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 [];
 | |
| 
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Wrapper to check if any splitting command works.
 | |
|      *
 | |
|      * @param string $datum Input date.
 | |
|      *
 | |
|      * @return array<string>
 | |
|      */
 | |
|     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);
 | |
| 
 | |
|         return $moda;
 | |
| 
 | |
|     }
 | |
| }
 |