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

nepali-date-utils

v1.0.0

Published

Bikram Sambat (BS) calendar data, BS<->AD conversion, and BS date-string utilities for Nepali dates. Zero dependencies, dual ESM/CJS, fully typed.

Downloads

157

Readme

nepali-date-utils

npm version license types

Bikram Sambat (BS) calendar data, BS↔AD conversion, and BS date-string utilities for Nepali dates.

Zero runtime dependencies · dual ESM/CJS · fully typed · ~8 kB gzipped · tree-shakeable.

Built around a NepaliDate class that is API-compatible with the widely used nepali-date-converter package, so it can be swapped in without touching call sites — but backed by a calendar table that is verified against official BS new-year dates and guarded by tests.

Installation

npm install nepali-date-utils
# or
yarn add nepali-date-utils
# or
pnpm add nepali-date-utils

Quick start

import {
  NepaliDate,
  adToBs,
  bsToAd,
  getTodayBs,
  isValidDateString,
} from "nepali-date-utils";

// today in BS
const today = new NepaliDate();
today.format("YYYY-MM-DD"); // e.g. "2083-04-13"
getTodayBs(); // same, as a string in one call

// convert
bsToAd(2081, 1, 1); // Date: 2024-04-13 (local midnight)
adToBs(new Date(2024, 3, 13)); // { year: 2081, month: 1, day: 1 }

// validate user input before trusting it
isValidDateString("2081-02-32"); // true  (BS months really have 32 days)
isValidDateString("2081-02-33"); // false

Plain JavaScript works identically — there is nothing TypeScript-only in the API:

const { NepaliDate } = require("nepali-date-utils"); // CJS build resolves automatically
new NepaliDate(2081, 0, 15).format("MMMM D, YYYY"); // "Baisakh 15, 2081"

Coverage & accuracy

  • Range: BS 1970-01-01 through 2099-12-30 (AD 1913-04-13 onwards).
  • Anchor: BS 1970-01-01 = AD 1913-04-13, a Sunday. All conversion is pure day-count arithmetic from that anchor, computed in UTC so the device timezone can never shift a date.
  • Verification: month lengths are cross-checked against official BS new-year dates for 2000, 2050, 2070, 2075 and 2080–2084; the whole range is weekday-chain consistent. Years beyond ~2085 are projections (Nepal publishes the official calendar only a year or two ahead) kept for UI range purposes — don't trust them for legal dates.
  • Every year row is guarded by a test asserting its 12 month lengths sum to its year total. Never hand-edit a single month without running the test suite — an off-by-one shifts every conversion after it.

API reference

NepaliDate

API-compatible replacement for nepali-date-converter's default export. Date-only — time of day is intentionally not carried.

new NepaliDate()                      // today
new NepaliDate(adDate: Date)          // from an AD date (read in local time)
new NepaliDate(other: NepaliDate)     // clone
new NepaliDate(2081, 0, 15)           // BS year, month0, day — month is 0-INDEXED
NepaliDate.fromAD(date: Date)         // alias for new NepaliDate(date)

Two compatibility quirks inherited from nepali-date-converter — both are load-bearing, not accidents:

  • getMonth() is 0-indexed (0 = Baishakh), like JS Date. The string helpers below use 1-indexed months; convert deliberately at the boundary.
  • JS-Date-style rollover: out-of-range parts normalize instead of throwing — new NepaliDate(2081, 12, 1) is BS 2082-01-01, day 0 is the last day of the previous month.

| Method | Returns | | -------------------------------------------- | -------------------------------------------------------------------------------------- | | getYear() | BS year | | getMonth() | BS month, 0-indexed | | getDate() | day of month, 1-indexed | | getDay() | weekday, 0 = Sunday | | setYear(y) / setMonth(m0) / setDate(d) | mutates in place (rollover applies) | | toJsDate() | AD Date at local midnight | | format(pattern, language?) | formatted string; language is "en" (default) or "np" (Devanagari digits + names) | | toString() | format("YYYY-MM-DD") |

Format tokens: YYYY YY MMMM MMM MM M DD D dddd ddd dd d.

const d = new NepaliDate(2081, 2, 5);
d.format("dddd, MMMM D"); // "Wednesday, Asar 5"
d.format("YYYY-MM-DD", "np"); // "२०८१-०३-०५"

Conversion functions

bsToAd(year: number, month: number, day: number): Date   // month 1-INDEXED here
adToBs(date: Date): BsDateParts                           // { year, month (1-indexed), day }

String helpers

The library's canonical format is the zero-padded "YYYY-MM-DD" BS string (BsDateString). All helpers are pure.

| Function | Behaviour | | ------------------------------- | --------------------------------------------------------------------------------------------------------------- | | isValidDateString(s) | true only for strict "YYYY-MM-DD" naming a real BS day | | isValidDate(y, m, d) | same check from numeric parts (month 1-indexed) | | parseDateString(s) | [year, month, day] numbers — does not validate; guard with isValidDateString for user input | | formatDate(y, m, d) | zero-padded "YYYY-MM-DD" | | isBetween(date, start?, end?) | inclusive range check; a missing/malformed bound is open-ended; malformed date is never in range | | getMonthData(y, m) | { totalDays, startDay } for a calendar grid; both undefined outside the table (render nothing, don't throw) | | getTodayBs() | today as BsDateString (device clock, local time) |

NepaliDate helpers

Pure, immutable functions over NepaliDate instances — arithmetic returns new instances. All throw only at the calendar-table edges (documented per function).

| Function | Behaviour | | ---------------------------------------------- | ---------------------------------------------------------------------------------------------- | | isSameDay(a, b) / isSameMonth(a, b) | calendar equality checks | | isBefore(a, b) / isAfter(a, b) | strict ordering | | addDays(date, n) | O(1) day offset, exact across month/year boundaries | | addMonths(date, n) | month offset with day clamping (Jestha 32 + 1 month → shorter month's last day) | | startOfWeek(date) / endOfWeek(date) | Sunday/Saturday bracketing the containing week | | daysBetween(a, b) | absolute day distance, order-independent | | parseNepaliDate(str) | lenient parse (2081-3-5, 2081/3/5) → NepaliDate or null; never rolls invalid days over | | adToBsString(date) | AD Date"YYYY-MM-DD" BS string | | bsToAdString(bs) | BS string → AD "YYYY-MM-DD" string, null if invalid | | toNepaliNumerals(v) / toEnglishNumerals(s) | ASCII ↔ Devanagari digit conversion, non-digits pass through |

import {
  NepaliDate,
  addDays,
  daysBetween,
  parseNepaliDate,
  toNepaliNumerals,
} from "nepali-date-utils";

const due = addDays(new NepaliDate(), 30);
daysBetween(new NepaliDate(), due); // → 30
parseNepaliDate("2081/3/5")?.toString(); // → "2081-03-05"
toNepaliNumerals("2081-01-15"); // → "२०८१-०१-१५"

Constants

| Export | What it is | | ------------------------------- | --------------------------------------------------------------- | | MIN_BS_YEAR / MAX_BS_YEAR | table bounds — derive UI year ranges from these, never hardcode | | CALENDAR_DATA | { [bsYear]: number[13] } — 12 month lengths + year total | | FIRST_DAY_OF_MONTH | derived { [bsYear]: weekday[12] } for calendar grids | | NEPALI_MONTHS / NEPALI_DAYS | display names, useful for datepicker headers | | LOCALE | en/np month, weekday, and digit strings for format() |

Types

BsDateParts, BsDateString, and BsMonthData are exported as types for use in your own signatures.

Error handling

Conversions throw (with the supported range in the message) when a date falls outside BS 1970–2099. Two idioms:

// user input → validate first, never try/catch
if (!isValidDateString(input)) return showFieldError();

// programmatic dates near the table edge → catch the range error
try {
  const d = new NepaliDate(year, month0, day + offset);
} catch {
  // clamp, or surface "date out of supported range"
}

getMonthData is the exception: it returns undefined fields instead of throwing, because calendar grids need to render gracefully at the table edge.

FAQ

Why is NepaliDate's month 0-indexed but everything else 1-indexed? NepaliDate mirrors nepali-date-converter (and JS Date) so it can be swapped in without touching call sites. The string/parts helpers are 1-indexed because that's how humans write dates. The type signatures and docs mark which is which.

Why strings rather than NepaliDate everywhere? Strings are serializable (forms, APIs, state stores) and cheap to compare. Construct a NepaliDate only when you need arithmetic or formatting.

What happens after BS 2099? Conversions throw. Extend CALENDAR_DATA as Nepal publishes new years — append rows, run the tests (the integrity test guards every row), done. PRs welcome.

Timezones? All arithmetic is UTC-internal; bsToAd/toJsDate hand back local midnight so downstream getFullYear()-style reads match what the user sees on a wall calendar.

Does this render a datepicker? No — this package is calendar logic only, deliberately UI-framework agnostic. getMonthData, FIRST_DAY_OF_MONTH, and NEPALI_MONTHS/NEPALI_DAYS give you everything needed to build a grid in React, Vue, Svelte, or plain DOM.

Performance

Day-offsets per year are precomputed once at module load (~130 years); conversions after that are array lookups plus integer math — suitable for hot paths like rendering calendar grids. No dependencies, ~8 kB gzipped for the full bundle including the calendar table, tree-shakeable (sideEffects: false) so unused helpers drop out.

Contributing

Issues and PRs are welcome at github.com/nativeTiger/nepali-date-utils.

git clone https://github.com/nativeTiger/nepali-date-utils.git
cd nepali-date-utils
npm install

npm run build       # tsdown → dual ESM/CJS + .d.ts
npm test            # node:test suite
npm run type-check  # tsc --noEmit

Development requires Node ≥ 22.6 — the test suite runs TypeScript directly via node's type stripping. (The published package targets Node ≥ 18.)

Calendar-data changes must keep the integrity test green — it asserts every year's 12 month lengths sum to its recorded year total. If you're adding a newly published BS year, cite the official source in the PR.

Releasing

./release.sh 1.0.1     # verifies, bumps, commits, tags — does not push
git push origin main v1.0.1
npm publish            # prepublishOnly rebuilds; publishConfig sets public access

Check the tarball with npm pack --dry-run first — only dist/, README.md, and LICENSE should ship.

License

MIT © nativeTiger