Skip to content

Releases: shivathapaa/nepali_calendar_utils

v3.1.0

Choose a tag to compare

@shivathapaa shivathapaa released this 19 Sep 12:24
3004f09

A holiday is one kind of calendar event. The package now names festivals, school programmes, deadlines and birthdays as well, marks whether a day is worked with a flag on the event rather than through its category, and states an institution's whole calendar, its week and its events, as a single policy.

This release also brings the package level with the Kotlin core it is ported from: whole-month reads, a calendar-tagged month, and the time half of the cross-platform wire format.

Every 3.0.0 name keeps working. No source change is required to upgrade.

Install

pip install nepali_calendar_utils==3.1.0

Requires Python 3.11 or newer. Tested on 3.11, 3.12 and 3.13 across Linux, macOS and Windows. No runtime dependencies.

Highlights

  • NepaliCalendarEvent replaces HolidayEntry, adding closes_offices, id and payload.
  • NepaliCalendarPolicy holds the week an institution keeps and the events it names, and answers status_of, month_status, events_on, events_in and as_selectable_dates from both.
  • spanning_days and spanning_through expand a festival or a stretch of leave into one entry per day.
  • Providers compose: national + own_list, and provider.filtered(predicate).
  • get_english_calendar and is_english_date_convertible read and test a Gregorian date directly.
  • Whole-month reads convert a month in one pass instead of one call per day.
  • CalendarSystem and MonthCalendar let layout code stop caring which calendar produced a month.
  • NepaliTimeFormatter completes the cross-platform wire format.
  • Three correctness fixes, and a faster, lighter import.

Events

NepaliCalendarEvent(date, name, kind, closes_offices=None, id=None, payload=None) is one named day. Whether the institution shuts is closes_offices, not the category, so two days can both be called Dashain and only one of them close the school. Left unset it follows the kind: a GOVERNMENT_PUBLIC, RELIGIOUS or REGIONAL entry closes the day and an OBSERVANCE does not.

from nepali_calendar_utils import (
    NepaliCalendarEvent, NepaliEventKind, NepaliEventProvider, SimpleDate,
)

class MyEvents(NepaliEventProvider):
    _by_year = {
        2082: {
            NepaliCalendarEvent(SimpleDate(2082, 1, 1), "नयाँ वर्ष",
                                NepaliEventKind.GOVERNMENT_PUBLIC),
        },
    }

    def events(self, year):
        return self._by_year.get(year, set())
  • id and payload are carried through untouched, for an app to correlate a day back to its own record.
  • NepaliEventKind.priority orders the kinds when several land on one day, strongest first.
  • provider.closes_on(date) counts only the entries that close, so a day carrying nothing but a programme stays a working day.
  • first + second reports everything either side reports, keeping both entries on a day they both name. A day either side calls a closure stays a closure.
  • provider.filtered(predicate) narrows a shared list to what one screen cares about, and narrows its closures with it.

No event data ships with the library, by design: Nepali holiday lists change year to year and every institution keeps its own.

Calendar policy

NepaliCalendarPolicy(weekly_off_days, provider) states an institution once. A number that is not a day of the week is rejected at construction.

from nepali_calendar_utils import NepaliCalendarPolicy, next_working_day

office = NepaliCalendarPolicy(provider=my_events)             # closed Saturdays
school = NepaliCalendarPolicy(frozenset({7, 1}), my_events)   # closed Saturday and Sunday

school.status_of(SimpleDate(2082, 1, 1)).names    # ['नयाँ वर्ष']
school.month_status(2082, 1)                      # one status per day, index 0 is day 1
school.is_non_working_day(SimpleDate(2082, 1, 1)) # True
next_working_day(SimpleDate(2082, 1, 1), school)  # the policy carries its own weekend
  • status_of(date) returns a NepaliDayStatus: whether the week makes the day off, what is named on it strongest kind first, plus is_non_working, primary_kind, names and closures.
  • month_status(year, month) answers for a whole month in one pass.
  • as_selectable_dates() turns the policy into a picker rule. Marking a day and refusing it stay separate decisions, and an event that leaves the institution open leaves its day selectable.
  • The working-day helpers take a policy in place of a provider and a weekend. Passing both is refused.

Multi-day spans

An event covers exactly one day, so a span is a list of entries, each carrying the event's name, kind, closes_offices, id and payload unchanged.

event.spanning_days(10)
event.spanning_through(SimpleDate(2082, 6, 26))
  • A span running out of Chaitra into Baisakh yields entries in both years, so each is reported by the year a provider is asked for.
  • Give the event an id first when the days have to be recognized as one thing again.
  • spanning_through raises rather than rolling a day past the end of its month, which would return a span of the wrong length.

New in the converter

  • get_english_calendar(year, month, day) returns a fully populated Gregorian CustomCalendar read straight from a Gregorian date. It needs no conversion anchor, so it answers for any year, and its derived fields follow the same definitions the Bikram Sambat calendars use.
  • is_english_date_convertible(year, month, day) reports whether an English date has a Bikram Sambat equivalent. EnglishYearRange alone is not a sufficient check: the calendars start mid-year relative to each other, so 1913-01-01 through 1913-04-12 sit inside the year range yet cannot convert.
  • Whole-month reads: get_english_calendars_in_month, get_nepali_calendars_in_english_month and get_english_calendars_in_nepali_month. Each converts the month in one pass, so prefer them over calling a converter in a loop. A Gregorian day before the anchor reads as None, never as a guess.
  • NepaliCalendarDefaults gains minConvertibleEnglishDate, maxConvertibleEnglishDate, GregorianYearRange and gregorian_year_range_for(...), so a Gregorian-first caller can bound itself without knowing where the conversion table starts.

Calendar systems and months

  • CalendarSystem names the two calendars by the era they carry, with opposite() and from_era, which answers None for an unrecognised era rather than raising. CustomCalendar.calendar_system reads it. A calendar carries the system it was read in, so a Gregorian read stays Gregorian.
  • MonthCalendar says what NepaliMonthCalendar says, for a month of either calendar, tagged with its system. get_english_month_calendar answers one for a Gregorian month, NepaliMonthCalendar.to_month_calendar() reads one from a Bikram Sambat month, and MonthCalendar.to_nepali_month_calendar() narrows one back. The narrowing copies the year and month verbatim, so calling it on a Gregorian month yields a NepaliMonthCalendar holding Gregorian numbers; convert first when that matters.

Times on the wire

NepaliTimeFormatter is the counterpart of NepaliDateFormatter, completing the wire format a Kotlin, Android, Swift or JavaScript client reads without translation.

NepaliTimeFormatter.format(SimpleTime(9, 30, 0, 0))            # "09:30:00"
NepaliTimeFormatter.format(SimpleTime(23, 59, 59, 123456789))  # "23:59:59.123456789"
NepaliTimeFormatter.parse("०९:३०:००")                           # SimpleTime(9, 30, 0, 0)
NepaliTimeFormatter.parse("24:00:00")                          # None

format writes HH:mm:ss, gaining a nine-digit fractional part only when the nanosecond is non-zero. parse returns None rather than raising. Field widths are not enforced and any Unicode decimal digit is accepted, so Devanagari input reads the same as Latin; whitespace, a sign and a digit separator are all refused.

Fixes

  • NepaliDateLocale.digit_script now reaches format_nepali_date and format_english_date. Both read the numeral script from the locale's language and ignored an explicit override, so NepaliDateLocale(language=NEPALI, digit_script=LATIN) still rendered Devanagari digits. A locale that leaves digit_script unset is unaffected.
  • get_english_date_nepali_time_from_iso_format reads the Gregorian date straight from the timestamp instead of routing through Bikram Sambat and back, which had limited it to EnglishYearRange for a result that never needed the conversion table. Any year now parses. get_nepali_date_time_from_iso_format still requires the table.
  • get_nepali_calendar rejects a day below 1. A day of 0 or a negative day used to build a calendar whose derived fields described nothing.

Performance

  • Month geometry is derived on demand instead of every supported month being built at import, so importing the package is faster and holds less memory.
  • Unicode pattern formatting compiles its token matcher once rather than on every call.

Migrating from 3.0.0

The former names still resolve, so nothing has to change today. Importing from nepali_calendar_utils.holiday raises a DeprecationWarning naming the replacement.

3.0.0 3.1.0
HolidayEntry NepaliCalendarEvent
HolidayKind NepaliEventKind
NepaliHolidayProvider NepaliEventProvider
NoOpHolidayProvider NoOpEventProvider
provider.holidays(year) provider.events(year)
provider.is_holiday(date) provider.closes_on(date)
excluding_holidays(base, provider) excluding_closures(base, provider)
nepali_calendar_utils.holiday nepali_calendar_utils.event

A provider written against NepaliHolidayProvider keeps working as it is: it stays a real class, its holidays and is_holiday are what the policy and the helpers read, and it keeps the older rule that every en...

Read more

v3.0.0

Choose a tag to compare

@shivathapaa shivathapaa released this 03 Sep 06:18
a827bad

Brings the Python package to feature parity with the :core module of the sibling Kotlin Multiplatform project, Nepali-Date-Picker (3.1.0). This is an additive release - every prior public symbol works unchanged and all new APIs are opt-in. The major version bump aligns the package with the Kotlin 3.x line.

The underlying Bikram Sambat data tables (day counts and reference anchors, years 1970–2100) are byte-for-byte identical to the Kotlin core, so conversions match exactly across both libraries.

Highlights

  • Language-independent digit script (DigitScript) with digit-localization helpers.
  • A NepaliDateFormatter for parsing/formatting short numeric date strings.
  • A holiday-provider SPI with working-day arithmetic (WORKDAY semantics).
  • Selectable-date predicates and before/after/range factories.
  • SimpleDate is now orderable (sorted, min, max, </>).
  • Correctness fixes: live "today", the 1913 anchor guard, week_of_month, parse.
  • Dependency-free and portable: no IANA tz database needed; honest requires-python.
  • Test suite more than doubled (117 → 257); a published Sphinx API reference.

New features

DigitScript: numeral script (LATIN / DEVANAGARI) decoupled from language, so any Devanagari-digit locale (Nepali, Hindi, Marathi, Maithili, Bhojpuri, Newari) reuses the same rendering. Helpers: default_digit_script, to_latin_digits, latin_digit_or_none, and NepaliDateConverter.localize_digits / .to_latin_digits.

from nepali_calendar_utils import NepaliDateConverter, DigitScript
NepaliDateConverter.localize_digits("2082/02/14", DigitScript.DEVANAGARI)  # "२०८२/०२/१४"
NepaliDateConverter.to_latin_digits("२०८२/०२/१४")                          # "2082/02/14"

NepaliDateFormatter: a parse/format primitive for short text-field input, with four DatePatterns (YYYY/MM/DD, YYYY-MM-DD, DD/MM/YYYY, DD-MM-YYYY). Accepts both Latin and Devanagari input; parse returns None on invalid input.

from nepali_calendar_utils import NepaliDateFormatter, DatePattern
NepaliDateFormatter.parse("२०८२/०२/१४", DatePattern.YYYY_SLASH_MM_SLASH_DD)  # SimpleDate(2082, 2, 14)

Holiday provider SPI: a new nepali_calendar_utils.holiday package: NepaliHolidayProvider, HolidayEntry, HolidayKind, NoOpHolidayProvider, and NepaliWeekend (Saturday-only default). No holiday data ships by design. Working-day arithmetic: working_days_between, next_working_day, add_working_days (Excel WORKDAY semantics), plus excluding_holidays / excluding_weekends wrappers. Also surfaced on the NepaliDateConverter facade.

NepaliSelectableDates: a predicate for enabling/disabling dates, with converter factories before_date_selectable, after_date_selectable, and date_range_selectable.

NepaliDateLocale.digit_script: an optional explicit numeral script with a resolved_digit_script property (None follows the language).

SimpleDate is ordered: supports <, >, sorted(), min(), and max() (chronological by year, then month, then day).

Correctness fixes

  • today_nepali_calendar / today_english_simple_date / today_english_calendar now read the wall clock on each access. They were captured once when the model was constructed, so "today" never rolled over at midnight for a long-lived instance.
  • English dates before the earliest convertible anchor (1913-04-13) now raise ValueError. They previously passed the year-only range check and silently returned Nepali 1970-01-01.
  • Out-of-table years raise a clear ValueError instead of leaking a KeyError, and get_total_days_in_nepali_month validates the month range.
  • week_of_month uses the clamped day of month when a date is adjusted.
  • NepaliCalendarModel.parse("YYYYMMDD") now returns a real CustomCalendar (it previously always returned an error stub because it passed a dict where a SimpleDate was expected). Logically invalid in-range dates return the documented stub with era=2 and -1 sentinel fields.

Dependencies and portability

  • requires-python is now >=3.11. The ISO 8601 conversion utilities rely on datetime.fromisoformat fully parsing offsets-with-seconds and the Z suffix, which landed in Python 3.11. (The previous >=3.7 floor was inaccurate - the package already used zoneinfo, which is 3.9+.)
  • No third-party runtime dependencies. Time-zone handling switched from ZoneInfo("Asia/Kathmandu") to a fixed +05:45 offset (datetime.timezone). Nepal Standard Time has no DST or transitions in the supported range, so results are identical - but it no longer needs the IANA tz database, so it works on Windows and minimal containers where ZoneInfo would raise ZoneInfoNotFoundError. This mirrors the Kotlin core's FixedOffsetTimeZone.

Performance

  • Month-details lookups are memoized and the day offset is computed in O(1) via a cumulative-days prefix table, instead of re-summing every year on each call. Behavior-preserving.

Tests and docs

  • Test suite expanded from 117 to 257 cases, mirroring the Kotlin :core suite and adding exhaustive invariants: every-year conversion round-trips, a cross-engine agreement check (offset table vs day-walk), a week-of-year suite with an independent Gregorian weekday oracle (stdlib date), leap-year and month-length range checks, date arithmetic, comparison, parse/locale, and holiday working-day edge cases.
  • A Sphinx API reference is published at shivathapaa.github.io/nepali_calendar_utils, with source links back to GitHub.

Install

pip install nepali_calendar_utils
from nepali_calendar_utils import NepaliDateConverter
converter = NepaliDateConverter()
nepali = converter.convert_english_to_nepali(2025, 6, 15)   # -> CustomCalendar (BS 2082-03-01)

Compatibility / upgrade notes

  • No public API was removed or renamed; existing 2.x code keeps working.
  • The only upgrade action is the interpreter floor: the package now requires Python 3.11+. Installs on 3.7–3.10 (where the ISO utilities never fully worked anyway) are no longer supported.

v2.0.1

Choose a tag to compare

@shivathapaa shivathapaa released this 20 May 18:29
47b2060

Overview

  • Bug fixes (Fix Nepali dates of year 2082 according to Panchanga)

v2.0.0

Choose a tag to compare

@shivathapaa shivathapaa released this 14 May 21:58
85ef865

Overview

  • Added various utilities to format date and time using unicode pattern.
  • Added iso to date time formatting. It converts ISO UTC format to CustomCalendar and SimpleTime. See examples

Breaking Changes

  • Bumped minimum python version from 3.6 to 3.7 to support iso formatting.

v1.1.0

Choose a tag to compare

@shivathapaa shivathapaa released this 25 Jan 10:56
f501df3

Overview

The version 1.1.0 has some changes in class naming. Now, some classes are name by their use cases.

New features

  • Add today's SimpleDate property for Nepali date.
  • Add today's CustomCalendar date property for both English date.

Bug Fixes/Improvements

  • Rename classes for functional identification.
  • Add documentation for core data classes.

v1.0.0

Choose a tag to compare

@shivathapaa shivathapaa released this 24 Jan 18:43
3e86e95

First stable release of nepali_calendar_utils package

  • The packge is packed with various utilities for date conversions, and date and time representation.

Use in your projects

Checkout documentation here