public static function init() { parent::init( self::$magicWordKeys, self::$substitutes, self::$magicWordArray, self::$flipMagicWordKeys ); self::$nothing = new self( self::nothing ); self::$spring = new self( self::spring ); self::$summer = new self( self::summer ); self::$autumn = new self( self::autumn ); self::$winter = new self( self::winter ); self::$AD = new self( self::AD ); self::$BC = new self( self::BC ); self::$yearTerm = new self( self::yearTerm ); self::$monthTerm = new self( self::monthTerm ); self::$dayTerm = new self( self::dayTerm ); self::$circa = new self( self::circa ); self::$number = new self( self::number ); self::$namedMonth = new self( self::namedMonth ); }
/** * Constructor. * @param WCCitation $citation = the WCCitation object * @param WCScopeEnum $scope = the scope (i.e., work, container, series, etc.) * @param WCParameterEnum $type = the type of property. * @param string date = the unprocessed date text. */ public function __construct( $date ) { # Separate into segments comprising numbers, letters, or special terms. $adTerms = MagicWord::get( WCDateTermsEnum::$magicWordKeys[ WCDateTermsEnum::AD ] )->getSynonyms(); $bcTerms = MagicWord::get( WCDateTermsEnum::$magicWordKeys[ WCDateTermsEnum::BC ] )->getSynonyms(); $circaTerms = MagicWord::get( WCDateTermsEnum::$magicWordKeys[ WCDateTermsEnum::circa ] )->getSynonyms(); $options = implode( '|', array_merge( $adTerms, $bcTerms, $circaTerms ) ); if ( !preg_match_all( '/'. $options . '|\p{N}+|\p{L}+|./uS', $date, $matches ) ) { $this->year = 0; $this->era = WCDateTermsEnum::AD; $this->month = 0; $this->day = 0; $this->isUncertain = True; return; } $chunks = $matches[0]; $numbers = $unknowns = array(); $years = $months = $days = array(); $eras = $seasons = $circas = $yearTerms = $monthTerms = $dayTerms = array(); $counter = 0; foreach( $chunks as $chunk ) { # Match month names. $month = $this->matchMonths( $chunk ); # $month is integer >= 1 or False if ( $month && count( $months ) < 2 ) { $months[ $counter ] = $month; $numbers[ $counter++ ] = new WCDateNumber( $counter, $month, WCDateNumber::month ); continue; } # Match date terms. $dateTermEnum = WCDateTermsEnum::match( $chunk, WCDateTermsEnum::$magicWordArray, WCDateTermsEnum::$flipMagicWordKeys, 'WCDateTermsEnum' ); if ( $dateTermEnum ) { switch ( $dateTermEnum->key ) { case WCDateTermsEnum::AD: if ( count( $eras ) < 2 ) { $eras[ $counter++ ] = WCDateTermsEnum::AD; } continue 2; case WCDateTermsEnum::BC: if ( count( $eras ) < 2 ) { $eras[ $counter++ ] = WCDateTermsEnum::BC; } continue 2; case WCDateTermsEnum::spring: if ( count( $seasons ) < 2 ) { $seasons[ $counter++ ] = WCDateTermsEnum::spring; } continue 2; case WCDateTermsEnum::summer: if ( count( $seasons ) < 2 ) { $seasons[ $counter++ ] = WCDateTermsEnum::summer; } continue 2; case WCDateTermsEnum::autumn: if ( count( $seasons ) < 2 ) { $seasons[ $counter++ ] = WCDateTermsEnum::autumn; } continue 2; case WCDateTermsEnum::winter: if ( count( $seasons ) < 2 ) { $seasons[ $counter++ ] = WCDateTermsEnum::winter; } continue 2; case WCDateTermsEnum::year: if ( count( $yearTerms ) < 2 ) { $yearTerms[ $counter++ ] = WCDateTermsEnum::yearTerm; } continue 2; case WCDateTermsEnum::month: if ( count( $monthTerms ) < 2 ) { $monthTerms[ $counter++ ] = WCDateTermsEnum::monthTerm; } continue 2; case WCDateTermsEnum::day: if ( count( $dayTerms ) < 2 ) { $dayTerms[ $counter++ ] = WCDateTermsEnum::dayTerm; } continue 2; case WCDateTermsEnum::circa: if ( count( $circas ) < 2 ) { $circas[ $counter++ ] = WCDateTermsEnum::circa; } continue 2; } } # Check for roman numerals (month is often Roman in Hungary, Poland, Romania). $intTerm = $this->romanToInt( $chunk ); # Convert to integer. if ( ! $intTerm ) { $intTerm = (integer) $chunk; # Note, this converts ordinals too. if ( ! $intTerm ) { # '00' cannot be month or day, so it must be the two-digit year 2000: if ( mb_substr( $chunk, 0, 2 ) == '00' ) { $numbers[ $counter ] = new WCDateNumber( $counter, 2000, WCDateNumber::year ); $years[ $counter ] = 2000; ++$counter; continue; } else { continue; # not a recognized number } } } $numbers[ $counter ] = $unknowns[ $counter ] = new WCDateNumber( $counter, $intTerm ); ++$counter; } # Look for and handle named Year/Month/Day labels foreach( $yearTerms as $yearTermKey => $yearTerm ) { if ( empty( $unknowns ) ) break; $unknown = $this->searchAdjacentTerm( $unknowns, $yearTermKey, $chunks ); if ( $unknown && count( $years ) < 2 ) { $years[ $unknown->key ] = $unknown->num; $unknown->setYear( $unknowns, $years ); } } foreach( $monthTerms as $monthTermKey => $monthTerm ) { if ( empty( $unknowns ) ) break; $unknown = $this->searchAdjacentTerm( $unknowns, $monthTermKey, $chunks ); if ( $unknown && count( $months ) < 2 ) { $months[ $unknown->key ] = $unknown->num; $unknown->setMonth( $unknowns, $months ); } } foreach( $dayTerms as $dayTermKey => $dayTerm ) { if ( empty( $unknowns ) ) break; $unknown = $this->searchAdjacentTerm( $unknowns, $dayTermKey, $chunks ); if ( $unknown && count( $days ) < 2 ) { $days[ $unknown->key ] = $unknown->num; $unknown->setDay( $unknowns, $days ); } } # If one or more seasons is specified, treat specially and return. if ( ! empty( $seasons ) ) { $this->season = reset( $seasons ); $season2 = next( $seasons ); # Only one season specified if ( $season2 === False || $season2 == $this->season ) { $isRange = False; # Determine year. if ( count( $years ) >= 1 ) { $year = reset( $years ); # Use first number as year $this->assignYearsAndEras( $eras, False, $year->num ); } elseif ( count( $unknowns ) >= 1 ) { $year = reset( $unknowns ); # Use first number as year $this->assignYearsAndEras( $eras, False, $year->num ); } else { $curDate = getdate(); $this->year = $curDate['year']; $this->era = WCDateTermsEnum::AD; } } # Two seasons specified else { $isRange = True; $this->season2 = $season2; # Determine year if ( count( $years ) >= 2 ) { $year = reset( $years )->num; $year2 = next( $years )->num; if ( $year2 == $year ) { $this->assignYearsAndEras( $eras, False, $year ); } else { $this->assignYearsAndEras( $eras, True, $year, $year2 ); } } elseif ( count( $years ) == 1 ) { $yearA = reset( $years )->num; if ( empty( $unknowns ) ) { $this->assignYearsAndEras( $eras, False, $yearA ); } else { $yearB = reset( $unknowns )->num; if ( $yearA == $yearB ) { $this->assignYearsAndEras( $eras, False, $yearA ); } elseif ( $yearA < $yearB ) { $this->assignYearsAndEras( $eras, True, $yearA, $yearB ); } else { $this->assignYearsAndEras( $eras, True, $yearB, $yearA ); } } } elseif ( count( $unknowns ) >= 2 ) { # Use first two numbers as years. $year = reset( $unknowns )->num; $year2 = next( $unknowns )->num; if ( $year2 == $year ) { $this->assignYearsAndEras( $eras, False, $year ); } else { $this->assignYearsAndEras( $eras, True, $year, $year2 ); } } elseif ( count( $unknowns ) == 1 ) { $year = reset( $unknowns )->num; $this->assignYearsAndEras( $eras, False, $year ); } else { $curDate = getdate(); $this->year = $curDate['year']; $this->era = WCDateTermsEnum::AD; } } $this->assignUncertainty( $circas, $isRange, $numbers, $chunks ); return; } # Handle numbers and/or named months. switch ( count( $numbers ) ) { case 0: /****** CASE 0 ******/ $this->finalizeDate( $days, $months, $years, $eras ); $this->assignUncertainty( $circas, False, $numbers, $chunks ); break; case 1: /****** CASE 1 ******/ /** Must be year */ if ( ! empty( $unknowns ) ) { reset( $unknowns ) -> setYear( $unknowns, $years ); } $this->finalizeDate( $days, $months, $years, $eras ); $this->assignUncertainty( $circas, False, $numbers, $chunks ); break; case 2: /****** CASE 2 ******/ /** Can be any of the following: * month-year * year-year * year-month */ $order1 = array( WCDateNumber::month, WCDateNumber::year ); $order2 = array( WCDateNumber::year, WCDateNumber::year ); $order3 = array( WCDateNumber::year, WCDateNumber::month ); if ( ! ( $this->monthUpTo12( $unknowns, $days, $years ) || $this->cannotBeDay( $unknowns, $months, $years ) || $this->yearAdjacentEra( $unknowns, $years, $eras, $chunks ) || $this->yearsInOrder( $unknowns, $days, $months, $years, $eras ) || $this->tryOrder( $unknowns, $days, $months, $years, $order1 ) || $this->tryOrder( $unknowns, $days, $months, $years, $order2 ) || $this->tryOrder( $unknowns, $days, $months, $years, $order3 ) ) ) { foreach( $unknowns as $unknownKey => $unknown ) { if ( empty( $months ) ) { $months[ $unknownKey ] = $unknown->num; } elseif ( count( $years ) < 2 ) { $years[ $unknownKey ] = $unknown->num; } } } $isRange = $this->finalizeDate( $days, $months, $years, $eras ); $this->assignUncertainty( $circas, $isRange, $numbers, $chunks ); break; case 3: /****** CASE 3 ******/ /** Can be any of the following: * day-month-year * month-day-year * year-month-day * month-month-year * year-month-month */ $order1 = array( WCDateNumber::day, WCDateNumber::month, WCDateNumber::year ); $order2 = array( WCDateNumber::month, WCDateNumber::day, WCDateNumber::year ); $order3 = array( WCDateNumber::year, WCDateNumber::month, WCDateNumber::day ); $order4 = array( WCDateNumber::month, WCDateNumber::month, WCDateNumber::year ); $order5 = array( WCDateNumber::year, WCDateNumber::month, WCDateNumber::month ); if ( ! ( $this->dayUpTo31( $unknowns, $months, $years ) || $this->monthUpTo12( $unknowns, $days, $years ) || $this->yearAdjacentEra( $unknowns, $years, $eras, $chunks ) || $this->yearsInOrder( $unknowns, $days, $months, $years, $eras ) || $this->tryOrder( $unknowns, $days, $months, $years, $order1 ) || $this->tryOrder( $unknowns, $days, $months, $years, $order2 ) || $this->tryOrder( $unknowns, $days, $months, $years, $order3 ) || $this->tryOrder( $unknowns, $days, $months, $years, $order4 ) || $this->tryOrder( $unknowns, $days, $months, $years, $order5 ) ) ) { foreach( $unknowns as $unknownKey => $unknown ) { if ( empty( $day ) ) { $days[ $unknownKey ] = $unknown->num; } elseif ( empty( $months ) ) { $months[ $unknownKey ] = $unknown->num; } elseif ( empty( $years ) ) { $years[ $unknownKey ] = $unknown->num; } else { $months[ $unknownKey ] = $unknown->num; } } } $isRange = $this->finalizeDate( $days, $months, $years, $eras ); $this->assignUncertainty( $circas, $isRange, $numbers, $chunks ); break; case 4: /****** CASE 4 ******/ /** Can be any of the following: * day-day-month-year * month-day-day-year * year-month-day-day * month-year-month-year * year-month-year-month */ $order1 = array( WCDateNumber::day, WCDateNumber::day, WCDateNumber::month, WCDateNumber::year ); $order2 = array( WCDateNumber::month, WCDateNumber::day, WCDateNumber::day, WCDateNumber::year ); $order3 = array( WCDateNumber::year, WCDateNumber::month, WCDateNumber::day, WCDateNumber::day ); $order4 = array( WCDateNumber::month, WCDateNumber::year, WCDateNumber::month, WCDateNumber::year ); $order5 = array( WCDateNumber::year, WCDateNumber::month, WCDateNumber::year, WCDateNumber::month ); if ( ! ( $this->dayUpTo31( $unknowns, $months, $years ) || $this->monthUpTo12( $unknowns, $days, $years ) || $this->yearAdjacentEra( $unknowns, $years, $eras, $chunks ) || $this->yearsInOrder( $unknowns, $days, $months, $years, $eras ) || $this->tryOrder( $unknowns, $days, $months, $years, $order1 ) || $this->tryOrder( $unknowns, $days, $months, $years, $order2 ) || $this->tryOrder( $unknowns, $days, $months, $years, $order3 ) || $this->tryOrder( $unknowns, $days, $months, $years, $order4 ) || $this->tryOrder( $unknowns, $days, $months, $years, $order5 ) ) ) { foreach( $unknowns as $unknownKey => $unknown ) { if ( count( $day ) < 2 ) { $days[ $unknownKey ] = $unknown->num; } elseif ( empty( $months ) ) { $months[ $unknownKey ] = $unknown->num; } elseif ( empty( $years ) ) { $years[ $unknownKey ] = $unknown->num; } elseif ( count( $months ) < 2 ) { $months[ $unknownKey ] = $unknown->num; } else { $years[ $unknownKey ] = $unknown->num; } } } $isRange = $this->finalizeDate( $days, $months, $years, $eras ); $this->assignUncertainty( $circas, $isRange, $numbers, $chunks ); break; case 5: /****** CASE 5 ******/ /** Can be any of the following: * day-month-day-month-year * month-day-month-day-year * year-month-day-month-day */ $order1 = array( WCDateNumber::day, WCDateNumber::month, WCDateNumber::day, WCDateNumber::month, WCDateNumber::year ); $order2 = array( WCDateNumber::month, WCDateNumber::day, WCDateNumber::month, WCDateNumber::day, WCDateNumber::year ); $order3 = array( WCDateNumber::year, WCDateNumber::month, WCDateNumber::day, WCDateNumber::month, WCDateNumber::day ); if ( ! ( $this->dayUpTo31( $unknowns, $months, $years ) || $this->monthUpTo12( $unknowns, $days, $years ) || $this->yearAdjacentEra( $unknowns, $years, $eras, $chunks ) || $this->yearsInOrder( $unknowns, $days, $months, $years, $eras ) || $this->tryOrder( $unknowns, $days, $months, $years, $order1 ) || $this->tryOrder( $unknowns, $days, $months, $years, $order2 ) || $this->tryOrder( $unknowns, $days, $months, $years, $order3 ) ) ) { foreach( $unknowns as $unknownKey => $unknown ) { if ( count( $day ) < 2 ) { $days[ $unknownKey ] = $unknown->num; } elseif ( count( $months ) < 2 ) { $months[ $unknownKey ] = $unknown->num; } else { $years[ $unknownKey ] = $unknown->num; } } } $isRange = $this->finalizeDate( $days, $months, $years, $eras ); $this->assignUncertainty( $circas, $isRange, $numbers, $chunks ); break; default: /****** CASE 6+ ******/ /** Can be one of the following: * day-month-year-day-month-year * month-day-year-month-day-year * year-month-day-year-month-day */ $order1 = array( WCDateNumber::day, WCDateNumber::month, WCDateNumber::year, WCDateNumber::day, WCDateNumber::month, WCDateNumber::year ); $order2 = array( WCDateNumber::month, WCDateNumber::day, WCDateNumber::year, WCDateNumber::month, WCDateNumber::day, WCDateNumber::year ); $order3 = array( WCDateNumber::year, WCDateNumber::month, WCDateNumber::day, WCDateNumber::year, WCDateNumber::month, WCDateNumber::day ); if ( ! ( $this->dayUpTo31( $unknowns, $months, $years ) || $this->monthUpTo12( $unknowns, $days, $years ) || $this->yearAdjacentEra( $unknowns, $years, $eras, $chunks ) || $this->yearsInOrder( $unknowns, $days, $months, $years, $eras ) || $this->tryOrder( $unknowns, $days, $months, $years, $order1 ) || $this->tryOrder( $unknowns, $days, $months, $years, $order2 ) || $this->tryOrder( $unknowns, $days, $months, $years, $order3 ) ) ) { foreach( $unknowns as $unknownKey => $unknown ) { if ( count( $day ) < 2 ) { $days[ $unknownKey ] = $unknown->num; } elseif ( count( $months ) < 2 ) { $months[ $unknownKey ] = $unknown->num; } else { $years[ $unknownKey ] = $unknown->num; } } } $isRange = $this->finalizeDate( $days, $months, $years, $eras ); $this->assignUncertainty( $circas, $isRange, $numbers, $chunks ); } }