Events, day status and working days¶
What a calendar has on a day, when an institution is closed, and the arithmetic that
counts the days it opens. No event data ships with the library by design; a consumer
plugs in a NepaliEventProvider.
Events¶
A named day in the Bikram Sambat calendar, and the spans built from one.
- class NepaliEventKind(value)[source]¶
Bases:
EnumWhat kind of thing an event is, which is what a calendar colors by.
Deliberately narrow, because adding a case is a breaking change. An app with its own taxonomy picks the closest kind and keeps its own category in
NepaliCalendarEvent.payload; whether the day is worked isNepaliCalendarEvent.closes_offices’s job either way.- GOVERNMENT_PUBLIC = 'government_public'¶
Bank / government office is closed. Sarkari bida.
- RELIGIOUS = 'religious'¶
Dashain, Tihar, Holi, Id, Christmas, and the like.
- Type:
Religious or cultural
- REGIONAL = 'regional'¶
Province- or district-level, not nationally observed.
- OBSERVANCE = 'observance'¶
World Health Day, a school programme, a meeting.
- Type:
Recognized but ordinarily worked
- property priority: int¶
How strongly a kind describes a day when several land on it, lowest first.
A day the offices close is called that before anything else it also happens to be, and an observance yields to everything. Sorting and color resolution both read this, so the two never disagree.
- property closes_offices_by_default: bool¶
Whether an event of this kind usually shuts the institution.
This is what
NepaliCalendarEvent.closes_officesfalls back to. Only a starting point: the event itself has the final say, because the same kind closes one place and not another.
- class NepaliCalendarEvent(date, name, kind, closes_offices=None, id=None, payload=None)[source]¶
Bases:
objectSomething that happens on one Bikram Sambat day.
A public holiday, a festival, a school programme, a deadline, a birthday. A holiday is an event like any other; what separates them is
closes_offices, not the name: two days can both be called Dashain and only one of them close the school. That is why the flag lives here rather than onkind, where a taxonomy would have to decide for every institution at once.- Parameters:
date (SimpleDate)
name (str)
kind (NepaliEventKind)
closes_offices (bool | None)
id (str | None)
payload (str | None)
- date¶
Bikram Sambat date the event falls on. One day per entry, so a ten-day festival is ten entries, which
spanning_days()andspanning_through()build from one.- Type:
- kind¶
Category, which is what a calendar colors by.
- Type:
- closes_offices¶
Whether the institution is shut for this. Leave it unset (
None) to take whatkindusually means, so aGOVERNMENT_PUBLICentry closes the day and anOBSERVANCEdoes not; the attribute is a plainboolonce constructed. Either default can be overridden: a regional holiday closes one district and not the next, and a school programme closes nothing at all.- Type:
- id¶
An identifier the app can correlate back to its own record, carried through untouched. The library never reads it.
- Type:
- payload¶
Anything else the app wants back when the day is tapped, as an opaque string: JSON, a URL, an identifier list. The library never parses it.
- Type:
- spanning_days(days)[source]¶
This event on each of
daysconsecutive days, starting on its own date.A
NepaliCalendarEventcovers a single day, so a span is a list of entries rather than a range. Every entry keeps this event’sname,kind,closes_offices,idandpayload, and differs only in its date. A span running out of Chaitra into Baisakh yields entries in both years, so each one is reported by the year a provider is asked for.Give the event an
idfirst when the days have to be recognized as one thing again. Nepal’s published holiday lists name each day separately, so prefer real per-day names where they exist and keep this for a span an app owns.The event’s own date is taken as stated, the way every other call here treats it, so only the length of the span is checked.
- Parameters:
days (int) – How many days the span covers, counting the first.
1returns this event alone.- Returns:
One entry per day, in date order.
- Return type:
- Raises:
ValueError – if
daysis below 1, or if the span runs pastNepaliCalendarDefaults.NepaliYearRange.
- spanning_through(end)[source]¶
This event on each day from its own date through
end, both included.That is the shape published holiday lists and leave requests usually state a span in. Expands the same way
spanning_days()does: an entry per day, carrying everything but the date unchanged. Anendequal to this event’s date returns the event alone.- Parameters:
end (SimpleDate) – Last day of the span, included.
- Returns:
One entry per day, in date order.
- Return type:
- Raises:
ValueError – if
endfalls before this event’s date, ifendis not a day its month has, or if the span runs pastNepaliCalendarDefaults.NepaliYearRange. A day the month does not reach is refused rather than rolled into the next one, since rolling would silently return a span of the wrong length.
Provider SPI¶
Service-provider interface for supplying a calendar’s events.
This library ships no data by design: Nepali holiday lists change year to year
and every institution keeps its own, so nothing here could be right for long.
Implement NepaliEventProvider with your own source (a static map, a CMS, an
HR API) and hand it to
NepaliCalendarPolicy.
- class NepaliEventProvider[source]¶
Bases:
objectInterface for supplying the events a calendar names: holidays, festivals, programmes, anything an app wants written on a day.
- Implementations must:
return a stable set for a given
year(calling twice yields the same contents),not raise for years outside the supported Nepali year range, returning an empty set instead.
Example:
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())
- events(year)[source]¶
Everything named in
year(BS). An empty set is a valid answer.- Parameters:
year (int)
- Return type:
- closes_on(date)[source]¶
Whether the institution is shut on
date, which is what the working-day helpers count by.The default answers from
events(), counting only the entries whosecloses_officesis set, so a day carrying nothing but an observance is still a working day. Override with a memoized implementation if you call this in tight loops.- Parameters:
date (SimpleDate)
- Return type:
- filtered(predicate)[source]¶
A view of this provider carrying only the entries
predicateaccepts.For narrowing a shared list to what one screen cares about:
provider.filtered(lambda e: e.kind is NepaliEventKind.GOVERNMENT_PUBLIC)
predicateruns on every entry of a year each time that year is asked for, so keep it a test rather than a lookup.A day stays closed while a closure behind it survives the filter, so narrowing a list narrows the closures with it. A day the source shuts without naming a closing event stays shut, since there is nothing to narrow.
filtered(lambda e: True)therefore answers exactly what the source does.- Parameters:
predicate (Callable[[NepaliCalendarEvent], bool])
- Return type:
- NoOpEventProvider = <nepali_calendar_utils.event.nepali_event_provider._NoOpEventProvider object>¶
No-op provider singleton. Use when you want the event-aware APIs but have not wired a data source yet.
- class NepaliWeekend[source]¶
Bases:
objectDay-of-week conventions.
The library uses a 1-based-Sunday convention everywhere: Sunday = 1, …, Saturday = 7.
- Default = frozenset({7})¶
Saturday only. Nepal observes a single-day weekend, so working-day arithmetic that uses this matches what a Nepali office counts as “5 working days from today”. Pass
frozenset({6, 7})for a Friday-and- Saturday weekend.- Type:
Default weekend in Nepal
Day status¶
What one day is under a calendar policy.
- class NepaliDayStatus(is_weekly_off, events=())[source]¶
Bases:
objectWhether the week makes a day off, and what is named on it.
The two are kept apart because they answer different questions. A weekly off day repeats fifty-two times a year and carries no name worth drawing; an event is a fact about that date alone. A day can be both, and a day that is both is still one day off, so
is_non_workingis a single answer rather than a count.- Parameters:
is_weekly_off (bool)
events (Tuple[NepaliCalendarEvent, ...])
- events¶
Everything named on the day, strongest
NepaliEventKindfirst. Empty when the day carries nothing, which is the usual case even for a weekly off day. Any sequence may be passed in; it is kept as a tuple.- Type:
- property is_non_working: bool¶
True when the institution is shut, whether the week says so or an event does.
Only an event that closes offices counts, so a working day carrying a programme or a meeting stays a working day, and the working-day helpers agree.
- property primary_kind: NepaliEventKind | None¶
The kind that describes the day best, or
Nonewhen nothing is named on it.A day that is only a weekly off day has no kind, which is what separates “it is Saturday” from “it is Dashain, which happens to be a Saturday”.
- property names: List[str]¶
The names of the day’s events, strongest first, for whatever the app draws or announces.
- property closures: List[NepaliCalendarEvent]¶
The events that actually shut the institution, the subset the arithmetic counts.
Calendar policy¶
When one institution is closed, and what its calendar has on it.
- class NepaliCalendarPolicy(weekly_off_days=frozenset({7}), provider=<nepali_calendar_utils.event.nepali_event_provider._NoOpEventProvider object>)[source]¶
Bases:
objectThe days of the week an institution never opens, plus the events it keeps.
The two travel together because they answer the same question, and an app that states them once gets both a calendar that paints the right days and arithmetic that counts the right ones. An office in Nepal is
NepaliCalendarPolicy(provider=my_events), closed Saturdays. A school closed Saturday and Sunday isNepaliCalendarPolicy(frozenset({7, 1}), my_events). Two institutions with different lists are two policies over two providers, and a national list shared by both isnational + own_list.Nothing here blocks a date on its own.
as_selectable_dates()turns the policy into a picker rule when that is what you want, so marking a day and refusing it stay separate decisions.- weekly_off_days¶
Days of the week the institution is closed, 1 for Sunday through 7 for Saturday. Defaults to
NepaliWeekend.Default, the single Saturday weekend Nepal observes. An empty set is an institution that never closes for the week alone. Any iterable may be passed in; it is kept as a frozenset.
- provider¶
The events the institution keeps. Defaults to
NoOpEventProvider, which is the right value while an app has only its weekly rule wired.- Type:
- Raises:
ValueError – if
weekly_off_daysholds a number that is not a day of the week. Other calendars number Sunday 0, and a set written to that convention would quietly close nothing, so it is rejected at construction rather than at the end of a month of wrong answers.- Parameters:
provider (NepaliEventProvider)
- is_weekly_off(day_of_week)[source]¶
Whether
day_of_week(1 for Sunday through 7 for Saturday) is one of the institution’s weekly off days.Takes the day of the week rather than a date because a calendar grid already knows it, and resolving it again would cost a conversion per cell.
- events_on(date)[source]¶
The events on
date, strongest kind first, or an empty list when the day carries none. A weekly off day with nothing named on it answers empty.- Parameters:
date (SimpleDate)
- Return type:
- events_in(year, month)[source]¶
Every event in the Bikram Sambat month
monthofyear, in date order and, within a date, strongest kind first.Empty for a month with none, and for a year the provider does not cover.
- Parameters:
- Return type:
- status_of(date)[source]¶
What
dateis under this policy: whether the week makes it a day off, and what is named on it.Resolves the day of the week through the conversion table, so prefer
month_status()when laying out a whole month.- Parameters:
date (SimpleDate)
- Return type:
- month_status(year, month)[source]¶
Every day of one Bikram Sambat month, in day order: index 0 is day 1.
The month’s first weekday is resolved once and the week walked forward from it, so a grid or an agenda costs one conversion rather than one per day.
- Parameters:
- Return type:
- is_non_working_day(date)[source]¶
Whether the institution is closed on
date, for either reason.A day that is both a weekly off day and a holiday is closed once, and a day carrying only an observance is still worked. The provider is asked directly rather than through
status_of(), so one that answerscloses_onwithout listing the event behind it is still heard, and this agrees with what the working-day helpers count.- Parameters:
date (SimpleDate)
- Return type:
- as_selectable_dates()[source]¶
The policy as a picker rule: every closed day becomes unselectable.
Opt in to this when a screen should refuse the days it marks, and leave it out when the days are only to be seen. An event that does not close the institution, a school programme or a meeting, leaves its day selectable, since the day is still worked.
- Return type:
Working-day helpers¶
Selectable-date wrappers and working-day arithmetic over a calendar’s events.
The arithmetic helpers are also surfaced as static methods on
NepaliDateConverter. Each of them takes either a provider and a weekend set, or a
NepaliCalendarPolicy,
which already states both.
- MAX_FORWARD_SCAN_DAYS = 366¶
A year of scanning, the point at which a forward search gives up rather than looping on a policy that closes every day.
- MAX_WORKING_DAY_SCAN_DAYS = 732¶
About two years of slack, the bound on a working-day count in either direction.
- excluding_closures(base, provider)[source]¶
Wrap
baseso it additionally rejects any dateprovidersays the institution is shut for.An event that does not close, a programme or a meeting, leaves its day selectable: the day is still worked, and refusing it would surprise anyone booking on it.
Year-level rejection still defers to the wrapped predicate, since event data is per-date.
- Parameters:
base (NepaliSelectableDates)
provider (NepaliEventProvider)
- Return type:
- excluding_weekends(base, weekend=frozenset({7}))[source]¶
Wrap
baseso it additionally rejects weekend days.weekendis a set of 1-based-Sunday day-of-week numbers (Sunday = 1, …, Saturday = 7). Defaults to Saturday only. Passfrozenset({6, 7})for a Friday-and-Saturday weekend.- Parameters:
base (NepaliSelectableDates)
- Return type:
- working_days_between(start, end, provider, weekend=None)[source]¶
Number of working days in the half-open range
[start, end).Skips both the weekend days and the dates the institution is shut for.
endis exclusive, matchingget_nepali_days_in_between; to make it inclusive, add 1 whenenditself is a working day. A day that is both a weekend and a closure is skipped once. Returns 0 whenstart == end.- Parameters:
start (SimpleDate) – First day of the range, included.
end (SimpleDate) – Day the range stops before.
provider – A
NepaliEventProvider, or aNepaliCalendarPolicythat carries its own weekly off days.weekend – Day-of-week numbers treated as the weekend. Defaults to Saturday only, and must be left unset when a policy is passed.
- Raises:
ValueError – if
start > end, or if both a policy and aweekendare given.- Return type:
- next_working_day(from_date, provider, weekend=None)[source]¶
First working day at or after
from_date.If
from_dateis itself a working day, returns it unchanged. Otherwise scans forward day by day, bounded: gives up after a year rather than looping forever on a policy that closes every day.- Parameters:
from_date (SimpleDate) – Day to start looking from, included.
provider – A
NepaliEventProvider, or aNepaliCalendarPolicythat carries its own weekly off days.weekend – Day-of-week numbers treated as the weekend. Defaults to Saturday only, and must be left unset when a policy is passed.
- Raises:
ValueError – if both a policy and a
weekendare given.RuntimeError – if no working day is found within 366 days.
- Return type:
- add_working_days(from_date, days, provider, weekend=None)[source]¶
Date that is
daysworking days fromfrom_date(ExcelWORKDAYsemantics).days == 0returnsfrom_dateunchanged.days > 0returns thedays-th working day strictly afterfrom_date.days < 0returns theabs(days)-th working day strictly before it.
Note this means
add_working_days(from_date, 0)is not the same asnext_working_day()- use the latter for adjustment.- Parameters:
from_date (SimpleDate) – Day the count starts from, itself never the answer unless
daysis 0.days (int) – How many working days to move, forward when positive.
provider – A
NepaliEventProvider, or aNepaliCalendarPolicythat carries its own weekly off days.weekend – Day-of-week numbers treated as the weekend. Defaults to Saturday only, and must be left unset when a policy is passed.
- Raises:
ValueError – if both a policy and a
weekendare given.RuntimeError – if more than about two years of scanning fails, which guards against a policy that closes every day.
- Return type:
Former holiday names¶
Code written against the 3.0.0 holiday package keeps working, implementations of
NepaliHolidayProvider included. Importing from here raises a DeprecationWarning.
The holiday provider SPI under its former names.
A holiday turned out to be one kind of event rather than the whole subject: the
package also names festivals, school programmes, deadlines and birthdays, and
whether a day is worked is now NepaliCalendarEvent.closes_offices rather than
something the taxonomy decides. Everything here still works and resolves to the
types in nepali_calendar_utils.event.
- HolidayEntry[source]¶
Former name of
NepaliCalendarEvent, which takes the same three positional arguments and addscloses_offices,idandpayload.
- class NepaliHolidayProvider[source]¶
Bases:
NepaliEventProviderFormer name of
NepaliEventProvider, kept as a class of its own so an implementation written against it keeps working.Subclasses implement
holidays()and optionallyis_holiday(), and the policy, the picker wrappers and the working-day helpers reach them througheventsandcloses_on. A subclass keeps the older, blunter rule that every entry closes the day:closes_officesis not consulted, so an observance returned fromholidays()still blocks its date and still stops a working-day count. ImplementNepaliEventProviderdirectly for the finer answer.- holidays(year)[source]¶
All holidays for
year(BS). An empty set is a valid answer.- Parameters:
year (int)
- Return type:
- is_holiday(date)[source]¶
Trueif any entry fromholidays()fordate.yearfalls ondate.Default implementation re-queries
holidays()on every call. Override with a memoized implementation if you call this in tight loops.- Parameters:
date (SimpleDate)
- Return type:
- events(year)[source]¶
Everything named in
year(BS). An empty set is a valid answer.- Parameters:
year (int)
- Return type:
- closes_on(date)[source]¶
Whether the institution is shut on
date, which is what the working-day helpers count by.The default answers from
events(), counting only the entries whosecloses_officesis set, so a day carrying nothing but an observance is still a working day. Override with a memoized implementation if you call this in tight loops.- Parameters:
date (SimpleDate)
- Return type:
- NoOpHolidayProvider = <nepali_calendar_utils.holiday.holiday_provider._NoOpHolidayProvider object>¶
Former name of
NoOpEventProvider, answering toholidaysandis_holidayas well.
- class NepaliWeekend[source]¶
Bases:
objectDay-of-week conventions.
The library uses a 1-based-Sunday convention everywhere: Sunday = 1, …, Saturday = 7.
- Default = frozenset({7})¶
Saturday only. Nepal observes a single-day weekend, so working-day arithmetic that uses this matches what a Nepali office counts as “5 working days from today”. Pass
frozenset({6, 7})for a Friday-and- Saturday weekend.- Type:
Default weekend in Nepal
The picker wrappers and working-day arithmetic under their former names.
Each name here resolves to its counterpart in
nepali_calendar_utils.event.event_helpers, which takes a calendar policy as
well as a provider.
- excluding_holidays(base, provider)[source]¶
Former name of
excluding_closures(), which is what it does: an event that leaves the institution open no longer blocks its day.A provider written against :class:` ~nepali_calendar_utils.holiday.holiday_provider.NepaliHolidayProvider` blocks every entry it lists, as it always did.
- Parameters:
base (NepaliSelectableDates)
provider (NepaliEventProvider)
- Return type:
- excluding_weekends(base, weekend=frozenset({7}))[source]¶
Wrap
baseso it additionally rejects weekend days.weekendis a set of 1-based-Sunday day-of-week numbers (Sunday = 1, …, Saturday = 7). Defaults to Saturday only. Passfrozenset({6, 7})for a Friday-and-Saturday weekend.- Parameters:
base (NepaliSelectableDates)
- Return type:
- working_days_between(start, end, provider, weekend=None)[source]¶
Number of working days in the half-open range
[start, end).Skips both the weekend days and the dates the institution is shut for.
endis exclusive, matchingget_nepali_days_in_between; to make it inclusive, add 1 whenenditself is a working day. A day that is both a weekend and a closure is skipped once. Returns 0 whenstart == end.- Parameters:
start (SimpleDate) – First day of the range, included.
end (SimpleDate) – Day the range stops before.
provider – A
NepaliEventProvider, or aNepaliCalendarPolicythat carries its own weekly off days.weekend – Day-of-week numbers treated as the weekend. Defaults to Saturday only, and must be left unset when a policy is passed.
- Raises:
ValueError – if
start > end, or if both a policy and aweekendare given.- Return type:
- next_working_day(from_date, provider, weekend=None)[source]¶
First working day at or after
from_date.If
from_dateis itself a working day, returns it unchanged. Otherwise scans forward day by day, bounded: gives up after a year rather than looping forever on a policy that closes every day.- Parameters:
from_date (SimpleDate) – Day to start looking from, included.
provider – A
NepaliEventProvider, or aNepaliCalendarPolicythat carries its own weekly off days.weekend – Day-of-week numbers treated as the weekend. Defaults to Saturday only, and must be left unset when a policy is passed.
- Raises:
ValueError – if both a policy and a
weekendare given.RuntimeError – if no working day is found within 366 days.
- Return type:
- add_working_days(from_date, days, provider, weekend=None)[source]¶
Date that is
daysworking days fromfrom_date(ExcelWORKDAYsemantics).days == 0returnsfrom_dateunchanged.days > 0returns thedays-th working day strictly afterfrom_date.days < 0returns theabs(days)-th working day strictly before it.
Note this means
add_working_days(from_date, 0)is not the same asnext_working_day()- use the latter for adjustment.- Parameters:
from_date (SimpleDate) – Day the count starts from, itself never the answer unless
daysis 0.days (int) – How many working days to move, forward when positive.
provider – A
NepaliEventProvider, or aNepaliCalendarPolicythat carries its own weekly off days.weekend – Day-of-week numbers treated as the weekend. Defaults to Saturday only, and must be left unset when a policy is passed.
- Raises:
ValueError – if both a policy and a
weekendare given.RuntimeError – if more than about two years of scanning fails, which guards against a policy that closes every day.
- Return type: