A
A
Andrey2017-09-11 15:48:21
PHP
Andrey, 2017-09-11 15:48:21

How to write a converter from Gregorian to Iranian calendars and vice versa?

The problem is that the more I read about the Iranian calendar, the more questions appear)))
Maybe someone has already dealt with this problem? I will be glad if you help with the algorithms.
And then there are too many different conditions, in connection with which the number of days changes.
Or, in the most extreme case, can it somehow be converted through the database with queries?))

Answer the question

In order to leave comments, you need to log in

2 answer(s)
M
marginBottom, 2017-09-11
@RUvik_od

https://www.codeproject.com/Articles/28380/Persian...

A
Andrey, 2018-03-02
@RUvik_od

found somewhere on the eastern sites a piece on JS. I rewrote it in PHP, the people of Iran appreciated it and said that it works correctly ;-)

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);

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question