django-npdatetime 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,36 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ export const memory: WebAssembly.Memory;
4
+ export const __wbg_bsdate_free: (a: number, b: number) => void;
5
+ export const bsdate_day: (a: number) => number;
6
+ export const bsdate_fromGregorian: (a: number, b: number, c: number, d: number) => void;
7
+ export const bsdate_month: (a: number) => number;
8
+ export const bsdate_new: (a: number, b: number, c: number, d: number) => void;
9
+ export const bsdate_tithi: (a: number, b: number) => void;
10
+ export const bsdate_toGregorian: (a: number, b: number) => void;
11
+ export const bsdate_toString: (a: number, b: number) => void;
12
+ export const bsdate_year: (a: number) => number;
13
+ export const init: () => void;
14
+ export const nepalidate_addDays: (a: number, b: number, c: number) => void;
15
+ export const nepalidate_fiscalQuarter: (a: number) => number;
16
+ export const nepalidate_fiscalYear: (a: number, b: number) => void;
17
+ export const nepalidate_format: (a: number, b: number, c: number, d: number) => void;
18
+ export const nepalidate_formatUnicode: (a: number, b: number) => void;
19
+ export const nepalidate_fromGregorian: (a: number, b: number, c: number, d: number) => void;
20
+ export const nepalidate_fromOrdinal: (a: number, b: number) => void;
21
+ export const nepalidate_monthCalendar: (a: number, b: number) => void;
22
+ export const nepalidate_new: (a: number, b: number, c: number, d: number) => void;
23
+ export const nepalidate_tithi: (a: number, b: number) => void;
24
+ export const nepalidate_toGregorian: (a: number, b: number) => void;
25
+ export const nepalidate_toOrdinal: (a: number) => number;
26
+ export const nepalidate_toString: (a: number, b: number) => void;
27
+ export const nepalidate_today: (a: number) => void;
28
+ export const nepalidate_year: (a: number) => number;
29
+ export const nepalidate_month: (a: number) => number;
30
+ export const nepalidate_day: (a: number) => number;
31
+ export const __wbg_nepalidate_free: (a: number, b: number) => void;
32
+ export const __wbindgen_export: (a: number, b: number, c: number) => void;
33
+ export const __wbindgen_export2: (a: number, b: number) => number;
34
+ export const __wbindgen_export3: (a: number, b: number, c: number, d: number) => number;
35
+ export const __wbindgen_add_to_stack_pointer: (a: number) => number;
36
+ export const __wbindgen_start: () => void;
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "npdatetime-wasm",
3
+ "type": "module",
4
+ "version": "0.1.0",
5
+ "files": [
6
+ "npdatetime_wasm_bg.wasm",
7
+ "npdatetime_wasm.js",
8
+ "npdatetime_wasm.d.ts"
9
+ ],
10
+ "main": "npdatetime_wasm.js",
11
+ "types": "npdatetime_wasm.d.ts",
12
+ "sideEffects": [
13
+ "./snippets/*"
14
+ ]
15
+ }
@@ -0,0 +1,28 @@
1
+ {% load static %}
2
+
3
+ <input
4
+ type="{{ widget.type }}"
5
+ name="{{ widget.name }}"
6
+ {% if widget.value != None %}
7
+ value="{{ widget.value }}"
8
+ {% endif %}
9
+ {% include "django/forms/widgets/attrs.html" %}
10
+ >
11
+
12
+ <script type="module">
13
+ import { NepaliDatePicker } from '{% static "npdatetime_django/js/date_picker.min.js" %}';
14
+
15
+ document.addEventListener('DOMContentLoaded', function() {
16
+ const input = document.querySelector('input[name="{{ widget.name }}"]');
17
+ if (input && !input.dataset.npdInitialized) {
18
+ const options = {{ widget.picker_options|safe }};
19
+
20
+ try {
21
+ new NepaliDatePicker(input, options);
22
+ input.dataset.npdInitialized = 'true';
23
+ } catch (error) {
24
+ console.error('Failed to initialize Nepali Date Picker:', error);
25
+ }
26
+ }
27
+ });
28
+ </script>
@@ -0,0 +1,25 @@
1
+ {% load static %}
2
+
3
+ <div class="npd-date-range-widget">
4
+ <div class="npd-range-start">{{ widget.0 }}</div>
5
+ <span class="npd-range-separator">to</span>
6
+ <div class="npd-range-end">{{ widget.1 }}</div>
7
+ </div>
8
+
9
+ <style>
10
+ .npd-date-range-widget {
11
+ display: flex;
12
+ align-items: center;
13
+ gap: 10px;
14
+ }
15
+
16
+ .npd-range-separator {
17
+ color: #666;
18
+ font-weight: 500;
19
+ }
20
+
21
+ .npd-range-start,
22
+ .npd-range-end {
23
+ flex: 1;
24
+ }
25
+ </style>
@@ -0,0 +1,259 @@
1
+ """Template tags and filters for Nepali date manipulation"""
2
+ from django import template
3
+ from django.utils.safestring import mark_safe
4
+ import datetime
5
+
6
+ try:
7
+ from npdatetime import NepaliDate
8
+ NPDATETIME_AVAILABLE = True
9
+ except ImportError:
10
+ NPDATETIME_AVAILABLE = False
11
+
12
+ register = template.Library()
13
+
14
+
15
+ @register.filter
16
+ def to_nepali_date(value, format_str='%Y-%m-%d'):
17
+ """
18
+ Convert a Gregorian date to Nepali date.
19
+
20
+ Args:
21
+ value: datetime.date object or string in YYYY-MM-DD format
22
+ format_str: Output format string (default: '%Y-%m-%d')
23
+
24
+ Returns:
25
+ Formatted Nepali date string or empty string if conversion fails
26
+
27
+ Example:
28
+ {{ person.birth_date|to_nepali_date }}
29
+ {{ person.birth_date|to_nepali_date:"%Y/%m/%d" }}
30
+ """
31
+ if not value or not NPDATETIME_AVAILABLE:
32
+ return ''
33
+
34
+ try:
35
+ # Handle datetime.date objects
36
+ if isinstance(value, datetime.date):
37
+ year, month, day = value.year, value.month, value.day
38
+ # Handle string format
39
+ elif isinstance(value, str):
40
+ if '-' in value:
41
+ year, month, day = map(int, value.split('-')[:3])
42
+ else:
43
+ return ''
44
+ else:
45
+ return ''
46
+
47
+ # Convert to Nepali date
48
+ nepali_date = NepaliDate.from_gregorian(year, month, day)
49
+
50
+ # Format output
51
+ result = format_str
52
+ result = result.replace('%Y', str(nepali_date.year))
53
+ result = result.replace('%m', f'{nepali_date.month:02d}')
54
+ result = result.replace('%d', f'{nepali_date.day:02d}')
55
+ result = result.replace('%B', get_nepali_month_name(nepali_date.month, 'en'))
56
+ result = result.replace('%b', get_nepali_month_name(nepali_date.month, 'en')[:3])
57
+
58
+ return result
59
+
60
+ except Exception as e:
61
+ return ''
62
+
63
+
64
+ @register.filter
65
+ def to_gregorian_date(value, format_str='%Y-%m-%d'):
66
+ """
67
+ Convert a Nepali date to Gregorian date.
68
+
69
+ Args:
70
+ value: Nepali date string in YYYY-MM-DD format
71
+ format_str: Output format string (default: '%Y-%m-%d')
72
+
73
+ Returns:
74
+ Formatted Gregorian date string or empty string if conversion fails
75
+
76
+ Example:
77
+ {{ person.birth_date_bs|to_gregorian_date }}
78
+ {{ person.birth_date_bs|to_gregorian_date:"%d/%m/%Y" }}
79
+ """
80
+ if not value or not NPDATETIME_AVAILABLE:
81
+ return ''
82
+
83
+ try:
84
+ # Parse Nepali date
85
+ if isinstance(value, str):
86
+ year, month, day = map(int, value.split('-'))
87
+ else:
88
+ return ''
89
+
90
+ # Create NepaliDate and convert
91
+ nepali_date = NepaliDate(year, month, day)
92
+ gy, gm, gd = nepali_date.to_gregorian()
93
+
94
+ # Create datetime object for formatting
95
+ gregorian_date = datetime.date(gy, gm, gd)
96
+
97
+ # Use Python's strftime for formatting
98
+ return gregorian_date.strftime(format_str)
99
+
100
+ except Exception as e:
101
+ return ''
102
+
103
+
104
+ @register.filter
105
+ def format_nepali_date(value, format_str='%Y-%m-%d'):
106
+ """
107
+ Format a Nepali date string.
108
+
109
+ Args:
110
+ value: Nepali date string in YYYY-MM-DD format
111
+ format_str: Output format string
112
+
113
+ Returns:
114
+ Formatted date string
115
+
116
+ Example:
117
+ {{ date_bs|format_nepali_date:"%Y/%m/%d" }}
118
+ """
119
+ if not value:
120
+ return ''
121
+
122
+ try:
123
+ year, month, day = map(int, value.split('-'))
124
+
125
+ result = format_str
126
+ result = result.replace('%Y', str(year))
127
+ result = result.replace('%m', f'{month:02d}')
128
+ result = result.replace('%d', f'{day:02d}')
129
+ result = result.replace('%B', get_nepali_month_name(month, 'en'))
130
+ result = result.replace('%b', get_nepali_month_name(month, 'en')[:3])
131
+
132
+ return result
133
+
134
+ except Exception:
135
+ return value
136
+
137
+
138
+ @register.filter
139
+ def nepali_month_name(month_num, language='en'):
140
+ """
141
+ Get Nepali month name.
142
+
143
+ Args:
144
+ month_num: Month number (1-12)
145
+ language: 'en' or 'np'
146
+
147
+ Returns:
148
+ Month name string
149
+
150
+ Example:
151
+ {{ 1|nepali_month_name }} # Returns "Baisakh"
152
+ {{ 1|nepali_month_name:"np" }} # Returns "बैशाख"
153
+ """
154
+ return get_nepali_month_name(month_num, language)
155
+
156
+
157
+ @register.filter
158
+ def to_nepali_number(value):
159
+ """
160
+ Convert English numerals to Nepali numerals.
161
+
162
+ Args:
163
+ value: Number or string containing numbers
164
+
165
+ Returns:
166
+ String with Nepali numerals
167
+
168
+ Example:
169
+ {{ 2081|to_nepali_number }} # Returns "२०८१"
170
+ """
171
+ nepali_digits = {
172
+ '0': '०', '1': '१', '2': '२', '3': '३', '4': '४',
173
+ '5': '५', '6': '६', '7': '७', '8': '८', '9': '९'
174
+ }
175
+
176
+ result = str(value)
177
+ for eng, nep in nepali_digits.items():
178
+ result = result.replace(eng, nep)
179
+
180
+ return result
181
+
182
+
183
+ @register.simple_tag
184
+ def nepali_date_today(format_str='%Y-%m-%d'):
185
+ """
186
+ Get today's date in Nepali calendar.
187
+
188
+ Args:
189
+ format_str: Output format string
190
+
191
+ Returns:
192
+ Formatted today's Nepali date
193
+
194
+ Example:
195
+ {% nepali_date_today %}
196
+ {% nepali_date_today "%Y/%m/%d" %}
197
+ """
198
+ if not NPDATETIME_AVAILABLE:
199
+ return ''
200
+
201
+ try:
202
+ today = NepaliDate.today()
203
+
204
+ result = format_str
205
+ result = result.replace('%Y', str(today.year))
206
+ result = result.replace('%m', f'{today.month:02d}')
207
+ result = result.replace('%d', f'{today.day:02d}')
208
+ result = result.replace('%B', get_nepali_month_name(today.month, 'en'))
209
+ result = result.replace('%b', get_nepali_month_name(today.month, 'en')[:3])
210
+
211
+ return result
212
+
213
+ except Exception:
214
+ return ''
215
+
216
+
217
+ @register.inclusion_tag('npdatetime_django/widgets/inline_picker.html')
218
+ def nepali_date_picker(field_name, value='', mode='BS', language='en', **kwargs):
219
+ """
220
+ Include a Nepali date picker inline in templates.
221
+
222
+ Args:
223
+ field_name: Name of the input field
224
+ value: Initial value
225
+ mode: 'BS' or 'AD'
226
+ language: 'en' or 'np'
227
+ **kwargs: Additional options
228
+
229
+ Example:
230
+ {% nepali_date_picker "birth_date" mode="BS" language="np" %}
231
+ """
232
+ return {
233
+ 'field_name': field_name,
234
+ 'value': value,
235
+ 'mode': mode,
236
+ 'language': language,
237
+ 'options': kwargs
238
+ }
239
+
240
+
241
+ # Helper function
242
+ def get_nepali_month_name(month_num, language='en'):
243
+ """Get the name of a Nepali month."""
244
+ months_en = [
245
+ 'Baisakh', 'Jestha', 'Ashadh', 'Shrawan', 'Bhadra', 'Ashwin',
246
+ 'Kartik', 'Mangshir', 'Poush', 'Magh', 'Falgun', 'Chaitra'
247
+ ]
248
+
249
+ months_np = [
250
+ 'बैशाख', 'जेठ', 'असार', 'साउन', 'भदौ', 'असोज',
251
+ 'कात्तिक', 'मंसिर', 'पुस', 'माघ', 'फागुन', 'चैत'
252
+ ]
253
+
254
+ if not (1 <= month_num <= 12):
255
+ return ''
256
+
257
+ if language == 'np':
258
+ return months_np[month_num - 1]
259
+ return months_en[month_num - 1]
@@ -0,0 +1 @@
1
+ # Template tags module
@@ -0,0 +1,131 @@
1
+ """Utility functions for working with Nepali dates in Django"""
2
+
3
+ try:
4
+ from npdatetime import NepaliDate
5
+ NPDATETIME_AVAILABLE = True
6
+ except ImportError:
7
+ NPDATETIME_AVAILABLE = False
8
+
9
+
10
+ def convert_bs_to_ad(bs_date_str):
11
+ """
12
+ Convert a Nepali (BS) date string to Gregorian (AD) date.
13
+
14
+ Args:
15
+ bs_date_str (str): Date in format "YYYY-MM-DD"
16
+
17
+ Returns:
18
+ str: Gregorian date in format "YYYY-MM-DD" or None if conversion fails
19
+
20
+ Example:
21
+ >>> convert_bs_to_ad("2081-01-15")
22
+ "2024-05-02"
23
+ """
24
+ if not bs_date_str or not NPDATETIME_AVAILABLE:
25
+ return None
26
+
27
+ try:
28
+ year, month, day = map(int, bs_date_str.split('-'))
29
+ nepali_date = NepaliDate(year, month, day)
30
+ gy, gm, gd = nepali_date.to_gregorian()
31
+ return f"{gy}-{gm:02d}-{gd:02d}"
32
+ except Exception:
33
+ return None
34
+
35
+
36
+ def convert_ad_to_bs(ad_date_str):
37
+ """
38
+ Convert a Gregorian (AD) date string to Nepali (BS) date.
39
+
40
+ Args:
41
+ ad_date_str (str): Date in format "YYYY-MM-DD"
42
+
43
+ Returns:
44
+ str: Nepali date in format "YYYY-MM-DD" or None if conversion fails
45
+
46
+ Example:
47
+ >>> convert_ad_to_bs("2024-05-02")
48
+ "2081-01-15"
49
+ """
50
+ if not ad_date_str or not NPDATETIME_AVAILABLE:
51
+ return None
52
+
53
+ try:
54
+ year, month, day = map(int, ad_date_str.split('-'))
55
+ nepali_date = NepaliDate.from_gregorian(year, month, day)
56
+ return f"{nepali_date.year}-{nepali_date.month:02d}-{nepali_date.day:02d}"
57
+ except Exception:
58
+ return None
59
+
60
+
61
+ def get_nepali_month_names(language='en'):
62
+ """
63
+ Get list of Nepali month names.
64
+
65
+ Args:
66
+ language (str): 'en' for English or 'np' for Nepali
67
+
68
+ Returns:
69
+ list: List of month names
70
+ """
71
+ months_en = [
72
+ 'Baisakh', 'Jestha', 'Ashadh', 'Shrawan', 'Bhadra', 'Ashwin',
73
+ 'Kartik', 'Mangshir', 'Poush', 'Magh', 'Falgun', 'Chaitra'
74
+ ]
75
+
76
+ months_np = [
77
+ 'बैशाख', 'जेठ', 'असार', 'साउन', 'भदौ', 'असोज',
78
+ 'कात्तिक', 'मंसिर', 'पुस', 'माघ', 'फागुन', 'चैत'
79
+ ]
80
+
81
+ return months_np if language == 'np' else months_en
82
+
83
+
84
+ def validate_nepali_date(date_str):
85
+ """
86
+ Validate a Nepali date string.
87
+
88
+ Args:
89
+ date_str (str): Date string to validate
90
+
91
+ Returns:
92
+ tuple: (is_valid, error_message)
93
+
94
+ Example:
95
+ >>> validate_nepali_date("2081-01-15")
96
+ (True, None)
97
+ >>> validate_nepali_date("2081-13-01")
98
+ (False, "Month must be between 1 and 12")
99
+ """
100
+ if not date_str:
101
+ return False, "Date string is empty"
102
+
103
+ try:
104
+ parts = date_str.split('-')
105
+ if len(parts) != 3:
106
+ return False, "Invalid date format. Use YYYY-MM-DD"
107
+
108
+ year, month, day = map(int, parts)
109
+
110
+ if year < 1975 or year > 2100:
111
+ return False, "Year must be between 1975 and 2100"
112
+
113
+ if month < 1 or month > 12:
114
+ return False, "Month must be between 1 and 12"
115
+
116
+ if day < 1 or day > 32:
117
+ return False, "Day must be between 1 and 32"
118
+
119
+ # Validate with npdatetime if available
120
+ if NPDATETIME_AVAILABLE:
121
+ try:
122
+ NepaliDate(year, month, day)
123
+ except Exception as e:
124
+ return False, str(e)
125
+
126
+ return True, None
127
+
128
+ except ValueError:
129
+ return False, "Invalid date format. Use YYYY-MM-DD with numeric values"
130
+ except Exception as e:
131
+ return False, str(e)
@@ -0,0 +1,168 @@
1
+ """Custom widgets for Nepali date picker"""
2
+ from django import forms
3
+ from django.forms.widgets import Input
4
+ from django.utils.safestring import mark_safe
5
+ import json
6
+
7
+
8
+ class NepaliDatePickerWidget(Input):
9
+ """
10
+ A widget that renders a Nepali date picker.
11
+
12
+ This widget uses the JavaScript date picker from npdatetime-rust
13
+ to provide a rich, interactive date selection experience.
14
+
15
+ Args:
16
+ mode (str): 'BS' for Bikram Sambat or 'AD' for Gregorian. Default: 'BS'
17
+ language (str): 'en' for English or 'np' for Nepali. Default: 'en'
18
+ include_time (bool): Whether to include time selection. Default: False
19
+ format (str): Date format string. Default: '%Y-%m-%d'
20
+ theme (str): 'auto', 'light', or 'dark'. Default: 'auto'
21
+ show_today_button (bool): Show the "Today" button. Default: True
22
+ show_clear_button (bool): Show the "Clear" button. Default: True
23
+ min_date (str): Minimum selectable date in YYYY-MM-DD format
24
+ max_date (str): Maximum selectable date in YYYY-MM-DD format
25
+
26
+ Example:
27
+ class PersonForm(forms.Form):
28
+ birth_date = forms.CharField(
29
+ widget=NepaliDatePickerWidget(
30
+ mode='BS',
31
+ language='np',
32
+ theme='light'
33
+ )
34
+ )
35
+ """
36
+
37
+ input_type = 'text'
38
+ template_name = 'npdatetime_django/widgets/date_picker.html'
39
+
40
+ class Media:
41
+ css = {
42
+ 'all': ('npdatetime_django/css/date_picker.css',)
43
+ }
44
+ js = (
45
+ 'npdatetime_django/js/date_picker.min.js',
46
+ )
47
+
48
+ def __init__(self, attrs=None, mode='BS', language='en', include_time=False,
49
+ format='%Y-%m-%d', theme='auto', show_today_button=True,
50
+ show_clear_button=True, min_date=None, max_date=None, **kwargs):
51
+ super().__init__(attrs)
52
+
53
+ self.mode = mode
54
+ self.language = language
55
+ self.include_time = include_time
56
+ self.format = format
57
+ self.theme = theme
58
+ self.show_today_button = show_today_button
59
+ self.show_clear_button = show_clear_button
60
+ self.min_date = min_date
61
+ self.max_date = max_date
62
+ self.extra_options = kwargs
63
+
64
+ def get_context(self, name, value, attrs):
65
+ """Build the context for rendering the widget template."""
66
+ context = super().get_context(name, value, attrs)
67
+
68
+ # Ensure attrs is not None
69
+ if attrs is None:
70
+ attrs = {}
71
+
72
+ # Build data attributes for the date picker
73
+ widget_attrs = context['widget']['attrs']
74
+ widget_attrs['data-mode'] = self.mode
75
+ widget_attrs['data-language'] = self.language
76
+ widget_attrs['data-theme'] = self.theme
77
+
78
+ if not widget_attrs.get('class'):
79
+ widget_attrs['class'] = 'npd-input'
80
+ else:
81
+ widget_attrs['class'] += ' npd-input'
82
+
83
+ # Build picker options as JSON
84
+ picker_options = {
85
+ 'mode': self.mode,
86
+ 'language': self.language,
87
+ 'format': self.format,
88
+ 'theme': self.theme,
89
+ 'showTodayButton': self.show_today_button,
90
+ 'showClearButton': self.show_clear_button,
91
+ }
92
+
93
+ if self.include_time:
94
+ picker_options['includeTime'] = True
95
+
96
+ if self.min_date:
97
+ picker_options['minDate'] = self.min_date
98
+
99
+ if self.max_date:
100
+ picker_options['maxDate'] = self.max_date
101
+
102
+ # Add any extra options
103
+ picker_options.update(self.extra_options)
104
+
105
+ context['widget']['picker_options'] = mark_safe(json.dumps(picker_options))
106
+ context['widget']['include_time'] = self.include_time
107
+
108
+ return context
109
+
110
+ def build_attrs(self, base_attrs, extra_attrs=None):
111
+ """Build HTML attributes for the widget."""
112
+ attrs = super().build_attrs(base_attrs, extra_attrs)
113
+
114
+ # Add data attributes
115
+ attrs['data-mode'] = self.mode
116
+ attrs['data-language'] = self.language
117
+ attrs['data-theme'] = self.theme
118
+
119
+ # Set autocomplete off for date pickers
120
+ attrs['autocomplete'] = 'off'
121
+
122
+ # Add placeholder if not set
123
+ if 'placeholder' not in attrs:
124
+ if self.mode == 'BS':
125
+ attrs['placeholder'] = 'Select Nepali Date' if self.language == 'en' else 'मिति छान्नुहोस्'
126
+ else:
127
+ attrs['placeholder'] = 'Select Date'
128
+
129
+ return attrs
130
+
131
+
132
+ class NepaliDateRangeWidget(forms.MultiWidget):
133
+ """
134
+ A widget for selecting a date range with two Nepali date pickers.
135
+
136
+ Example:
137
+ class ReportForm(forms.Form):
138
+ date_range = forms.CharField(
139
+ widget=NepaliDateRangeWidget(mode='BS', language='np')
140
+ )
141
+ """
142
+
143
+ template_name = 'npdatetime_django/widgets/date_range.html'
144
+
145
+ def __init__(self, attrs=None, mode='BS', language='en', **kwargs):
146
+ widgets = [
147
+ NepaliDatePickerWidget(attrs=attrs, mode=mode, language=language, **kwargs),
148
+ NepaliDatePickerWidget(attrs=attrs, mode=mode, language=language, **kwargs),
149
+ ]
150
+ super().__init__(widgets, attrs)
151
+
152
+ def decompress(self, value):
153
+ """
154
+ Split the value into start and end dates.
155
+ Expects value in format: "YYYY-MM-DD to YYYY-MM-DD"
156
+ """
157
+ if value:
158
+ if ' to ' in value:
159
+ return value.split(' to ')
160
+ return [value, '']
161
+ return [None, None]
162
+
163
+ def value_from_datadict(self, data, files, name):
164
+ """Combine the two date values into a single range string."""
165
+ values = super().value_from_datadict(data, files, name)
166
+ if values and len(values) == 2 and values[0] and values[1]:
167
+ return f"{values[0]} to {values[1]}"
168
+ return ''