<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: M Gh</title>
    <description>The latest articles on DEV Community by M Gh (@m_gh_a5ab8beb20f8c72425f4).</description>
    <link>https://dev.to/m_gh_a5ab8beb20f8c72425f4</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4007820%2F86fd403d-8012-4d19-a544-1513ccd83e73.png</url>
      <title>DEV Community: M Gh</title>
      <link>https://dev.to/m_gh_a5ab8beb20f8c72425f4</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/m_gh_a5ab8beb20f8c72425f4"/>
    <language>en</language>
    <item>
      <title>How to Convert Persian (Jalali) Date to Gregorian in JavaScript — Zero Dependencies</title>
      <dc:creator>M Gh</dc:creator>
      <pubDate>Mon, 29 Jun 2026 09:53:07 +0000</pubDate>
      <link>https://dev.to/m_gh_a5ab8beb20f8c72425f4/how-to-convert-persian-jalali-date-to-gregorian-in-javascript-zero-dependencies-4lo9</link>
      <guid>https://dev.to/m_gh_a5ab8beb20f8c72425f4/how-to-convert-persian-jalali-date-to-gregorian-in-javascript-zero-dependencies-4lo9</guid>
      <description>&lt;p&gt;If you've ever built an app for Iranian users, you've run into the Persian calendar problem. Iran uses the &lt;strong&gt;Solar Hijri (Jalali) calendar&lt;/strong&gt; as its official calendar — not Gregorian. So when a user types their birthdate as &lt;code&gt;1370/06/15&lt;/code&gt;, you can't just store it as-is if your backend expects Gregorian dates.&lt;/p&gt;


&lt;p&gt;In this post I'll show you a &lt;strong&gt;pure JavaScript implementation&lt;/strong&gt; with zero external dependencies that handles both directions: Jalali ↔ Gregorian. This is the same algorithm powering &lt;a href="https://tabdiltarikh.ir/" rel="noopener noreferrer"&gt;تبدیل تاریخ — tabdiltarikh.ir&lt;/a&gt;, a free Persian date converter tool.&lt;/p&gt;







&lt;h2&gt;A Quick Background on the Jalali Calendar&lt;/h2&gt;



&lt;p&gt;The Jalali (Solar Hijri) calendar:&lt;/p&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;Is the &lt;strong&gt;official calendar of Iran and Afghanistan&lt;/strong&gt;
&lt;/li&gt;

    &lt;li&gt;Starts from the vernal equinox (Nowruz, March 20/21)&lt;/li&gt;

    &lt;li&gt;Has &lt;strong&gt;6 months of 31 days&lt;/strong&gt;, &lt;strong&gt;5 months of 30 days&lt;/strong&gt;, and &lt;strong&gt;1 month of 29 or 30 days&lt;/strong&gt; (leap year)&lt;/li&gt;

    &lt;li&gt;Leap years follow a &lt;strong&gt;4-5 year pattern&lt;/strong&gt;, not strictly every 4 years like Gregorian&lt;/li&gt;

    &lt;li&gt;Is currently &lt;strong&gt;621 or 622 years behind&lt;/strong&gt; the Gregorian calendar (depending on the month)&lt;/li&gt;

  &lt;/ul&gt;







&lt;h2&gt;The Algorithm&lt;/h2&gt;



&lt;p&gt;We use the &lt;strong&gt;astronomical Jalali algorithm&lt;/strong&gt; — the same one used in Iran's official calendar. It works via Julian Day Numbers (JDN) as an intermediate step, which makes bidirectional conversion straightforward.&lt;/p&gt;



&lt;pre&gt;&lt;span&gt;javascript&lt;/span&gt;copy&lt;code&gt;// Helper: integer division&lt;br&gt;
function div(a, b) {&lt;br&gt;
  return ~~(a / b);&lt;br&gt;
}

&lt;p&gt;// Core: compute Jalali calendar properties for a given Jalali year&lt;br&gt;
function jalCal(jy) {&lt;br&gt;
  const breaks = [&lt;br&gt;
    -61, 9, 38, 199, 426, 686, 756, 818, 1111, 1181,&lt;br&gt;
    1210, 1635, 2060, 2097, 2192, 2262, 2324, 2394, 2456, 3178&lt;br&gt;
  ];&lt;br&gt;
  const bl = breaks.length;&lt;br&gt;
  const gy = jy + 621;&lt;br&gt;
  let leapJ = -14, jp = breaks[0], jm, jump, leap, n, i;&lt;/p&gt;

&lt;p&gt;if (jy &amp;lt; jp || jy &amp;gt;= breaks[bl - 1])&lt;br&gt;
    throw new Error('Invalid Jalaali year ' + jy);&lt;/p&gt;

&lt;p&gt;for (i = 1; i &amp;lt; bl; i++) {&lt;br&gt;
    jm = breaks[i];&lt;br&gt;
    jump = jm - jp;&lt;br&gt;
    if (jy &amp;lt; jm) break;&lt;br&gt;
    leapJ = leapJ + div(jump, 33) * 8 + div(jump % 33, 4);&lt;br&gt;
    jp = jm;&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;n = jy - jp;&lt;br&gt;
  leapJ = leapJ + div(n, 33) * 8 + div((n % 33) + 3, 4);&lt;br&gt;
  if ((jump % 33) === 4 &amp;amp;&amp;amp; jump - n === 4) leapJ++;&lt;/p&gt;

&lt;p&gt;const leapG = div(gy, 4) - div((div(gy, 100) + 1) * 3, 4) - 150;&lt;br&gt;
  const march = 20 + leapJ - leapG;&lt;/p&gt;

&lt;p&gt;if (jump - n &amp;lt; 6) n = n - jump + div(jump + 4, 33) * 33;&lt;br&gt;
  leap = (((n + 1) % 33) - 1) % 4;&lt;br&gt;
  if (leap === -1) leap = 4;&lt;/p&gt;

&lt;p&gt;return { leap, gy, march };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;// Gregorian date → Julian Day Number&lt;br&gt;
function g2d(gy, gm, gd) {&lt;br&gt;
  let d = div((gy + div(gm - 8, 6) + 100100) * 1461, 4)&lt;br&gt;
        + div(153 * ((gm + 9) % 12) + 2, 5)&lt;br&gt;
        + gd - 34840408;&lt;br&gt;
  d = d - div(div(gy + 100100 + div(gm - 8, 6), 100) * 3, 4) + 752;&lt;br&gt;
  return d;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;// Julian Day Number → Gregorian date&lt;br&gt;
function d2g(jdn) {&lt;br&gt;
  let j = 4 * jdn + 139361631;&lt;br&gt;
  j = j + div(div(4 * jdn + 183187720, 146097) * 3, 4) * 4 - 3908;&lt;br&gt;
  const i = div((j % 1461), 4) * 5 + 308;&lt;br&gt;
  const gd = div(i % 153, 5) + 1;&lt;br&gt;
  const gm = (div(i, 153) % 12) + 1;&lt;br&gt;
  const gy = div(j, 1461) - 100100 + div(8 - gm, 6);&lt;br&gt;
  return { gy, gm, gd };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;// Jalali date → Julian Day Number&lt;br&gt;
function j2d(jy, jm, jd) {&lt;br&gt;
  const r = jalCal(jy);&lt;br&gt;
  return g2d(r.gy, 3, r.march)&lt;br&gt;
       + (jm - 1) * 31&lt;br&gt;
       - div(jm, 7) * (jm - 7)&lt;br&gt;
       + jd - 1;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;// Julian Day Number → Jalali date&lt;br&gt;
function d2j(jdn) {&lt;br&gt;
  const gy = d2g(jdn).gy;&lt;br&gt;
  let jy = gy - 621;&lt;br&gt;
  let r = jalCal(jy);&lt;br&gt;
  let jdn1f = g2d(gy, 3, r.march);&lt;br&gt;
  let jd, jm, k;&lt;/p&gt;

&lt;p&gt;k = jdn - jdn1f;&lt;br&gt;
  if (k &amp;gt;= 0) {&lt;br&gt;
    if (k &amp;lt;= 185) {&lt;br&gt;
      jm = 1 + div(k, 31);&lt;br&gt;
      jd = (k % 31) + 1;&lt;br&gt;
      return { jy, jm, jd };&lt;br&gt;
    } else {&lt;br&gt;
      k -= 186;&lt;br&gt;
    }&lt;br&gt;
  } else {&lt;br&gt;
    jy -= 1;&lt;br&gt;
    k += 179;&lt;br&gt;
    if (r.leap === 1) k++;&lt;br&gt;
  }&lt;/p&gt;

&lt;/code&gt;&lt;p&gt;&lt;code&gt;jm = 7 + div(k, 30);&lt;br&gt;&lt;br&gt;
  jd = (k % 30) + 1;&lt;br&gt;&lt;br&gt;
  return { jy, jm, jd };&lt;br&gt;&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;&lt;/pre&gt;







&lt;h2&gt;The Public API&lt;/h2&gt;



&lt;p&gt;Two clean functions on top of the algorithm above:&lt;/p&gt;



&lt;pre&gt;&lt;span&gt;javascript&lt;/span&gt;copy&lt;code&gt;/**

&lt;ul&gt;
&lt;li&gt;Convert Jalali (Persian) date to Gregorian&lt;/li&gt;
&lt;li&gt;@param {number} jy - Jalali year (e.g. 1403)&lt;/li&gt;
&lt;li&gt;@param {number} jm - Jalali month (1–12)&lt;/li&gt;
&lt;li&gt;@param {number} jd - Jalali day (1–31)&lt;/li&gt;
&lt;li&gt;@returns {number[]} [gregorianYear, gregorianMonth, gregorianDay]
*/
function jalaaliToGregorian(jy, jm, jd) {
const d = d2g(j2d(jy, jm, jd));
return [d.gy, d.gm, d.gd];
}&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;/**&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;code&gt;&lt;br&gt;
&lt;li&gt;Convert Gregorian date to Jalali (Persian)&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;@param {number} gy - Gregorian year&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;@param {number} gm - Gregorian month (1–12)&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;@param {number} gd - Gregorian day&lt;/li&gt;
&lt;br&gt;
&lt;/code&gt;&lt;li&gt;&lt;code&gt;@returns {number[]} [jalaliYear, jalaliMonth, jalaliDay]&lt;br&gt;
*/&lt;br&gt;
function gregorianToJalaali(gy, gm, gd) {&lt;br&gt;
const d = d2j(g2d(gy, gm, gd));&lt;br&gt;
return [d.jy, d.jm, d.jd];&lt;br&gt;
}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;






&lt;h2&gt;Usage Examples&lt;/h2&gt;



&lt;pre&gt;&lt;span&gt;javascript&lt;/span&gt;copy&lt;code&gt;// Jalali → Gregorian&lt;br&gt;
const [gy, gm, gd] = jalaaliToGregorian(1403, 1, 1);&lt;br&gt;
console.log(&lt;code&gt;${gy}-${gm}-${gd}&lt;/code&gt;); // 2024-3-20

&lt;p&gt;// Gregorian → Jalali&lt;br&gt;
const [jy, jm, jd] = gregorianToJalaali(2024, 3, 20);&lt;br&gt;
console.log(&lt;code&gt;${jy}/${jm}/${jd}&lt;/code&gt;); // 1403/1/1&lt;/p&gt;

&lt;/code&gt;&lt;p&gt;&lt;code&gt;// Convert a user's Persian birthdate to Gregorian&lt;br&gt;&lt;br&gt;
const birthJalali = { y: 1370, m: 6, d: 15 };&lt;br&gt;&lt;br&gt;
const [by, bm, bd] = jalaaliToGregorian(birthJalali.y, birthJalali.m, birthJalali.d);&lt;br&gt;&lt;br&gt;
console.log(&lt;code&gt;${by}-${String(bm).padStart(2,'0')}-${String(bd).padStart(2,'0')}&lt;/code&gt;);&lt;br&gt;&lt;br&gt;
// → 1991-09-06&lt;/code&gt;&lt;/p&gt;&lt;/pre&gt;







&lt;h2&gt;Leap Year Check&lt;/h2&gt;



&lt;p&gt;Jalali leap years don't follow the simple "divisible by 4" rule. Use this:&lt;/p&gt;



&lt;pre&gt;&lt;span&gt;javascript&lt;/span&gt;copy&lt;code&gt;function isLeapJalaliYear(jy) {&lt;br&gt;
  return jalCal(jy).leap === 0;&lt;br&gt;
}

&lt;/code&gt;&lt;p&gt;&lt;code&gt;console.log(isLeapJalaliYear(1403)); // true  (1403 is a leap year)&lt;br&gt;&lt;br&gt;
console.log(isLeapJalaliYear(1404)); // false&lt;br&gt;&lt;br&gt;
console.log(isLeapJalaliYear(1408)); // true  (next leap year after 1403)&lt;/code&gt;&lt;/p&gt;&lt;/pre&gt;



&lt;p&gt;The pattern for recent leap years: &lt;strong&gt;1399, 1403, 1408, 1412&lt;/strong&gt; — notice the 4-4-4-5 year gap.&lt;/p&gt;







&lt;h2&gt;Month Lengths&lt;/h2&gt;



&lt;pre&gt;&lt;span&gt;javascript&lt;/span&gt;copy&lt;code&gt;function jalaliMonthLength(jy, jm) {&lt;br&gt;
  if (jm &amp;lt;= 6) return 31;   // Farvardin–Shahrivar&lt;br&gt;
  if (jm &amp;lt;= 11) return 30;  // Mehr–Bahman&lt;br&gt;
  return isLeapJalaliYear(jy) ? 30 : 29; // Esfand&lt;br&gt;
}&lt;/code&gt;&lt;/pre&gt;







&lt;h2&gt;Why Not Just Use a Library?&lt;/h2&gt;



&lt;p&gt;You can — &lt;code&gt;jalaali-js&lt;/code&gt; and &lt;code&gt;moment-jalaali&lt;/code&gt; are solid. But if you only need date conversion (no formatting, no locale, no timezone handling), this self-contained implementation is under &lt;strong&gt;2KB minified&lt;/strong&gt; and has &lt;strong&gt;zero npm dependencies&lt;/strong&gt;. Useful for edge functions, service workers, or any environment where bundle size matters.&lt;/p&gt;







&lt;h2&gt;Real-World Usage&lt;/h2&gt;



&lt;p&gt;If you need a &lt;strong&gt;ready-to-use tool&lt;/strong&gt; rather than implementing it yourself, &lt;a href="https://tabdiltarikh.ir/" rel="noopener noreferrer"&gt;تبدیل تاریخ&lt;/a&gt; provides a free Persian date converter that supports Jalali ↔ Gregorian, Jalali ↔ Hijri (lunar), and age calculation. It also offers a &lt;strong&gt;free embeddable widget&lt;/strong&gt; — two lines of code to add it to any site:&lt;/p&gt;



&lt;pre&gt;&lt;span&gt;html&lt;/span&gt;copy&lt;code&gt;&amp;lt;div data-ttkw&amp;gt;&amp;lt;/div&amp;gt;&lt;br&gt;
&amp;lt;script src="&lt;a href="https://tabdiltarikh.ir/widget.js%22&gt;&lt;/script" rel="noopener noreferrer"&gt;https://tabdiltarikh.ir/widget.js"&amp;amp;gt;&amp;amp;lt;/script&lt;/a&gt;&amp;gt;&lt;/code&gt;&lt;/pre&gt;







&lt;h2&gt;Summary&lt;/h2&gt;



&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
    &lt;thead&gt;
      &lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;This implementation&lt;/th&gt;
&lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
&lt;td&gt;Jalali → Gregorian&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
      &lt;tr&gt;
&lt;td&gt;Gregorian → Jalali&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
      &lt;tr&gt;
&lt;td&gt;Leap year detection&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
      &lt;tr&gt;
&lt;td&gt;Month length&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
      &lt;tr&gt;
&lt;td&gt;Dependencies&lt;/td&gt;
&lt;td&gt;Zero&lt;/td&gt;
&lt;/tr&gt;
      &lt;tr&gt;
&lt;td&gt;Valid range&lt;/td&gt;
&lt;td&gt;Year 1–1500 Jalali&lt;/td&gt;
&lt;/tr&gt;
      &lt;tr&gt;
&lt;td&gt;Algorithm&lt;/td&gt;
&lt;td&gt;Astronomical Jalali (zero error)&lt;/td&gt;
&lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;&lt;/div&gt;



&lt;p&gt;Drop the full code into any JS project and you're done. No build step, no install, no configuration.&lt;/p&gt;







&lt;p&gt;&lt;em&gt;Built something with Persian dates? Share it in the comments — always curious to see what the dev community builds for Farsi-speaking users.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>converter</category>
    </item>
  </channel>
</rss>
