nepali 1.0.1__py3-none-any.whl → 1.1.1__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.

Potentially problematic release.


This version of nepali might be problematic. Click here for more details.

Files changed (37) hide show
  1. nepali/{datetime/constants.py → constants.py} +15 -2
  2. nepali/date_converter.py +4 -4
  3. nepali/datetime/__init__.py +1 -1
  4. nepali/datetime/_datetime.py +12 -13
  5. nepali/datetime/_formatter.py +3 -2
  6. nepali/datetime/_humanize.py +14 -29
  7. nepali/datetime/_nepalimonth.py +7 -6
  8. nepali/datetime/_nepaliweek.py +4 -3
  9. nepali/datetime/parser/__init__.py +1 -1
  10. nepali/datetime/parser/_parser.py +7 -9
  11. nepali/datetime/parser/validators.py +162 -78
  12. nepali/datetime/utils.py +1 -0
  13. nepali/locations/__init__.py +1 -1
  14. nepali/locations/_locations.py +1 -1
  15. nepali/locations/utils.py +1 -2
  16. nepali/number/__init__.py +1 -1
  17. nepali/number/_nepalinumber.py +26 -12
  18. nepali/number/_number.py +1 -6
  19. nepali/number/utils.py +1 -2
  20. nepali/phone_number.py +2 -3
  21. nepali/templatetags/nepalidatetime.py +37 -0
  22. nepali/templatetags/nepalinumber.py +26 -0
  23. nepali/tests/test_date_converter.py +17 -4
  24. nepali/tests/test_datetime.py +3 -5
  25. nepali/tests/test_humanize.py +1 -2
  26. nepali/tests/test_locations.py +3 -3
  27. nepali/tests/test_number.py +35 -33
  28. nepali/tests/test_phone_number.py +3 -3
  29. nepali/tests/test_timezone.py +6 -5
  30. nepali/timezone.py +5 -3
  31. nepali/utils.py +1 -1
  32. {nepali-1.0.1.dist-info → nepali-1.1.1.dist-info}/METADATA +11 -85
  33. nepali-1.1.1.dist-info/RECORD +46 -0
  34. {nepali-1.0.1.dist-info → nepali-1.1.1.dist-info}/WHEEL +1 -1
  35. nepali-1.0.1.dist-info/RECORD +0 -46
  36. {nepali-1.0.1.dist-info → nepali-1.1.1.dist-info}/LICENSE +0 -0
  37. {nepali-1.0.1.dist-info → nepali-1.1.1.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,12 @@
1
- MONTHS_EN = (
1
+ """
2
+ This files contains constants for the py-Nepali project.
3
+ """
4
+
5
+ # Nepali timezone
6
+ NEPAL_TIMEZONE = "Asia/Kathmandu"
7
+
8
+ # Nepali months in english
9
+ NEPALI_MONTHS_EN = (
2
10
  "Baishakh",
3
11
  "Jestha",
4
12
  "Ashad",
@@ -13,7 +21,8 @@ MONTHS_EN = (
13
21
  "Chaitra",
14
22
  )
15
23
 
16
- MONTHS_NE = (
24
+ # Nepali months in Nepali (devanagari)
25
+ NEPALI_MONTHS_NE = (
17
26
  "बैशाख",
18
27
  "जेठ",
19
28
  "असार",
@@ -28,6 +37,7 @@ MONTHS_NE = (
28
37
  "चैत",
29
38
  )
30
39
 
40
+ # Week names in english
31
41
  WEEKS_EN = (
32
42
  "Sunday",
33
43
  "Monday",
@@ -38,8 +48,10 @@ WEEKS_EN = (
38
48
  "Saturday",
39
49
  )
40
50
 
51
+ # Week abbreviation name in english
41
52
  WEEKS_ABBR_EN = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat")
42
53
 
54
+ # Weeks names in Nepali (devanagari)
43
55
  WEEKS_NE = (
44
56
  "आइतबार",
45
57
  "सोमबार",
@@ -50,4 +62,5 @@ WEEKS_NE = (
50
62
  "शनिबार",
51
63
  )
52
64
 
65
+ # Week abbreviation name in Nepali (devanagari)
53
66
  WEEKS_ABBR_NE = ("आइत", "सोम", "मंगल", "बुध", "बिही", "शुक्र", "शनि")
nepali/date_converter.py CHANGED
@@ -78,7 +78,7 @@ class NepaliDateConverter:
78
78
  ((31, 31, 31, 32, 31, 31, 30, 29, 30, 29, 30, 30), 365),
79
79
  ((31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30), 365),
80
80
  ((31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 30), 365),
81
- ((31, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31), 366),
81
+ ((31, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31), 366), # 2050
82
82
  ((31, 31, 31, 32, 31, 31, 30, 29, 30, 29, 30, 30), 365),
83
83
  ((31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30), 365),
84
84
  ((31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 30), 365),
@@ -98,7 +98,7 @@ class NepaliDateConverter:
98
98
  ((31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30), 365),
99
99
  ((31, 31, 32, 32, 31, 30, 30, 29, 30, 29, 30, 30), 365),
100
100
  ((31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31), 366),
101
- ((31, 31, 31, 32, 31, 31, 29, 30, 30, 29, 30, 30), 365),
101
+ ((31, 31, 31, 32, 31, 31, 29, 30, 30, 29, 30, 30), 365), # 2070
102
102
  ((31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30), 365),
103
103
  ((31, 32, 31, 32, 31, 30, 30, 29, 30, 29, 30, 30), 365),
104
104
  ((31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31), 366),
@@ -108,8 +108,8 @@ class NepaliDateConverter:
108
108
  ((31, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31), 366),
109
109
  ((31, 31, 31, 32, 31, 31, 30, 29, 30, 29, 30, 30), 365),
110
110
  ((31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30), 365),
111
- ((31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 30), 365),
112
- ((31, 31, 32, 32, 31, 30, 30, 30, 29, 30, 30, 30), 366),
111
+ ((31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 30), 365), # 2080
112
+ ((31, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31), 366),
113
113
  ((30, 32, 31, 32, 31, 30, 30, 30, 29, 30, 30, 30), 365),
114
114
  ((31, 31, 32, 31, 31, 30, 30, 30, 29, 30, 30, 30), 365),
115
115
  ((31, 31, 32, 31, 31, 30, 30, 30, 29, 30, 30, 30), 365),
@@ -1,4 +1,4 @@
1
- from ._datetime import nepalidate, nepalitime, nepalidatetime
1
+ from ._datetime import nepalidate, nepalidatetime, nepalitime
2
2
  from ._formatter import NepaliDateTimeFormatter
3
3
  from ._humanize import HumanizeDateTime, nepalihumanize
4
4
  from ._nepalimonth import nepalimonth
@@ -1,7 +1,7 @@
1
1
  import datetime as pythonDateTime
2
2
 
3
3
  from nepali.date_converter import converter as nepali_date_converter
4
- from nepali.timezone import NepaliTimeZone, utc_now, to_nepali_timezone
4
+ from nepali.timezone import NepaliTimeZone, to_nepali_timezone, utc_now
5
5
 
6
6
  from ._nepalimonth import nepalimonth
7
7
 
@@ -17,31 +17,31 @@ class formatter_class_mixin:
17
17
 
18
18
  @classmethod
19
19
  def init_formatter_class(cls):
20
- if not hasattr(cls, "__formatter_class__Cache"):
20
+ if not hasattr(cls, "_formatter_class_cache"):
21
21
  from ._formatter import NepaliDateTimeFormatter
22
22
 
23
- cls.__formatter_class__Cache = NepaliDateTimeFormatter
24
- return cls.__formatter_class__Cache
23
+ cls._formatter_class_cache = NepaliDateTimeFormatter
24
+ return cls._formatter_class_cache
25
25
 
26
26
  @classmethod
27
27
  def get_strptime_method(cls):
28
- if not hasattr(cls, "_strptime_method_CACHE"):
28
+ if not hasattr(cls, "_strptime_method_cache"):
29
29
  from .parser import strptime
30
30
 
31
- cls._strptime_method_CACHE = strptime
32
- return cls._strptime_method_CACHE
31
+ cls._strptime_method_cache = strptime
32
+ return cls._strptime_method_cache
33
33
 
34
34
  def strftime(self, format: str) -> str:
35
35
  return self.strftime_en(format)
36
36
 
37
37
  def strftime_en(self, format: str) -> str:
38
- NepaliDateTimeFormatter = self.get_formatter_class()
39
- formatter = NepaliDateTimeFormatter(self, devanagari=False)
38
+ nepali_datetime_formatter = self.get_formatter_class()
39
+ formatter = nepali_datetime_formatter(self, devanagari=False)
40
40
  return formatter.get_str(format)
41
41
 
42
42
  def strftime_ne(self, format: str) -> str:
43
- NepaliDateTimeFormatter = self.get_formatter_class()
44
- formatter = NepaliDateTimeFormatter(self, devanagari=True)
43
+ nepali_datetime_formatter = self.get_formatter_class()
44
+ formatter = nepali_datetime_formatter(self, devanagari=True)
45
45
  return formatter.get_str(format)
46
46
 
47
47
 
@@ -194,12 +194,11 @@ class nepalidate(formatter_class_mixin):
194
194
 
195
195
  @staticmethod
196
196
  def from_date(date_object):
197
- npDate = nepalidate(
197
+ return nepalidate(
198
198
  *nepali_date_converter.english_to_nepali(
199
199
  date_object.year, date_object.month, date_object.day
200
200
  )
201
201
  )
202
- return npDate
203
202
 
204
203
  @staticmethod
205
204
  def from_nepalidatetime(datetime_object):
@@ -1,4 +1,5 @@
1
1
  import datetime as pythonDateTime
2
+
2
3
  from nepali import number
3
4
  from nepali.exceptions import (
4
5
  InvalidDateFormatException,
@@ -40,7 +41,7 @@ class NepaliDateTimeFormatter:
40
41
  }
41
42
 
42
43
  def __init__(self, datetime_object, devanagari=False):
43
- # TODO: Change variable npDateTime into snakecase: `np_date_time`
44
+ # TODO: Change variable npDateTime into snake case: `np_date_time`
44
45
  if type(datetime_object) == nepalidatetime:
45
46
  self.npDateTime = datetime_object
46
47
  elif type(datetime_object) == nepalidate:
@@ -100,7 +101,7 @@ class NepaliDateTimeFormatter:
100
101
 
101
102
  def get_format_map(self, ch: str) -> str:
102
103
  if ch not in self.format_map:
103
- raise InvalidDateFormatException("Invalid Date format %{}".format(ch))
104
+ raise InvalidDateFormatException(f"Invalid Date format %{ch}")
104
105
  return self.format_map[ch]
105
106
 
106
107
  @property
@@ -1,10 +1,7 @@
1
- import datetime as pythonDateTime
2
-
3
1
  from nepali import number
4
- from nepali.timezone import now, to_nepali_timezone
5
- from nepali.exceptions import InvalidNepaliDateTimeObjectException
2
+ from nepali.timezone import now
6
3
 
7
- from ._datetime import nepalidate, nepalidatetime
4
+ from .utils import to_nepalidatetime
8
5
 
9
6
 
10
7
  class HumanizeDateTime:
@@ -29,20 +26,7 @@ class HumanizeDateTime:
29
26
  threshold (kwargs): threshold to be humanize
30
27
  format (kwargs): format to display behind threshold
31
28
  """
32
- if type(datetime_obj) == nepalidatetime:
33
- self.datetime_obj = datetime_obj.to_datetime()
34
- elif type(datetime_obj) == nepalidate:
35
- self.datetime_obj = nepalidatetime.from_nepali_date(
36
- datetime_obj
37
- ).to_datetime()
38
- elif type(datetime_obj) == pythonDateTime.date:
39
- self.datetime_obj = nepalidatetime.from_date(datetime_obj).to_datetime()
40
- elif type(datetime_obj) == pythonDateTime.datetime:
41
- self.datetime_obj = to_nepali_timezone(datetime_obj)
42
- else:
43
- raise InvalidNepaliDateTimeObjectException(
44
- "Argument must be instance of NepaliDate or NepaliDateTime or datetime.datetime or datetime.date"
45
- )
29
+ self.datetime_obj = to_nepalidatetime(datetime_obj)
46
30
 
47
31
  self.threshold = kwargs.get("threshold")
48
32
  self.format = kwargs.get("format")
@@ -53,8 +37,11 @@ class HumanizeDateTime:
53
37
  def __calc_seconds(self):
54
38
  """calculates total seconds from now"""
55
39
  current_date_time = now()
56
- date = self.datetime_obj
57
- self.seconds = int((current_date_time - date).total_seconds())
40
+
41
+ # TODO (@aj3sh): support datetime - nepalidatetime
42
+ self.seconds = int(
43
+ (current_date_time - self.datetime_obj.to_datetime()).total_seconds()
44
+ )
58
45
 
59
46
  self.interval_tense = self.__past_text
60
47
  if self.seconds < 0:
@@ -67,13 +54,12 @@ class HumanizeDateTime:
67
54
  """returns humanize string"""
68
55
  seconds = self.__calc_seconds() # calculating seconds
69
56
 
70
- if self.threshold is not None:
71
- if seconds >= self.threshold:
72
- return self.get_datetime().strip()
57
+ if self.threshold is not None and seconds >= self.threshold:
58
+ return self._get_datetime_str().strip()
73
59
 
74
- return self.get_humanize().strip()
60
+ return self._get_humanize_str().strip()
75
61
 
76
- def get_humanize(self):
62
+ def _get_humanize_str(self):
77
63
  """
78
64
  returns humanize datetime
79
65
  """
@@ -118,14 +104,13 @@ class HumanizeDateTime:
118
104
  str(interval_value) + " " + str(interval_text) + " " + self.interval_tense
119
105
  )
120
106
 
121
- def get_datetime(self):
107
+ def _get_datetime_str(self):
122
108
  """
123
109
  returns date in nepali characters
124
110
  """
125
111
  if not self.format:
126
112
  self.format = "%B %d, %Y"
127
- ndt = nepalidatetime.from_datetime(self.datetime_obj)
128
- return ndt.strftime_ne(self.format)
113
+ return self.datetime_obj.strftime_ne(self.format)
129
114
 
130
115
  def __str__(self):
131
116
  return self.to_str()
@@ -1,7 +1,7 @@
1
1
  from functools import cached_property
2
2
  from typing import Any, Dict, Optional, Union
3
3
 
4
- from .constants import MONTHS_EN, MONTHS_NE
4
+ from nepali.constants import NEPALI_MONTHS_EN, NEPALI_MONTHS_NE
5
5
 
6
6
 
7
7
  class NepaliMonthMeta(type):
@@ -40,7 +40,8 @@ class NepaliMonthMeta(type):
40
40
 
41
41
  return cls._cache[value]
42
42
 
43
- def _parse_str(cls, month: str) -> int:
43
+ @staticmethod
44
+ def _parse_str(month: str) -> int:
44
45
  """
45
46
  Parses str value of the month and returns int.
46
47
 
@@ -54,7 +55,7 @@ class NepaliMonthMeta(type):
54
55
  return int(month)
55
56
 
56
57
  month = month.capitalize()
57
- month_names = MONTHS_EN + MONTHS_NE
58
+ month_names = NEPALI_MONTHS_EN + NEPALI_MONTHS_NE
58
59
  try:
59
60
  index = month_names.index(month)
60
61
  except ValueError:
@@ -66,7 +67,7 @@ class NepaliMonthMeta(type):
66
67
  class nepalimonth(metaclass=NepaliMonthMeta):
67
68
  """
68
69
  Represents Nepali month: Baishakh, Jestha, ..., Chaitra.
69
- Baishak: 1,
70
+ Baishakh: 1,
70
71
  Jestha: 2,
71
72
  ...
72
73
  Chaitra: 12
@@ -107,9 +108,9 @@ class nepalimonth(metaclass=NepaliMonthMeta):
107
108
  @cached_property
108
109
  def name(self) -> str:
109
110
  """Month's english name"""
110
- return MONTHS_EN[self.__value - 1]
111
+ return NEPALI_MONTHS_EN[self.__value - 1]
111
112
 
112
113
  @cached_property
113
114
  def name_ne(self) -> str:
114
115
  """Month's nepali name"""
115
- return MONTHS_NE[self.__value - 1]
116
+ return NEPALI_MONTHS_NE[self.__value - 1]
@@ -1,7 +1,7 @@
1
1
  from functools import cached_property
2
2
  from typing import Any, Dict, Optional, Union
3
3
 
4
- from .constants import WEEKS_EN, WEEKS_NE, WEEKS_ABBR_EN, WEEKS_ABBR_NE
4
+ from nepali.constants import WEEKS_ABBR_EN, WEEKS_ABBR_NE, WEEKS_EN, WEEKS_NE
5
5
 
6
6
 
7
7
  class NepaliWeekMeta(type):
@@ -28,7 +28,7 @@ class NepaliWeekMeta(type):
28
28
  pass
29
29
 
30
30
  # checking if week is valid
31
- if value is None or not (0 <= value <= 6):
31
+ if value is None or not 0 <= value <= 6:
32
32
  raise ValueError(f"Invalid week: {week}")
33
33
 
34
34
  # checking cache
@@ -37,7 +37,8 @@ class NepaliWeekMeta(type):
37
37
 
38
38
  return cls._cache[value]
39
39
 
40
- def _parse_str(cls, week: str) -> int:
40
+ @staticmethod
41
+ def _parse_str(week: str) -> int:
41
42
  """
42
43
  Parses str value of the week and returns int.
43
44
 
@@ -1,4 +1,4 @@
1
- from ._parser import strptime, parse
1
+ from ._parser import parse, strptime
2
2
 
3
3
  __all__ = [
4
4
  "strptime",
@@ -1,4 +1,4 @@
1
- from nepali.exceptions import InvalidDateTimeFormatException, FormatNotMatchException
1
+ from nepali.exceptions import FormatNotMatchException, InvalidDateTimeFormatException
2
2
 
3
3
  from .validators import validate
4
4
 
@@ -53,10 +53,8 @@ def _get_standard_formats():
53
53
  for time_format in STANDARD_TIME_FORMAT:
54
54
  for date_format in STANDARD_DATE_FORMAT:
55
55
  _standard_datetime_format_CACHE += [
56
- "{} {}".format(date_format, time_format)
57
- ]
58
- _standard_datetime_format_CACHE += [
59
- "{}, {}".format(date_format, time_format)
56
+ f"{date_format} {time_format}",
57
+ f"{date_format}, {time_format}",
60
58
  ]
61
59
  return _standard_datetime_format_CACHE
62
60
 
@@ -67,10 +65,10 @@ def parse(datetime_str):
67
65
  eg. parse('2078-10-12') => <NepaliDateTime: 2078-10-12>
68
66
  """
69
67
  standard_formats = _get_standard_formats()
70
- nepalidatetime_object = None
71
68
  for format in standard_formats:
72
- nepalidatetime_object = validate(datetime_str, format=format)
73
- if nepalidatetime_object is not None:
74
- return nepalidatetime_object
69
+ try:
70
+ return strptime(datetime_str, format=format)
71
+ except FormatNotMatchException:
72
+ pass
75
73
 
76
74
  raise InvalidDateTimeFormatException("Invalid format to parse nepali datetime.")
@@ -2,11 +2,11 @@
2
2
  validates parsing
3
3
  """
4
4
  import re
5
+ from typing import Optional, Tuple
5
6
 
6
7
  from nepali.char import nepali_to_english_text
8
+ from nepali.constants import NEPALI_MONTHS_EN, WEEKS_ABBR_EN, WEEKS_EN
7
9
  from nepali.datetime import nepalidatetime, nepalimonth, nepaliweek
8
- from nepali.datetime.constants import MONTHS_EN, WEEKS_EN, WEEKS_ABBR_EN
9
-
10
10
 
11
11
  __nepali_time_re__CACHE = None
12
12
 
@@ -41,8 +41,8 @@ class NepaliTimeRE(dict):
41
41
  "z": r"(?P<z>[+-]\d\d:?[0-5]\d(:?[0-5]\d(\.\d{1,6})?)?|(?-i:Z))",
42
42
  "A": self.__seqToRE(WEEKS_EN, "A"),
43
43
  "a": self.__seqToRE(WEEKS_ABBR_EN, "a"),
44
- "B": self.__seqToRE(MONTHS_EN, "B"),
45
- "b": self.__seqToRE(MONTHS_EN, "b"),
44
+ "B": self.__seqToRE(NEPALI_MONTHS_EN, "B"),
45
+ "b": self.__seqToRE(NEPALI_MONTHS_EN, "b"),
46
46
  "p": self.__seqToRE(
47
47
  (
48
48
  "AM",
@@ -68,39 +68,42 @@ class NepaliTimeRE(dict):
68
68
  else:
69
69
  return ""
70
70
  regex = "|".join(re.escape(stuff) for stuff in to_convert)
71
- regex = "(?P<%s>%s" % (directive, regex)
72
- return "%s)" % regex
71
+ regex = f"(?P<{directive}>{regex}"
72
+ return f"{regex})"
73
73
 
74
- def pattern(self, format):
74
+ def pattern(self, date_format):
75
75
  """
76
- Handle conversion from format directives to regexes.
76
+ Handle conversion from format directives to regex.
77
77
  """
78
78
  processed_format = ""
79
79
  regex_chars = re.compile(r"([\\.^$*+?\(\){}\[\]|])")
80
- format = regex_chars.sub(r"\\\1", format)
80
+ date_format = regex_chars.sub(r"\\\1", date_format)
81
81
  whitespace_replacement = re.compile(r"\s+")
82
- format = whitespace_replacement.sub(r"\\s+", format)
83
- while "%" in format:
84
- directive_index = format.index("%") + 1
82
+ date_format = whitespace_replacement.sub(r"\\s+", date_format)
83
+ while "%" in date_format:
84
+ directive_index = date_format.index("%") + 1
85
85
  index_increment = 1
86
86
 
87
- if format[directive_index] == "-":
87
+ if date_format[directive_index] == "-":
88
88
  index_increment = 2
89
89
 
90
- if format[directive_index : directive_index + index_increment] not in self:
90
+ if (
91
+ date_format[directive_index : directive_index + index_increment]
92
+ not in self
93
+ ):
91
94
  return None
92
95
 
93
96
  processed_format = "%s%s%s" % (
94
97
  processed_format,
95
- format[: directive_index - 1],
96
- self[format[directive_index : directive_index + index_increment]],
98
+ date_format[: directive_index - 1],
99
+ self[date_format[directive_index : directive_index + index_increment]],
97
100
  )
98
- format = format[directive_index + index_increment :]
99
- return "^%s%s$" % (processed_format, format)
101
+ date_format = date_format[directive_index + index_increment :]
102
+ return f"^{processed_format}{date_format}$"
100
103
 
101
- def compile(self, format):
104
+ def compile(self, date_format):
102
105
  """Return a compiled re object for the format string."""
103
- return re.compile(self.pattern(format), re.IGNORECASE)
106
+ return re.compile(self.pattern(date_format), re.IGNORECASE)
104
107
 
105
108
 
106
109
  def get_nepali_time_re_object():
@@ -131,13 +134,144 @@ def extract(datetime_str, format):
131
134
  # converting datetime_str to english if any exists
132
135
  datetime_str = nepali_to_english_text(datetime_str)
133
136
 
134
- re_compiled_format = get_nepali_time_re_object().compile(format=format)
137
+ re_compiled_format = get_nepali_time_re_object().compile(format)
135
138
  match = re_compiled_format.match(datetime_str)
136
139
  if match is None:
137
140
  return {}
138
141
  return match.groupdict()
139
142
 
140
143
 
144
+ def __convert_12_hour_to_24_hour(hour: int, am_pm: str) -> int:
145
+ """Converts hours from 12-hour format to 24-hour format.
146
+
147
+ :param hour: The hour value to convert.
148
+ :param am_pm: Either "am" or "pm"; signifies whether the hour is in am or pm.
149
+
150
+ :returns: The value of `hour` converted to 24-hour format.
151
+ """
152
+ am_pm = am_pm.lower()
153
+ if am_pm == "am" and hour == 12:
154
+ return 0
155
+ elif am_pm == "pm" and hour != 12:
156
+ return hour + 12
157
+ return hour
158
+
159
+
160
+ def __calculate_year(data: dict) -> Optional[int]:
161
+ """Calculates the year value from given data.
162
+
163
+ :param data: The dictionary of the format:
164
+ {
165
+ "Y": 2078,
166
+ "b": "Mangsir",
167
+ "d": 12,
168
+ ...
169
+ }
170
+
171
+ :returns: The year value of given date data.
172
+ """
173
+ if "y" in data:
174
+ return int(data["y"]) + 2000
175
+ elif "Y" in data:
176
+ return int(data["Y"])
177
+ return None
178
+
179
+
180
+ def __calculate_month(data: dict) -> nepalimonth:
181
+ """Calculates the month value from given data.
182
+
183
+ :param data: The dictionary of the format:
184
+ {
185
+ "Y": 2078,
186
+ "b": "Mangsir",
187
+ "d": 12,
188
+ ...
189
+ }
190
+
191
+ :returns: The month value of given date data.
192
+ """
193
+ if "m" in data:
194
+ return nepalimonth(int(data["m"]))
195
+ elif "b" in data:
196
+ return nepalimonth(data["b"])
197
+ elif "B" in data:
198
+ return nepalimonth(data["B"])
199
+ return nepalimonth(1)
200
+
201
+
202
+ def __calculate_day(data: dict) -> int:
203
+ """Calculates the day value from given data.
204
+
205
+ :param data: The dictionary of the format:
206
+ {
207
+ "Y": 2078,
208
+ "b": "Mangsir",
209
+ "d": 12,
210
+ ...
211
+ }
212
+
213
+ :returns: The day value of given date data.
214
+ """
215
+ if "d" in data:
216
+ return int(data["d"])
217
+ return 1
218
+
219
+
220
+ def __calculate_hour_minute_seconds(data: dict) -> Tuple[int, int, int, int]:
221
+ """Calculates hour, minutes, seconds and microseconds from given data.
222
+
223
+ :param data: The dictionary of the format:
224
+ {
225
+ "Y": 2078,
226
+ "b": "Mangsir",
227
+ "d": 12,
228
+ "H": 12,
229
+ "M": 12,
230
+ "S": 12,
231
+ "f": 12,
232
+ ...
233
+ }
234
+
235
+ :returns: A tuple of hour, minute, seconds and microseconds.
236
+ """
237
+ hour = minute = second = fraction = 0
238
+ if "H" in data:
239
+ hour = int(data["H"])
240
+ elif "I" in data:
241
+ am_pm = data.get("p", "").lower() or "am"
242
+ hour = __convert_12_hour_to_24_hour(hour=int(data["I"]), am_pm=am_pm)
243
+
244
+ if "M" in data:
245
+ minute = int(data["M"])
246
+
247
+ if "S" in data:
248
+ second = int(data["S"])
249
+
250
+ if "f" in data:
251
+ s = data["f"]
252
+ # Pad to always return microseconds.
253
+ s += "0" * (6 - len(s))
254
+ fraction = int(s)
255
+
256
+ return hour, minute, second, fraction
257
+
258
+
259
+ def __calculate_weekday(data: dict) -> Optional[nepaliweek]:
260
+ """Calculates the weekday of the date given in data.
261
+
262
+ :param data: The data that describes the date.
263
+
264
+ :returns: The weekday value; 0 for Sunday, 1 for Monday, etc.
265
+ """
266
+ if "a" in data:
267
+ return nepaliweek(data["a"])
268
+ elif "A" in data:
269
+ return nepaliweek(data["A"])
270
+ elif "w" in data:
271
+ return nepaliweek((int(data["w"]) - 1) % 7)
272
+ return None
273
+
274
+
141
275
  def transform(data: dict):
142
276
  """
143
277
  transforms different format data to uniform data
@@ -160,62 +294,12 @@ def transform(data: dict):
160
294
  }
161
295
  """
162
296
 
163
- year = None
164
- month = day = 1
165
- hour = minute = second = fraction = 0
166
- weekday = None
167
-
168
- for date_key in data.keys():
169
- if date_key == "y":
170
- year = int(data["y"])
171
- year += 2000
172
- elif date_key == "Y":
173
- year = int(data["Y"])
174
- elif date_key == "m":
175
- month = int(data["m"])
176
- elif date_key == "B":
177
- month = nepalimonth(data["B"])
178
- elif date_key == "b":
179
- month = nepalimonth(data["b"])
180
- elif date_key == "d":
181
- day = int(data["d"])
182
- elif date_key == "H":
183
- hour = int(data["H"])
184
- elif date_key == "I":
185
- hour = int(data["I"])
186
- ampm = data.get("p", "").lower()
187
- # If there was no AM/PM indicator, we'll treat this like AM
188
- if ampm in ("", "am"):
189
- # We're in AM so the hour is correct unless we're
190
- # looking at 12 midnight.
191
- # 12 midnight == 12 AM == hour 0
192
- if hour == 12:
193
- hour = 0
194
- elif ampm == "pm":
195
- # We're in PM so we need to add 12 to the hour unless
196
- # we're looking at 12 noon.
197
- # 12 noon == 12 PM == hour 12
198
- if hour != 12:
199
- hour += 12
200
- elif date_key == "M":
201
- minute = int(data["M"])
202
- elif date_key == "S":
203
- second = int(data["S"])
204
- elif date_key == "f":
205
- s = data["f"]
206
- # Pad to always return microseconds.
207
- s += "0" * (6 - len(s))
208
- fraction = int(s)
209
- elif date_key == "A":
210
- weekday = nepaliweek(data["A"])
211
- elif date_key == "a":
212
- weekday = nepaliweek(data["a"])
213
- elif date_key == "w":
214
- weekday = int(data["w"])
215
- if weekday == 0:
216
- weekday = 6
217
- else:
218
- weekday -= 1
297
+ year = __calculate_year(data)
298
+ month = __calculate_month(data)
299
+ day = __calculate_day(data)
300
+ hour, minute, second, fraction = __calculate_hour_minute_seconds(data)
301
+ weekday = __calculate_weekday(data)
302
+
219
303
  return {
220
304
  "year": year,
221
305
  "month": month,
@@ -239,7 +323,7 @@ def validate(datetime_str, format):
239
323
  """
240
324
 
241
325
  # 1. validate if format is correct.
242
- if get_nepali_time_re_object().pattern(format=format) is None:
326
+ if get_nepali_time_re_object().pattern(format) is None:
243
327
  # regex pattern generation failed
244
328
  return None
245
329