@RUvik_od

Как написать конвертер с григорианского в иранский календари и обратно?

Проблема заключается в том, что чем больше читаю про иранских календарь, тем больше вопросов появляется )))
Может кто-то уже разбирался с данной проблемой ? Буду рад если поможете с алгоритмами.
А то слишком много различных условий, в связи с которыми меняется количество дней.
Или на самый крайний случай, через БД запросами может как-то конвертировать можно будет ?))
  • Вопрос задан
  • 235 просмотров
Решения вопроса 1
marginBottom
@marginBottom
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@RUvik_od Автор вопроса
нашел где-то на восточных сайтах кусок на JS. Переписал на PHP, жители Ирана оценили и сказали что работает правильно ;-)
class IranCalendarParser
{
    const GREGORIAN_EPOCH = 1721425.5;
    const PERSIAN_EPOCH = 1948320.5;
    const ISLAMIC_EPOCH = 1948439.5;
    static public $MONTH_NAME = array(
        1 => 'Farvardin',
        2 => 'Ordibehesht',
        3 => 'Khordad',
        4 => 'Tir',
        5 => 'Mordad',
        6 => 'Shahrivar',
        7 => 'Mehr',
        8 => 'Aban',
        9 => 'Azar',
        10 => 'Dey',
        11 => 'Bahman',
        12 => 'Esfand',
    );

    static function GregorianToIran($year, $month, $day)
    {
        return self::jd_to_persian(self::gregorian_to_jd($year, $month, $day));
    }

    static function IranToGregorian($year, $month, $day)
    {
        return self::jd_to_gregorian(self::persian_to_jd($year, $month, $day));
    }

    static public function GetMonthName($month)
    {
        return self::$MONTH_NAME[$month];
    }

    public function jd_to_gregorian($jd)
    {
       // self::GREGORIAN_EPOCH = 1721425.5;
        $wjd = floor($jd - 0.5) + 0.5;

        $depoch = $wjd - self::GREGORIAN_EPOCH;
        $quadricent = floor($depoch / 146097);
        $dqc = self::mod($depoch, 146097);
        $cent = floor($dqc / 36524);
        $dcent = self::mod($dqc, 36524);
        $quad = floor($dcent / 1461);
        $dquad = self::mod($dcent, 1461);
        $yindex = floor($dquad / 365);
        $year = ($quadricent * 400) + ($cent * 100) + ($quad * 4) + $yindex;
        if (!(($cent == 4) || ($yindex == 4))) {
            $year++;
        }
        $yearday = $wjd - self::gregorian_to_jd($year, 1, 1);
        $leapadj = (($wjd < self::gregorian_to_jd($year, 3, 1)) ? 0
            :
            (self::leap_gregorian($year) ? 1 : 2)
        );
        $month = floor(((($yearday + $leapadj) * 12) + 373) / 367);
        $day = ($wjd - self::gregorian_to_jd($year, $month, 1)) + 1;
        return array( 'day'=>$day,'month'=>$month,'year'=>$year );
    }

    public function mod($a, $b)
    {
        return $a - ($b * floor($a / $b));
    }

    public function gregorian_to_jd($year, $month, $day)
    {
        return (self::GREGORIAN_EPOCH  - 1) +
            (365 * ($year - 1)) +
            floor(($year - 1) / 4) +
            (-floor(($year - 1) / 100)) +
            floor(($year - 1) / 400)+
            floor((((367 * $month) - 362) / 12) +
                (($month <= 2) ? 0 :
                    (self::leap_gregorian($year) ? -1 : -2)
                ) +
                $day)
            ;
    }

    public function leap_gregorian($year)
    {
        return (($year % 4) == 0) &&
            (!((($year % 100) == 0) && (($year % 400) != 0)));
    }

    public function persian_to_jd($year, $month, $day)
    {
        $epbase = $year - (($year >= 0) ? 474 : 473);
        $epyear = 474 + self::mod($epbase, 2820);
        return $day +
            (($month <= 7) ?
                (($month - 1) * 31) :
                ((($month - 1) * 30) + 6)
            ) +
            floor((($epyear * 682) - 110) / 2816) +
            ($epyear - 1) * 365 +
            floor($epbase / 2820) * 1029983 +
            (self::PERSIAN_EPOCH - 1);
    }

    public function jd_to_persian($jd)
    {
        $jd = floor($jd) + 0.5;

        $depoch = $jd - self::persian_to_jd(475, 1, 1);
        $cycle = floor($depoch / 1029983);
        $cyear = self::mod($depoch, 1029983);
        if ($cyear == 1029982) {
            $ycycle = 2820;
        } else {
            $aux1 = floor($cyear / 366);
            $aux2 = self::mod($cyear, 366);
            $ycycle = floor(((2134 * $aux1) + (2816 * $aux2) + 2815) / 1028522) +
                $aux1 + 1;
        }
        $year = $ycycle + (2820 * $cycle) + 474;
        if ($year <= 0) {
            $year--;
        }
        $yday = ($jd - self::persian_to_jd($year, 1, 1)) + 1;
        $month = ($yday <= 186) ? ceil($yday / 31) : ceil(($yday - 6) / 30);
        $day = ($jd - self::persian_to_jd($year, $month, 1)) + 1;
        return array( 'day'=>$day,'month'=>$month,'year'=>$year );
    }

    public function jd_to_islamic($jd)
    {
        $jd = floor($jd) + 0.5;
        $year = floor(((30 * ($jd - self::ISLAMIC_EPOCH)) + 10646) / 10631);
        $month = min(12,
                ceil(($jd - (29 + self::islamic_to_jd($year, 1, 1))) / 29.5) + 1);
        $day = ($jd - self::islamic_to_jd($year, $month, 1)) + 1;
        return array( 'day'=>$day,'month'=>$month,'year'=>$year );
    }

    public function islamic_to_jd($year, $month, $day)
    {
            return ($day +
                    ceil(29.5 * ($month - 1)) +
                    ($year - 1) * 354 +
                    floor((3 + (11 * $year)) / 30) +
                    self::ISLAMIC_EPOCH) - 1;
    }

    public function leap_islamic($year)
    {
            return ((($year * 11) + 14) % 30) < 11;
    }
}

/**
 * Example
 */
IranCalendarParser::GregorianToIran(2017,2,10);
IranCalendarParser::IranToGregorian(1395,11,22);
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
YCLIENTS Москва
от 200 000 до 350 000 ₽
Ведисофт Екатеринбург
от 25 000 ₽
ИТЦ Аусферр Магнитогорск
от 100 000 до 160 000 ₽