Django NPDateTime
Nepali Date Field and Date Picker Widget for Django
A Django package that provides custom model fields, form fields, and a modern date picker widget for working with Nepali (Bikram Sambat) dates. Powered by the high-performance npdatetime library.
Features
✨ Custom Model Fields - NepaliDateField and NepaliDateTimeField with direct access to fiscal year/quarter properties
✨ Fiscal Year Support - Built-in support for Nepali Fiscal Years (e.g., 2080/81) and quarters
🎨 Beautiful Date Picker Widget - Modern, responsive date picker with both BS and AD modes
🌐 Bilingual Support - English and Nepali language options
🔄 Auto Conversion - Seamless conversion between Bikram Sambat and Gregorian calendars
📝 Template Tags & Filters - Rich template tags for date formatting and conversion
⚡ High Performance - Built on Rust for maximum speed
🎯 Django Integration - Works seamlessly with Django's forms and admin
🔒 Enterprise Options - Disable past dates, weekends, holidays, specific dates/weekdays, and custom validation callbacks
For Developers
If you're contributing to this package, the JavaScript/CSS files are synchronized from ../javascript/. When you update the date picker:
# Run the build script to sync assets
python build_assets.py
# or
./build_assets.sh
This copies:
picker.js→static/npdt/js/picker.min.jspicker.css→static/npdt/css/picker.csspkg/→static/npdt/js/pkg/
Installation
pip install django-npdt
# or with uv
uv add django-npdt
Quick Start
1. Add to INSTALLED_APPS
# settings.py
INSTALLED_APPS = [
...
'npdt',
...
]
2. Use in Models
from django.db import models
from npdt import NepaliDateField
class Person(models.Model):
name = models.CharField(max_length=100)
birth_date_bs = NepaliDateField()
def __str__(self):
return f"{self.name} - {self.birth_date_bs}"
3. Use in Forms
from django import forms
from npdt import NepaliDateField, NepaliDatePickerWidget
class PersonForm(forms.Form):
name = forms.CharField(max_length=100)
birth_date = NepaliDateField(
mode='BS',
language='np',
label='जन्म मिति'
)
4. Use Template Tags
{% load nepali_date %}
<p>Birth Date (BS): {{ person.birth_date_bs }}</p>
<p>Birth Date (AD): {{ person.birth_date_bs|to_gregorian_date }}</p>
<p>Fiscal Year: {{ person.birth_date_bs.fiscal_year }}</p>
<p>Today in BS: {% nepali_date_today %}</p>
<p>Month: {{ 1|nepali_month_name:"np" }}</p>
<p>Inline Picker: {% nepali_date_picker "event_date" theme="dark" %}</p>
Usage Guide
Model Fields
NepaliDateField
Stores Nepali dates in YYYY-MM-DD format.
from npdt.models import NepaliDateField
class Event(models.Model):
event_name = models.CharField(max_length=200)
event_date_bs = NepaliDateField(mode='BS', language='np') # Configurable!
NepaliDateTimeField
Stores Nepali dates with time in YYYY-MM-DD HH:MM:SS format.
from npdt.models import NepaliDateTimeField
class Meeting(models.Model):
title = models.CharField(max_length=200)
scheduled_at_bs = NepaliDateTimeField()
Form Fields and Widgets
Basic Date Picker
from npdt.forms import NepaliDateField
class PersonForm(forms.Form):
birth_date = NepaliDateField(
mode='BS', # 'BS' or 'AD'
language='en', # 'en' or 'np'
)
Advanced Configuration
from npdt.widgets import NepaliDatePickerWidget
class EventForm(forms.Form):
event_date = forms.CharField(
widget=NepaliDatePickerWidget(
mode='BS',
language='np',
theme='dark',
show_today_button=True,
show_clear_button=True,
min_date='2080-01-01',
max_date='2085-12-30',
)
)
Enterprise Configuration
from npdt.widgets import NepaliDatePickerWidget
class LeaveForm(forms.Form):
# Future dates only, no weekends or holidays
leave_date = forms.CharField(
widget=NepaliDatePickerWidget(
mode='BS',
disable_past_dates=True,
disable_weekends=True,
disable_holidays=True,
)
)
Using widget_kwargs with Form Fields
NepaliDateField and NepaliDateRangeField accept widget_kwargs to pass options through to the widget:
from npdt.forms import NepaliDateField
class LeaveForm(forms.Form):
start_date = NepaliDateField(
mode='BS',
widget_kwargs={
'disable_past_dates': True,
'disable_holidays': True,
'disable_weekends': True,
'show_tithi': True,
}
)
Date Range Picker
from npdt.forms import NepaliDateRangeField
class ReportForm(forms.Form):
report_period = NepaliDateRangeField(
mode='BS',
language='np'
)
def clean_report_period(self):
period = self.cleaned_data['report_period']
start_date, end_date = period.split(' to ')
# Process date range
return period
Template Tags and Filters
Load the template tag library:
{% load nepali_date %}
Convert Gregorian to Nepali
{{ gregorian_date|to_nepali_date }}
{{ gregorian_date|to_nepali_date:"%Y/%m/%d" }}
Convert Nepali to Gregorian
{{ nepali_date|to_gregorian_date }}
{{ nepali_date|to_gregorian_date:"%d/%m/%Y" }}
Format Nepali Date
{{ "2081-01-15"|format_nepali_date:"%Y/%m/%d" }}
Get Month Name
{{ 1|nepali_month_name }} {# Baisakh #}
{{ 1|nepali_month_name:"np" }} {# बैशाख #}
Convert to Nepali Numerals
{{ 2081|to_nepali_number }} {# २०८१ #}
Fiscal Year and Quarter
{{ "2081-01-15"|fiscal_year }} {# 2080/81 #}
{{ "2081-01-15"|fiscal_quarter }} {# 3 #}
Get Today's Date
{% nepali_date_today %}
{% nepali_date_today "%Y/%m/%d" %}
Inline Date Picker
{% load nepali_date %}
{# Basic #}
{% nepali_date_picker "event_date" %}
{# With dynamic options #}
{% nepali_date_picker "event_date" disable_past_dates=True %}
{% nepali_date_picker "event_date" disable_weekends=True disable_holidays=True %}
{% nepali_date_picker "event_date" admin_theme=True %}
{% nepali_date_picker "event_date" show_tithi=True %}
Widget Options
The NepaliDatePickerWidget accepts the following options:
Core Options
| Option | Type | Default | Description |
|---|---|---|---|
mode |
str | 'BS' |
Calendar mode: 'BS' or 'AD' |
language |
str | 'en' |
Interface language: 'en' or 'np' |
theme |
str | 'auto' |
Color theme: 'auto', 'light', 'dark', or 'admin' |
format |
str | '%Y-%m-%d' |
Date format string |
include_time |
bool | False |
Include time picker |
show_today_button |
bool | True |
Show "Today" button |
show_clear_button |
bool | True |
Show "Clear" button |
min_date |
str | None |
Minimum selectable date (YYYY-MM-DD) |
max_date |
str | None |
Maximum selectable date (YYYY-MM-DD) |
Dynamic Disabling Options
| Option | Type | Default | Description |
|---|---|---|---|
disabled_dates |
list[str] | [] |
List of date strings to disable (YYYY-MM-DD) |
disabled_days |
list[int] | str | [] |
Weekday indices to disable. Supports: list [0,6], range "1-5" (Mon–Fri), mixed "1-5,0". 0=Sunday, 1=Monday, ..., 6=Saturday |
disable_past_dates |
bool | False |
Disable all dates before today |
disable_weekends |
bool | False |
Disable weekends (Saturday in BS, Sunday in AD) |
disable_holidays |
bool | False |
Disable holidays from the holiday provider |
show_holidays |
bool | True |
Highlight holidays visually (without disabling) |
holiday_provider |
HolidayProvider | None |
Custom holiday provider. Defaults to NepalPublicHolidays when disable_holidays=True |
on_date_disabled |
str | 'prevent' |
Behavior when a disabled date is selected: 'prevent' or 'warn' |
show_tithi |
bool | False |
Show lunar tithi on date hover |
admin_theme |
bool | False |
Shortcut for theme='admin' — matches Django admin styling |
Holiday Provider System
The widget includes an extensible holiday provider system for defining which dates should be treated as holidays.
Built-in: NepalPublicHolidays
Covers major Nepal public holidays for BS years 2070–2100. Automatically used when disable_holidays=True and no custom provider is specified.
from npdt.widgets import NepaliDatePickerWidget
widget = NepaliDatePickerWidget(
disable_holidays=True, # Uses NepalPublicHolidays by default
)
Custom Holiday Provider
Subclass HolidayProvider to define your organization's holidays:
from npdt.holidays import HolidayProvider, HolidayDate
class MyCompanyHolidays(HolidayProvider):
def get_holidays(self, year, month=None):
return [
HolidayDate('2082-01-01', 'Company Foundation Day', name_np='कम्पनी स्थापना दिवस'),
HolidayDate('2082-06-15', 'Annual Retreat', type='optional'),
]
widget = NepaliDatePickerWidget(
holiday_provider=MyCompanyHolidays(),
disable_holidays=True,
)
CompositeHolidayProvider
Merge multiple providers (e.g., public holidays + company holidays):
from npdt.holidays import CompositeHolidayProvider, NepalPublicHolidays
provider = CompositeHolidayProvider(
NepalPublicHolidays(),
MyCompanyHolidays(),
)
widget = NepaliDatePickerWidget(
holiday_provider=provider,
disable_holidays=True,
show_holidays=True,
)
StaticHolidayProvider
Quick one-off configuration without writing a full class:
from npdt.holidays import StaticHolidayProvider
provider = StaticHolidayProvider(
['2082-01-01', '2082-09-03'],
name='Bank Holiday',
)
widget = NepaliDatePickerWidget(
holiday_provider=provider,
disable_holidays=True,
)
Django Admin Integration
The date picker automatically integrates with Django admin. Use admin_theme=True to match Django admin's styling:
from django.contrib import admin
from npdt.widgets import NepaliDatePickerWidget
@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
list_display = ['name', 'birth_date_bs']
fields = ['name', 'birth_date_bs']
For explicit admin theme on individual widgets:
class PersonForm(forms.ModelForm):
class Meta:
model = Person
fields = ['name', 'birth_date_bs']
widgets = {
'birth_date_bs': NepaliDatePickerWidget(
admin_theme=True,
disable_holidays=True,
),
}
Examples
Complete Model Example
from django.db import models
from npdt.models import NepaliDateField, NepaliDateTimeField
class Employee(models.Model):
name = models.CharField(max_length=100)
join_date_bs = NepaliDateField(help_text="Joining date in BS")
birth_date_bs = NepaliDateField(blank=True, null=True)
last_login_bs = NepaliDateTimeField(blank=True, null=True)
class Meta:
ordering = ['-join_date_bs']
def __str__(self):
return f"{self.name} (Joined: {self.join_date_bs})"
ModelForm Example
from django import forms
from npdt.widgets import NepaliDatePickerWidget
from .models import Employee
class EmployeeForm(forms.ModelForm):
class Meta:
model = Employee
fields = ['name', 'join_date_bs', 'birth_date_bs']
widgets = {
'join_date_bs': NepaliDatePickerWidget(
mode='BS',
language='np',
theme='light'
),
'birth_date_bs': NepaliDatePickerWidget(
mode='BS',
language='np'
),
}
Production Example: Banking Form
from django import forms
from npdt.widgets import NepaliDatePickerWidget
class FacilityForm(forms.ModelForm):
class Meta:
model = CustomerFacility
fields = ['reference', 'initiated_date', 'approval_date']
widgets = {
'initiated_date': NepaliDatePickerWidget(
mode='AD',
disable_holidays=True,
),
'approval_date': NepaliDatePickerWidget(
disable_holidays=True,
),
}
Converting BS ↔ AD in Forms
When storing AD dates in the database but displaying BS in the picker:
from django import forms
from npdt.widgets import NepaliDatePickerWidget
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Convert AD dates to BS for initial display
for date_field in ('initiated_date', 'approval_date'):
if date_field in self.fields and self.initial.get(date_field):
try:
from npdatetime import NepaliDate
ad_val = self.initial[date_field]
if hasattr(ad_val, 'year'):
np_date = NepaliDate.from_gregorian(
ad_val.year, ad_val.month, ad_val.day
)
self.initial[date_field] = str(np_date)
except Exception:
pass
def _clean_bs_date(self, field_name):
"""Convert BS date string from picker to AD date for the model."""
value = self.cleaned_data.get(field_name)
if not value:
return value
if hasattr(value, 'year') and not isinstance(value, str):
return value
try:
from npdatetime import NepaliDate
import datetime
parts = [int(p) for p in str(value).split('-')]
np_date = NepaliDate(parts[0], parts[1], parts[2])
gy, gm, gd = np_date.to_gregorian()
return datetime.date(gy, gm, gd)
except Exception:
raise forms.ValidationError(f'Invalid BS date format for {field_name}.')
def clean_initiated_date(self):
return self._clean_bs_date('initiated_date')
Template Example
{% load nepali_date %}
<!DOCTYPE html>
<html>
<head>
<title>Employee Details</title>
</head>
<body>
<h1>{{ employee.name }}</h1>
<div>
<strong>Join Date (BS):</strong>
{{ employee.join_date_bs|format_nepali_date:"%Y/%m/%d" }}
</div>
<div>
<strong>Join Date (AD):</strong>
{{ employee.join_date_bs|to_gregorian_date:"%B %d, %Y" }}
</div>
<div>
<strong>Birth Month:</strong>
{{ employee.birth_date_bs|slice:":7"|last|int|nepali_month_name:"np" }}
</div>
</body>
</html>
Requirements
- Python >= 3.8
- Django >= 3.2
- npdatetime >= 0.1.0
Browser Support
- Chrome/Edge (latest)
- Firefox (latest)
- Safari (latest)
- Mobile browsers (iOS Safari, Chrome Mobile)
License
MIT License - see LICENSE file for details
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Credits
Built on top of:
- npdatetime(Rust) - High-performance Nepali datetime library (Rust)
Support
For bugs and feature requests, please open an issue on GitHub.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_npdt-0.2.6.tar.gz.
File metadata
- Download URL: django_npdt-0.2.6.tar.gz
- Upload date:
- Size: 126.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
561f01496a470ef3089bc36dec42760169fc0a4befcad9051a60e2fbd63aab68
|
|
| MD5 |
a562b0bfd4870103369ba102c7b09c56
|
|
| BLAKE2b-256 |
1c28a8fae7f5bb2c4e61d4db6b99cefc281d76634b6edc72e36acc07a20c4a11
|
File details
Details for the file django_npdt-0.2.6-py3-none-any.whl.
File metadata
- Download URL: django_npdt-0.2.6-py3-none-any.whl
- Upload date:
- Size: 120.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e4687e82b3e8cb56f024c407f771a9bd2633dbf4677229214cf903bbe4d56a2c
|
|
| MD5 |
1a8ae3bbef24e819bee0893823046c21
|
|
| BLAKE2b-256 |
30b3991aa787e859046905aeb50e51b2240fbc4ef514ccde19f1c833facbbbd0
|