<?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: Pijar Sukma Adiluhung</title>
    <description>The latest articles on DEV Community by Pijar Sukma Adiluhung (@pijaradiluhung).</description>
    <link>https://dev.to/pijaradiluhung</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%2F4099639%2F8bea9c17-5fa4-4ece-ac02-e2becfa6f52e.png</url>
      <title>DEV Community: Pijar Sukma Adiluhung</title>
      <link>https://dev.to/pijaradiluhung</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pijaradiluhung"/>
    <language>en</language>
    <item>
      <title>How a niche calendar page got to #1 on Google and Bing</title>
      <dc:creator>Pijar Sukma Adiluhung</dc:creator>
      <pubDate>Mon, 21 Sep 2026 06:55:03 +0000</pubDate>
      <link>https://dev.to/pijaradiluhung/how-a-niche-calendar-page-got-to-1-on-google-and-bing-f51</link>
      <guid>https://dev.to/pijaradiluhung/how-a-niche-calendar-page-got-to-1-on-google-and-bing-f51</guid>
      <description>&lt;p&gt;I maintain &lt;a href="https://mabims.dev" rel="noopener noreferrer"&gt;mabims.dev&lt;/a&gt;, a free, open-source Hijri calendar API for Indonesia. Its calendar page, &lt;a href="https://mabims.dev/kalender-hijriah/" rel="noopener noreferrer"&gt;Kalender Hijriah MABIMS&lt;/a&gt;, now ranks #1 on Google and Bing for "kalender hijriah mabims" (screenshots below, taken 21 Sep 2026).&lt;/p&gt;

&lt;p&gt;Some context first. It's a niche, low-competition query, rankings vary by location, and I can't prove which change moved the needle. This is what the page does today.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwkjnlu3m84nkw3u31fqs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwkjnlu3m84nkw3u31fqs.png" alt="Bing Search Result" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzjf2m51xlgyfwd3jqyy0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzjf2m51xlgyfwd3jqyy0.png" alt="Google Search Result" width="800" height="736"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Real HTML on every request
&lt;/h2&gt;

&lt;p&gt;The page started as a static build. It's now rendered on the server, in a Node container separate from the API. The file opts out of prerendering with &lt;code&gt;export const prerender = false;&lt;/code&gt;, and on each request it fetches from the API over the internal network:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiBase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;INTERNAL_API_BASE&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:8000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;apiBase&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/api/v1/month?year=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currentYear&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;month=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currentMonth&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;calendar=hijri`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The month grid, today's date, important dates, a 12-month summary, and the hilal facts are all in the first HTML response. The browser script only handles month navigation and refreshes. The browser uses the public API base, and the server uses the internal one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fresh, but cheap: cache until midnight Jakarta
&lt;/h2&gt;

&lt;p&gt;Rendering on every hit would be wasteful, and a daily static build goes stale. So the page sets its own cache header, expiring at midnight in Jakarta, the same rhythm as the API's &lt;code&gt;/today&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ttl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;86400&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;secsOfDayInJakarta&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;Astro&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cache-Control&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`public, max-age=0, s-maxage=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CDN (Bunny) can hold the page until then, so the origin should render at most once per region per day. The header is only set when the &lt;code&gt;/today&lt;/code&gt; fetch succeeded, so a failed render isn't cached for the day.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in the HTML
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A real table for the year.&lt;/strong&gt; A 12-month overview with &lt;code&gt;&amp;lt;th scope="row"&amp;gt;&lt;/code&gt; for each month, its Gregorian date range, and its length in days.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text generated from data.&lt;/strong&gt; The hilal section builds a sentence like "Kapan Jumadil Awal dimulai? Berdasarkan kriteria Neo MABIMS…", followed by the actual numbers: moon altitude, elongation, illumination, moon age, sunset and moonset.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Images with descriptive alt text&lt;/strong&gt;, lazy-loaded, with width and height set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Important dates as &lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt; rows&lt;/strong&gt;, not a JS-only widget.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  One source for the FAQ and its schema
&lt;/h2&gt;

&lt;p&gt;The visible FAQ and the FAQPage JSON-LD come from the same array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;acceptedAnswer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Answer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aPlain&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Answers with links or &lt;code&gt;&amp;lt;code&amp;gt;&lt;/code&gt; have &lt;code&gt;aHtml&lt;/code&gt; for display and &lt;code&gt;aPlain&lt;/code&gt; for the schema. One question, the date of 1 Ramadhan, is built from live event data.&lt;/p&gt;

&lt;h2&gt;
  
  
  The title comes from data
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Kalender Hijriah MABIMS &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currentYear&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;masehiYear&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;) • Kriteria Kemenag Neo MABIMS`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The target phrase is first, the years roll over automatically, and there's an explicit &lt;code&gt;canonical&lt;/code&gt;. Google still shows my old title, "Kalender Hijriah 1448 H &amp;amp; 2026", while Bing shows the new one. That's recrawl lag, so I requested reindexing in Search Console.&lt;/p&gt;

&lt;h2&gt;
  
  
  Say what you are
&lt;/h2&gt;

&lt;p&gt;The page says in several places that it's independent, not affiliated with Kemenag, and that results are estimates. The FAQ also explains why Google Calendar (Umm al-Qura) can differ by a day. For a topic people take seriously, I think that honesty builds trust, and it answers questions people are already searching.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd still fix
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Midnight vs maghrib.&lt;/strong&gt; The cache expires at midnight, but the Hijri date changes at maghrib. &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The month grid is &lt;code&gt;div&lt;/code&gt;s, not a semantic table.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Event schema or &lt;code&gt;&amp;lt;time&amp;gt;&lt;/code&gt; tags&lt;/strong&gt; for the holidays, though the data is there.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The H1 is followed by only a date line.&lt;/strong&gt; The explanatory text sits lower, in the "Tentang" section.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Beyond the page
&lt;/h2&gt;

&lt;p&gt;I also published posts on dev.to, Medium, and Kompasiana, and the GitHub READMEs link to the page with descriptive anchors. &lt;/p&gt;

&lt;p&gt;If you've ranked a data or tool page, I'd like to hear what mattered most for you.&lt;/p&gt;

&lt;p&gt;Peace!&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>api</category>
    </item>
    <item>
      <title>Indonesians! Your Hijri Calendar Widget Shouldn't Need a Network Call. So I Fixed That.</title>
      <dc:creator>Pijar Sukma Adiluhung</dc:creator>
      <pubDate>Tue, 01 Sep 2026 02:38:33 +0000</pubDate>
      <link>https://dev.to/pijaradiluhung/indonesians-your-hijri-calendar-widget-shouldnt-need-a-network-call-so-i-fixed-that-2o3d</link>
      <guid>https://dev.to/pijaradiluhung/indonesians-your-hijri-calendar-widget-shouldnt-need-a-network-call-so-i-fixed-that-2o3d</guid>
      <description>&lt;p&gt;A while back I wrote about building &lt;a href="https://mabims.dev" rel="noopener noreferrer"&gt;mabims.dev&lt;/a&gt;, a free open-source API for Indonesia's Hijri calendar based on MABIMS criteria (not Umm al-Qura, which is what most Hijri libraries default to and which can be off by a day from what's officially observed here).&lt;/p&gt;

&lt;p&gt;But an API is still an API... every time your widget renders, you're firing a network request just to answer "what's today's Hijri date?" For something that changes once a day and barely ever needs live computation, that felt like overkill.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;&lt;a href="https://github.com/PijarAdiluhung/mabims-hijri" rel="noopener noreferrer"&gt;mabims-hijri&lt;/a&gt;&lt;/strong&gt;, an npm package that bundles the calendar data directly into your app. Most lookups resolve instantly, with zero network calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Idea
&lt;/h2&gt;

&lt;p&gt;Hijri dates for 2024–2026 are already known, they're not live-computed, they come from an official curated table. So instead of hitting an API for a fact that doesn't change, the package ships that table (~72KB of JSON) right inside itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;mabims-hijri
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;today&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mabims-hijri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;today&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// {&lt;/span&gt;
&lt;span class="c1"&gt;//   date: '1448-03-18',&lt;/span&gt;
&lt;span class="c1"&gt;//   calendar: 'hijri',&lt;/span&gt;
&lt;span class="c1"&gt;//   day: 18,&lt;/span&gt;
&lt;span class="c1"&gt;//   month: 3,&lt;/span&gt;
&lt;span class="c1"&gt;//   month_name: 'Rabiul Awal',&lt;/span&gt;
&lt;span class="c1"&gt;//   year: 1448&lt;/span&gt;
&lt;span class="c1"&gt;// }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That call resolves from bundled data. No fetch, no waiting, works offline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three-Tier Fallback
&lt;/h2&gt;

&lt;p&gt;For dates outside the bundled range (post-2026), it falls back gracefully instead of just failing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌───────────────────┐     ┌──────────────────┐     ┌───────────────────┐
│  Bundled MABIMS    │ ──► │  In-Memory Cache │ ──► │  Live API         │
│  (data.json)       │     │  (per-session)    │     │  (mabims.dev)     │
└───────────────────┘     └──────────────────┘     └───────────────────┘
      Built-in                 Always fast            Fallback only
      2024–2026                (TTL: 24h)             (outside range)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Bundled data&lt;/strong&gt;: instant, no network, covers 2024-01-13 to 2026-12-31.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In-memory cache&lt;/strong&gt;: anything fetched from the API gets cached for 24h so repeat lookups stay fast.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live API&lt;/strong&gt;: only touched when you ask for a date outside the bundled range.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The package also silently checks once a day for a newer version of the table and updates itself in the background, so it stays current without you having to bump the package version by hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Converting Dates
&lt;/h2&gt;

&lt;p&gt;Same offline-first behavior applies to conversion, not just "today":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;convert&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mabims-hijri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Gregorian → Hijri&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hijri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2026-08-31&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hijri&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;month_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 'Rabiul Awal'&lt;/span&gt;

&lt;span class="c1"&gt;// Hijri → Gregorian&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gregorian&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1448-03-18&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hijri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Rendering a Widget (React example)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;today&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;HijriDate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mabims-hijri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;HijriToday&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setDate&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HijriDate&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;today&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;day&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;month_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;year&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; H&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First render, no spinner needed in practice! The bundled lookup is fast enough that &lt;code&gt;useEffect&lt;/code&gt; resolves almost immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  Works Anywhere &lt;code&gt;fetch&lt;/code&gt; Exists
&lt;/h2&gt;

&lt;p&gt;Node 18+, browsers, edge runtimes (Cloudflare Workers, Vercel Edge, Deno), and React Native. For React Native, there's no &lt;code&gt;localStorage&lt;/code&gt;, so persistent caching needs a storage adapter... but good news! The package exposes a simple interface for that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setStorageAdapter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mabims-hijri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;AsyncStorage&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@react-native-async-storage/async-storage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nf"&gt;setStorageAdapter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;AsyncStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mabims_&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;AsyncStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mabims_&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;AsyncStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mabims_&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without it, caching just falls back to in-memory (works fine, just doesn't persist across app restarts).&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Things It Covers
&lt;/h2&gt;

&lt;p&gt;Beyond &lt;code&gt;today()&lt;/code&gt; and &lt;code&gt;convert()&lt;/code&gt;, the package wraps the full API surface: &lt;code&gt;range()&lt;/code&gt; for bulk date conversion, &lt;code&gt;month()&lt;/code&gt;/&lt;code&gt;year()&lt;/code&gt; for rendering calendar grids, &lt;code&gt;events()&lt;/code&gt; for Islamic holidays (Ramadan, Idul Fitri, Idul Adha, etc.), and &lt;code&gt;hilal.info()&lt;/code&gt; for moon-visibility data used to determine the start of a Hijri month. Full reference is in the &lt;a href="https://github.com/PijarAdiluhung/mabims-hijri" rel="noopener noreferrer"&gt;README&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;mabims-hijri
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;npm: &lt;a href="https://www.npmjs.com/package/mabims-hijri" rel="noopener noreferrer"&gt;npmjs.com/package/mabims-hijri&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Source: &lt;a href="https://github.com/PijarAdiluhung/mabims-hijri" rel="noopener noreferrer"&gt;github.com/PijarAdiluhung/mabims-hijri&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;API docs: &lt;a href="https://mabims.dev" rel="noopener noreferrer"&gt;mabims.dev&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MIT licensed, zero dependencies beyond native &lt;code&gt;fetch&lt;/code&gt;. If you build something with it or hit an edge case, issues and PRs are welcome.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>npm</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Hijri Dates in Indonesia Were a Pain to Get Right. Not Anymore.</title>
      <dc:creator>Pijar Sukma Adiluhung</dc:creator>
      <pubDate>Sun, 30 Aug 2026 11:20:06 +0000</pubDate>
      <link>https://dev.to/pijaradiluhung/hijri-dates-in-indonesia-were-a-pain-to-get-right-not-anymore-499c</link>
      <guid>https://dev.to/pijaradiluhung/hijri-dates-in-indonesia-were-a-pain-to-get-right-not-anymore-499c</guid>
      <description>&lt;p&gt;If you've ever built a website for Indonesian users and needed to show today's Hijri date, you probably know the pain. Most Hijri calendar APIs and libraries default to &lt;strong&gt;Umm al-Qura&lt;/strong&gt; (Saudi Arabia's calendar), which can differ by a full day from what's actually observed and announced in Indonesia.&lt;/p&gt;

&lt;p&gt;It's not just a theoretical mismatch. In my own community, this got bad enough that &lt;strong&gt;nobody trusts online Hijri dates anymore.&lt;/strong&gt; People just wait for the official government announcement instead of checking a website or app, because too many times, the date shown online didn't match what Kemenag (Indonesia's Ministry of Religious Affairs) actually announced. A one-day difference sounds small, until it's the difference between fasting on the right day or not.&lt;/p&gt;

&lt;p&gt;The root cause is simple: Indonesia (along with Malaysia, Brunei, and Singapore) uses a different visibility standard called &lt;strong&gt;MABIMS&lt;/strong&gt;, not Umm al-Qura. Most APIs just never bothered to support it.&lt;/p&gt;

&lt;p&gt;That's exactly the gap I set out to close: &lt;a href="https://mabims.dev" rel="noopener noreferrer"&gt;mabims.dev&lt;/a&gt; an open-source Hijri calendar API for Indonesia, built on the country's official MABIMS criteria instead of Saudi Arabia's Umm al-Qura standard. Free, open-source, no API key required. Here's how to use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We're Building
&lt;/h2&gt;

&lt;p&gt;A simple "Today in Hijri" widget, then leveling it up into a date converter and a full month grid. All plain JavaScript, no dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Get Today's Date
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET https://api.mabims.dev/api/v1/today
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-08-24"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"calendar"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gregorian"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"tz"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Asia/Jakarta"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1448-03-11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"calendar"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hijri"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"day"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"month"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"month_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Rabiul Akhir"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"year"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1448&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mabims"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"warnings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the &lt;code&gt;output&lt;/code&gt; object already gives you &lt;code&gt;day&lt;/code&gt;, &lt;code&gt;month_name&lt;/code&gt;, and &lt;code&gt;year&lt;/code&gt; separately — no string parsing needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Render It
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"hijri-date"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.mabims.dev/api/v1/today&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;month_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;year&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hijri-date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;day&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;month_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;year&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; H`&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hijri-date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Output: &lt;code&gt;11 Rabiul Akhir 1448 H&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Add a Date Converter
&lt;/h2&gt;

&lt;p&gt;Sometimes you need to convert a specific date, not just "today." Use &lt;code&gt;/convert&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET https://api.mabims.dev/api/v1/convert?date=2026-08-24&amp;amp;calendar=gregorian
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;convertDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://api.mabims.dev/api/v1/convert?date=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;calendar=gregorian`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;convertDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2026-08-24&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;day&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;month_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;year&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; H`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flip &lt;code&gt;calendar=gregorian&lt;/code&gt; to &lt;code&gt;calendar=hijri&lt;/code&gt; (with a Hijri-format date like &lt;code&gt;1448-03-11&lt;/code&gt;) to convert the other direction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Render a Full Month Grid
&lt;/h2&gt;

&lt;p&gt;Need a whole calendar, not just one date? Use &lt;code&gt;/month&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET https://api.mabims.dev/api/v1/month?year=1447&amp;amp;month=9&amp;amp;calendar=hijri
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.mabims.dev/api/v1/month?year=1447&amp;amp;month=9&amp;amp;calendar=hijri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hijri&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; — &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gregorian&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Need a whole year in one call instead of looping &lt;code&gt;/month&lt;/code&gt; twelve times? There's a &lt;code&gt;/year&lt;/code&gt; endpoint too, grouped by month.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Under the Hood
&lt;/h2&gt;

&lt;p&gt;mabims.dev sources its dates from Kemenag RI's official tables (2024–2026 currently), and falls back to computed &lt;strong&gt;Neo MABIMS&lt;/strong&gt; criteria (moon altitude ≥ 3°, elongation ≥ 6.4°) for dates outside that range, up to 2053. Every response tells you which one you got via the &lt;code&gt;source&lt;/code&gt; field: &lt;code&gt;"mabims"&lt;/code&gt; for table data, &lt;code&gt;"mabims-computed"&lt;/code&gt; for the calculated fallback.&lt;/p&gt;

&lt;p&gt;There's also a genuinely fun endpoint, &lt;code&gt;/hilal/viz&lt;/code&gt;, that renders an actual sky chart PNG showing moon position, visibility criteria, and verdict for any given month — worth a look if you're curious how moon-sighting criteria translate visually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It / Contribute
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Docs: &lt;a href="https://mabims.dev" rel="noopener noreferrer"&gt;mabims.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Source: &lt;a href="https://github.com/PijarAdiluhung/mabims-api" rel="noopener noreferrer"&gt;github.com/PijarAdiluhung/mabims-api&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No API key, no rate-limit paywall, CORS-open so you can call it straight from the browser. If you build something with it, or hit an edge case, issues and PRs are welcome.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>api</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I Built an API Because My Government’s Website Got the Date Wrong (and Just… Deleted It)</title>
      <dc:creator>Pijar Sukma Adiluhung</dc:creator>
      <pubDate>Sat, 29 Aug 2026 03:26:27 +0000</pubDate>
      <link>https://dev.to/pijaradiluhung/i-built-an-api-because-my-governments-website-got-the-date-wrong-and-just-deleted-it-4ca5</link>
      <guid>https://dev.to/pijaradiluhung/i-built-an-api-because-my-governments-website-got-the-date-wrong-and-just-deleted-it-4ca5</guid>
      <description>&lt;p&gt;There’s a funny (and slightly sad) story behind why I built &lt;a href="https://mabims.dev" rel="noopener noreferrer"&gt;mabims.dev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It started with a date.&lt;/p&gt;

&lt;p&gt;More specifically, a &lt;strong&gt;Hijri date&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Once Upon a Time, the Government Website Had the Date
&lt;/h2&gt;

&lt;p&gt;For a long time, Indonesia’s Ministry of Religious Affairs (Kemenag) website displayed the current Hijri date.&lt;/p&gt;

&lt;p&gt;It was convenient.&lt;/p&gt;

&lt;p&gt;You opened the website, looked at the corner of the page, and there it was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Today: 30 Sha'ban&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Simple enough.&lt;/p&gt;

&lt;p&gt;A lot of people, including me, got used to relying on it.&lt;/p&gt;

&lt;p&gt;Then one day, something weird happened.&lt;/p&gt;

&lt;p&gt;A post went viral.&lt;/p&gt;

&lt;p&gt;Someone noticed that the &lt;strong&gt;official calendar published by Kemenag said one date&lt;/strong&gt;, while the &lt;strong&gt;date displayed on Kemenag’s own website said the next day&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;They were off by one day.&lt;/p&gt;

&lt;p&gt;People started asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How can the official website and the official calendar disagree with each other?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The post spread.&lt;/p&gt;

&lt;p&gt;People discussed it.&lt;/p&gt;

&lt;p&gt;And then…&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution? Just Delete It.
&lt;/h2&gt;

&lt;p&gt;I didn't know what exactly happened behind the scenes.&lt;/p&gt;

&lt;p&gt;Maybe it was a bug.&lt;/p&gt;

&lt;p&gt;Maybe it was a calculation issue.&lt;/p&gt;

&lt;p&gt;Maybe the website was using a different data source.&lt;/p&gt;

&lt;p&gt;I don't know.&lt;/p&gt;

&lt;p&gt;But I do remember what happened eventually.&lt;/p&gt;

&lt;p&gt;The Hijri date disappeared from the website.&lt;/p&gt;

&lt;p&gt;Problem solved.&lt;/p&gt;

&lt;p&gt;Technically.&lt;/p&gt;

&lt;p&gt;If you can't display the wrong date, you can't display a wrong date.&lt;/p&gt;

&lt;p&gt;Elegant. 😂&lt;/p&gt;

&lt;p&gt;At the time, I just thought it was funny.&lt;/p&gt;

&lt;p&gt;A few years later, I became a developer.&lt;/p&gt;

&lt;p&gt;And suddenly, the story made a lot more sense.&lt;/p&gt;

&lt;h2&gt;
  
  
  Years Later, I Became a Junior Developer
&lt;/h2&gt;

&lt;p&gt;Once I started working as a developer, I learned how easy it is to add a Hijri date to a website.&lt;/p&gt;

&lt;p&gt;You don't need to calculate the lunar calendar yourself.&lt;/p&gt;

&lt;p&gt;You just install a library.&lt;/p&gt;

&lt;p&gt;Or call an API.&lt;/p&gt;

&lt;p&gt;There are plenty of them.&lt;/p&gt;

&lt;p&gt;The problem is that most of the libraries and APIs you'll find use &lt;strong&gt;Umm al-Qura&lt;/strong&gt; by default.&lt;/p&gt;

&lt;p&gt;And that's perfectly reasonable.&lt;/p&gt;

&lt;p&gt;Umm al-Qura is the official calendar of Saudi Arabia. It's well documented, widely supported, and easy to integrate.&lt;/p&gt;

&lt;p&gt;For a developer who just wants:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Gregorian date → Hijri date
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it works great.&lt;/p&gt;

&lt;p&gt;But there's a catch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Indonesia doesn't use the Saudi calendar as its official reference.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Indonesian context involves Kemenag's calendar, astronomical calculations, and the &lt;strong&gt;Neo MABIMS&lt;/strong&gt; criteria.&lt;/p&gt;

&lt;p&gt;As a result, the Hijri date can differ by one day.&lt;/p&gt;

&lt;p&gt;And suddenly that old story made sense.&lt;/p&gt;

&lt;p&gt;Maybe the problem wasn't really:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The code is wrong."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Maybe it was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"The code is using the wrong source of truth for the context."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's a very different problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  So I Looked for an Indonesian-Friendly API
&lt;/h2&gt;

&lt;p&gt;I started thinking about a fairly simple question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If I'm an Indonesian developer and I want to display the Hijri date according to Kemenag, what do I use?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The answer wasn't particularly satisfying.&lt;/p&gt;

&lt;p&gt;I could:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scrape Kemenag's website.&lt;/li&gt;
&lt;li&gt;Maintain my own calendar table.&lt;/li&gt;
&lt;li&gt;Find some obscure data source.&lt;/li&gt;
&lt;li&gt;Calculate everything myself.&lt;/li&gt;
&lt;li&gt;Or just use a normal Hijri API and accept that it might be a day off.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of those felt particularly great.&lt;/p&gt;

&lt;p&gt;And option #4 is especially dangerous.&lt;/p&gt;

&lt;p&gt;Because the application will happily tell users:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;1 Ramadan&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;while the official Indonesian calendar says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;30 Sha'ban&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Your code isn't crashing.&lt;/p&gt;

&lt;p&gt;Your API isn't returning an error.&lt;/p&gt;

&lt;p&gt;Your tests might all pass.&lt;/p&gt;

&lt;p&gt;Everything looks fine.&lt;/p&gt;

&lt;p&gt;The date is just… wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  So I Built One
&lt;/h2&gt;

&lt;p&gt;That's why I built &lt;strong&gt;&lt;a href="https://mabims.dev" rel="noopener noreferrer"&gt;mabims.dev&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It's a Hijri calendar API designed specifically for the Indonesian context.&lt;/p&gt;

&lt;p&gt;The primary source is the &lt;strong&gt;official Kemenag RI calendar&lt;/strong&gt;, with &lt;strong&gt;Neo MABIMS&lt;/strong&gt; criteria used as a fallback outside the available official data range.&lt;/p&gt;

&lt;p&gt;The goal is deliberately simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your application
       ↓
   mabims.dev
       ↓
Kemenag / Neo MABIMS
       ↓
Indonesian Hijri date
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No API key.&lt;/p&gt;

&lt;p&gt;No complicated authentication.&lt;/p&gt;

&lt;p&gt;No scraping required on the developer's side.&lt;/p&gt;

&lt;p&gt;Just call an endpoint.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://api.mabims.dev/api/v1/today"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you get the current Hijri date according to the project's Indonesian calendar reference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Not Just Use Umm al-Qura?
&lt;/h2&gt;

&lt;p&gt;To be clear: &lt;strong&gt;Umm al-Qura isn't bad.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's a perfectly legitimate calendar system.&lt;/p&gt;

&lt;p&gt;If you're building something for Saudi Arabia, or your application specifically needs Umm al-Qura, use it.&lt;/p&gt;

&lt;p&gt;The problem is assuming that:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Hijri calendar = one universal calendar."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It isn't quite that simple.&lt;/p&gt;

&lt;p&gt;Different countries and institutions can use different methodologies, observations, calculations, and official decisions.&lt;/p&gt;

&lt;p&gt;And when you're building software that deals with religious dates, a difference of one day isn't necessarily a minor UI issue.&lt;/p&gt;

&lt;p&gt;It can affect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ramadan&lt;/li&gt;
&lt;li&gt;Eid&lt;/li&gt;
&lt;li&gt;fasting schedules&lt;/li&gt;
&lt;li&gt;Islamic events&lt;/li&gt;
&lt;li&gt;religious announcements&lt;/li&gt;
&lt;li&gt;prayer-related applications&lt;/li&gt;
&lt;li&gt;educational content&lt;/li&gt;
&lt;li&gt;community calendars&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For an Indonesian application, the Indonesian source of truth matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  I'm Not an Astronomer
&lt;/h2&gt;

&lt;p&gt;There's another reason I wanted to build this as an API.&lt;/p&gt;

&lt;p&gt;Developers shouldn't have to become astronomers just to display a calendar.&lt;/p&gt;

&lt;p&gt;If an application needs the Indonesian Hijri date, the developer should be able to write something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;today&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.mabims.dev/api/v1/today&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and move on with building the actual application.&lt;/p&gt;

&lt;p&gt;The complicated part: calendar data, methodology, historical coverage, and fallback logic, belongs behind the API.&lt;/p&gt;

&lt;p&gt;That's what APIs are good at.&lt;/p&gt;

&lt;h2&gt;
  
  
  Will Anyone Actually Use It?
&lt;/h2&gt;

&lt;p&gt;Honestly?&lt;/p&gt;

&lt;p&gt;I have no idea.&lt;/p&gt;

&lt;p&gt;Maybe nobody will.&lt;/p&gt;

&lt;p&gt;But at least one application already uses it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://kajian.malangmengaji.com" rel="noopener noreferrer"&gt;kajian.malangmengaji.com&lt;/a&gt;&lt;/strong&gt;, which I also built.&lt;/p&gt;

&lt;p&gt;So even if nobody else ever uses the API, it still solves a real problem for one of my own projects.&lt;/p&gt;

&lt;p&gt;And that's good enough reason for me.&lt;/p&gt;

&lt;p&gt;If other Indonesian developers find it useful, even better.&lt;/p&gt;

&lt;h2&gt;
  
  
  It's Free and Open Source
&lt;/h2&gt;

&lt;p&gt;I wanted the barrier to adoption to be as low as possible.&lt;/p&gt;

&lt;p&gt;So:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Free to use&lt;/li&gt;
&lt;li&gt;No API key&lt;/li&gt;
&lt;li&gt;Open source&lt;/li&gt;
&lt;li&gt;Simple HTTP API&lt;/li&gt;
&lt;li&gt;Designed around the Indonesian context&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can try it right now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://api.mabims.dev/api/v1/today"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The full documentation is available at:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://mabims.dev/quickstart" rel="noopener noreferrer"&gt;https://mabims.dev/quickstart&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Lesson
&lt;/h2&gt;

&lt;p&gt;The funny thing about this project is that it didn't start with:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I'm going to build a Hijri calendar API."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It started with:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Why is the official website showing the wrong date?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then years later, after becoming a developer, I realized that the problem wasn't necessarily a broken algorithm.&lt;/p&gt;

&lt;p&gt;Sometimes software can be perfectly correct &lt;strong&gt;and still produce the wrong answer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Because the source of truth is wrong.&lt;/p&gt;

&lt;p&gt;That's a lesson I keep finding useful in software engineering:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Correct code + wrong assumptions = wrong software.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And sometimes, instead of deleting the feature…&lt;/p&gt;

&lt;p&gt;you just need to build a better API.&lt;/p&gt;

&lt;p&gt;Hopefully, this one won't have to be deleted because it got the date wrong. :)&lt;/p&gt;

</description>
      <category>api</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
