npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

jalali-date

v1.5.0

Published

A Jalali to Gregorian converter with support of formatting output

Readme

JDate

Build Status NPM Version NPM License

A Jalali to Gregorian converter in JavaScript with support of formatting output

Installation

Install from npm:

npm install jalali-date

Both ES modules and CommonJS are supported:

import JDate from 'jalali-date'; // ESM
const JDate = require('jalali-date'); // CommonJS

For the browser, grab a build from the lib directory (or a CDN) and load it with a <script> tag, which defines a global JDate:

<head>
  <script src="jdate.js" type="text/javascript" charset="utf-8"></script>
  <script src="jdate.min.js" type="text/javascript" charset="utf-8"></script>
</head>

The full version is useful for debugging. You may want to use the minified version in production as it is smaller. Both ship with external source maps.

| File | Format | Used by | | ---- | ------ | ------- | | lib/jdate.mjs | ESM | import | | lib/jdate.cjs | CommonJS | require | | lib/jdate.js | IIFE | <script>, sets window.JDate | | lib/jdate.min.js | IIFE, minified | <script>, CDN |

AMD/RequireJS is no longer supported as of 1.3.0. The bundles target ES2019, so Internet Explorer is no longer supported either — use 1.2.x if you need either.

TypeScript

Types ship with the package — there is no @types/jalali-date to install, and nothing to configure. The library itself stays JavaScript; the declarations are hand written in types/jdate.d.ts and emitted per module format, so import and require each get the shape they actually receive at runtime.

import JDate, { type JalaliDate, type JDateConfig } from 'jalali-date';

const jdate = new JDate([1396, 8, 26], { persianNumerical: true });
const formatted: string = jdate.format('dddd DD MMMM YYYY');
const parts: JalaliDate = jdate.date;

Under require, the same types come through a namespace on the class:

import JDate = require('jalali-date');

const config: JDate.JDateConfig = { persianNumerical: true };

The constructor is typed as four overloads, so the argument mistakes that fail quietly at runtime fail at compile time instead — new JDate([1396, 8]) builds an Invalid Date rather than throwing, and is rejected here because JalaliDate is a three-element tuple. Config entry counts stay a runtime check, so that a name list inferred as string[] rather than as a fixed-length tuple can still be passed.

Initialization

For initializing JDate you may either pass an array of Jalali date to it or a Date object. If no parameter is passed, the default is today:

const jdate = new JDate; // => default to today
const jdate2 = new JDate(1393, 10, 11);
const jdate3 = new JDate([1393, 10, 11]);
const jdate4 = new JDate(new Date(2014, 1, 3));

Every form also takes an optional config object as its last argument.

API

jdate.date //=> [1393, 5, 13] An Array of Jalali Date
jdate._d // => Gregorian Date Object

// Getters
jdate.getFullYear() // => 1393
jdate.getMonth() // => 5
jdate.getDate() // => 13
jdate.getDay() // => 1

// Setters
jdate.setFullYear(1394)
jdate.setMonth(6)
jdate.setDate(12)

// Formatting output
jdate.format('dddd DD MMMM YYYY') // => پنج‌شنبه 12 شهریور 1394

// Static functions
JDate.isLeapYear(1393) // => false
JDate.daysInMonth(1393, 5) // => 31
JDate.toGregorian(1393, 12, 11) // => Gregorian Date object
JDate.toJalali(new Date) // => JDate object

// Display options (see Configuration)
jdate.config // => the frozen names and options this instance formats with
JDate.setDefaultConfig({ monthNames: [...] })
JDate.getDefaultConfig()
JDate.resetDefaultConfig()

Note on month numbering. Unlike Date#getMonth/Date#setMonth, months on an instance are one-based1 is فروردین and 12 is اسفند. getDate() is likewise 131. Values passed to setMonth() outside 1..12 roll the year over, so setMonth(13) gives month 1 of the following year.

The static JDate.daysInMonth(year, month) is the exception: it is zero-based (0 is فروردین, 11 is اسفند), so it does not compose directly with getMonth():

JDate.daysInMonth(jdate.getFullYear(), jdate.getMonth() - 1) // note the -1

This inconsistency is retained for backwards compatibility and is expected to be resolved in a future major version.

Formatting output

Use format() and following conversion identifiers as follows:

date.format('dddd D MMMM YYYY') //=> دوشنبه 6 امرداد 1393

The conversion identifiers are as follows:

| Identifier | Description | Example | | ------------- | ------------- | ---------- | | YYY or YYYY | Full Year (4 digits) | 1393 | | YY | Year (2 digits) | 93 | | M | Month in number | returns 5 for امرداد | | MM | Month in number | returns 05 for امرداد | | MMM or MMMM | Month in string | امرداد | | D | Day in number | 26 | | DD | Day in number | 06 | | d or dd | Abbreviation of day name in string | ۱ش (for یکشنبه) | | ddd or dddd | Full day name in string | یکشنبه |

Anything that is not an identifier is passed through unchanged, so separators need no special treatment:

date.format('YYYY-MM-DD') //=> 1393-05-06

Escaping literal text

Identifiers are matched wherever they appear, including inside words. To keep literal text that contains a Y, M, D or d, wrap it in square brackets:

date.format('[Day] D')      //=> Day 6
date.format('Day D')        //=> 6ay 6     (the D in "Day" is an identifier)
date.format('YYYY [در] MMMM') //=> 1393 در امرداد

Write [[] for a literal [. A bracketed run cannot itself contain ], and an unterminated [ opens literal mode that runs to the end of the format string:

date.format('MM [YYYY') //=> 05 YYYY

A run of an unsupported length is left alone rather than partly consumed — YYYYY and DDD come back as-is.

Configuration

What format() prints defaults to Persian names and ASCII digits, and can be changed with a config object. There are four keys, all optional:

| Key | Value | Used by | Notes | | --- | ----- | ------- | ----- | | monthNames | 12 strings | MMM, MMMM | calendar order, فروردین first | | dayNames | 7 strings | ddd, dddd | Sunday first, matching Date#getDay() | | abbrDays | 7 strings | d, dd | Sunday first, matching Date#getDay() | | persianNumerical | boolean | YYYY, YY, M, MM, D, DD | false by default; true prints Persian digits |

Keys you leave out keep their built-in values.

Persian numerals

The numeric identifiers print ASCII digits unless persianNumerical is true:

new JDate([1396, 8, 26]).format('YYYY/MM/DD')                            //=> 1396/08/26
new JDate([1396, 8, 26], { persianNumerical: true }).format('YYYY/MM/DD') //=> ۱۳۹۶/۰۸/۲۶

It applies only to those identifiers. Names come out of the config verbatim, so a Latin abbreviation keeps its own digits, and bracketed literals are never touched:

const jdate = new JDate([1396, 8, 26], { persianNumerical: true });

jdate.format('dddd DD MMMM YYYY') //=> جمعه ۲۶ آبان ۱۳۹۶
jdate.format('[Day 1] D')         //=> Day 1 ۲۶

It is false by default so that existing output does not change; set it app-wide with JDate.setDefaultConfig({ persianNumerical: true }) if you want it everywhere.

Note that false does not mean "ASCII everywhere". The built-in abbrDays are written with Persian digits already (۱ش, ۲ش, …), so d/dd print them whatever this is set to. Override abbrDays if you need those in ASCII too.

Per instance

Pass the config as the last constructor argument, in any of the four initialization forms:

const en = {
  monthNames: ['Farvardin', 'Ordibehesht', 'Khordad', 'Tir', 'Mordad', 'Shahrivar',
               'Mehr', 'Aban', 'Azar', 'Dey', 'Bahman', 'Esfand'],
  dayNames: ['Yekshanbe', 'Doshanbe', 'Seshanbe', 'Chaharshanbe',
             'Panjshanbe', 'Jome', 'Shanbe']
};

new JDate([1396, 8, 26], en).format('dddd DD MMMM YYYY') //=> Jome 26 Aban 1396
new JDate(1396, 8, 26, en)
new JDate(new Date(2017, 10, 17), en)
new JDate(en)                             // today, with these names

Because it is per instance, two locales can be rendered side by side:

new JDate([1396, 8, 26]).format('MMMM')     //=> آبان
new JDate([1396, 8, 26], en).format('MMMM') //=> Aban

Application-wide

JDate.setDefaultConfig() sets what every instance created afterwards will use:

JDate.setDefaultConfig(en);

new JDate([1396, 8, 26]).format('dddd MMMM') //=> Jome Aban

// still overridable per instance, layered over the default
new JDate([1396, 8, 26], { dayNames: [...] }).format('dddd MMMM')

JDate.resetDefaultConfig(); // back to the built-in Persian names and ASCII digits

Two things to know about it:

  • It replaces the default rather than merging into whatever a previous call left behind, so the result depends only on what you pass. Two partial calls do not accumulate — the second one's omitted keys revert to their built-in values.
  • Instances capture the default when they are constructed, so calling it later does not retroactively change dates that already exist.

Validation

A config is checked when it is passed, so mistakes surface at the call site instead of as undefined inside formatted output:

new JDate([1396, 8, 26], { monthName: [...] })
// Error: JDate config: unknown key "monthName", expected one of monthNames, abbrDays, dayNames, persianNumerical

new JDate([1396, 8, 26], { monthNames: ['Farvardin', 'Ordibehesht'] })
// Error: JDate config: "monthNames" must have 12 entries, got 2

new JDate([1396, 8, 26], { dayNames: 'Jome' })
// Error: JDate config: "dayNames" must be an array of 7 strings

new JDate([1396, 8, 26], { persianNumerical: 'yes' })
// Error: JDate config: "persianNumerical" must be a boolean

persianNumerical is checked strictly rather than for truthiness, so a typo is an error instead of quietly meaning true — as 'false' otherwise would.

The config must be a plain object; anything else in that position is rejected as Unexpected input. The resolved config is frozen and its arrays are copied, so jdate.config cannot be mutated and changing the array you passed in afterwards does not reach back into an existing instance.

Contribute

Report bugs and suggest feature in issue tracker. Feel free to Fork and send Pull Requests.

| Script | What it does | | ------ | ------------ | | npm test | Runs the unit tests against src/ | | npm run lint | ESLint over the sources, tests and scripts | | npm run build | Writes the bundles and declarations into lib/ | | npm run watch | The same, rebuilding on change | | npm run test:types | Compiles tests/types/ against the built declarations | | npm run test:bundles | Checks the bundles still export what those declarations describe | | npm run test:exports | Checks that every way of importing the package resolves to types |

The last three read lib/, so run npm run build first. Changing the public API means changing types/jdate.d.ts alongside src/ — nothing generates one from the other.

License

MIT