Valid Hijri Date shown as invalid in moment-hijri

309 Views Asked by At

According to the ummul-qura site, 30-Shawwal-1400 is a valid date , but it is returned as invalid when passed throught isValid function using moment-hijri plugin

moment('1400-10-30', 'iYYYY-iMM-iDD').isValid() , What could be the issue?

https://www.ummulqura.org.sa/yearcalender.aspx?y=1400&l=True

enter image description here

1

There are 1 best solutions below

11
Alberto Fecchi On

UPDATE

Using this code in moment-hijri.js right after the closing brackets at line 121, dates seems to work correctly. By the way, you should check it deeply to be sure that everything is ok.

...
79517, 79546, 79576, 79606, 79635, 79665, 79694, 79724, 79753, 79783, 79812, 79841, 79871, 79900, 79930, 79960, 79990]
}

// Add this code 
for (let i = 538; i < ummalqura.ummalquraData.length; i++) {
 ummalqura.ummalquraData[i] += 1;
}

(Otherwise, you can also decrease constants from 0 to 537 by 1, it's the same solution.)

If a month has 29 or 30 days depends on a simple calculation: ummalquraData[i] - ummalquraData[i - 1]. In your case, ummalquraData[538] - ummalquraData[537] returns 29 instead of expected 30. To obtain 30 preserving every other calculation you need to increase every constant after 538 (included) OR decrease every constant before 538 (excluded). This way, you're changing only the duration of 1400-10, keeping original duration of every other month.

UPDATE (not valid solution)

I have found a (seems to be) valid solution for you. Using constant data from here (https://github.com/talomaireeni/Umm-Al-Qura-Calendar/blob/master/UQCal.js), i see that 1400-10 is correctly validated.

Be careful, this library starts from 15141 (line 17) while moment-hijri starts from 28607 (line 39). Switching moment-hijri constants with the ones from this library, everything seems to work.

I suggest you to open an issue in the official moment-hijri's GitHub repository and ask for a fix.

Meanwhile, you can use UQCal.js's constants to fix your app.

UPDATE (old)

Analyzing the library's source code, i found that the main problem is generated by this function (which bases its calculations on constants):


// moment-hijri.js at line 806

hMoment.iDaysInMonth = function (year, month) {
    var i = getNewMoonMJDNIndex(year, month + 1),
    daysInMonth = ummalqura.ummalquraData[i] - ummalqura.ummalquraData[i - 1]
    return daysInMonth
}



// moment-hijri.js at line 29

/************************************
      Constants
  ************************************/

    var ummalqura = {
        ummalquraData: [28607, 28636, 28665, 28695, 28724, ...

This function returns the number of days in a month providing specific year and month values. Providing 1400 and 10 it returns 29 days (instead of expected 30).

getNewMoonMJDNIndex() finds the index of the new moon in modified Julian day number (moment-hijri.js at line 935) in ummalquraData, which contains constant data.

So, the problem is caused by wrong constant data inside ummalquraData which consider 1400-10 of 29 days.

Here are my tests:

    it('should add one day in the same month', function() {
      var m = moment('1400-10-29', 'iYYYY-iMM-iDD');
      m.add(1, 'idate')
      m.format('iYYYY-iM-iD').should.be.equal('1400-10-30')
    })
    // AssertionError: expected '1400-11-1' to equal '1400-10-30'


    it('should confirm that 1400-09 has 30 days', function() {
      var daysInMonth = moment('1400-09-15', 'iYYYY-iMM-iDD').iDaysInMonth();
      daysInMonth.should.be.equal(30);
    })
    // Pass, 1400-09 has 30 days


    it('FALSE POSITIVE should confirm that 1400-10 has 30 days', function() {
      // After an internal conversion, the date becomes 1400-11-01 (so the month becomes '11')
      // That's why iDaysInMonth() returns 30 (that seems correct).
      var daysInMonth = moment('1400-10-30', 'iYYYY-iMM-iDD').iDaysInMonth();
      daysInMonth.should.be.equal(30);
    })
    // Pass, but it's a false positive


    it('should confirm that 1400-10 has 30 days', function() {
      // After an internal conversion, the date becomes 1400-11-01 (so the month becomes '11')
      // That's why iDaysInMonth() returns 30 (that seems correct).
      var daysInMonth = moment('1400-10-15', 'iYYYY-iMM-iDD').iDaysInMonth();
      daysInMonth.should.be.equal(30);
    })
    // AssertionError: expected 29 to equal 30

OLD ANSWER

Accordingly to multiple online Hijri calendars, 1400-10-30 is not a valid date:

https://www.mumineencalendar.com/# If you set 1400 Shawwal and click on '30', you'll see that '30' is referred to Gregorian Calendar - 30 August 1980 - and the "real" last day of Shawwal is 29.

This is a bit strange, every month seems to leak the last day, anyway it confirms that 1400-10-30 is not a valid date: https://www.islamicfinder.org/islamic-calendar/1400/Shawwal/?type=Hijri

So, the isValid() method seems to work correctly.