Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(strftime): treat %% as an escape sequence #137

Merged
merged 1 commit into from
Mar 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 24 additions & 20 deletions jdatetime/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -588,24 +588,24 @@ def __format__(self, format):
return self.strftime(format)

# strftime helper functions
def _strftime_get_attr_value(self, format, symbol, attr, fmt, fb=None):
def _strftime_get_attr_value(self, attr, fmt, fb=None):
try:
return format.replace(symbol, fmt % getattr(self, attr))
except Exception:
return format.replace(symbol, fb)
return fmt % getattr(self, attr)
except AttributeError:
return fb

def _strftime_get_method_value(self, format, symbol, attr, fmt):
return format.replace(symbol, fmt % getattr(self, attr)())
def _strftime_get_method_value(self, attr, fmt):
return fmt % getattr(self, attr)()

def _strftime_p(self, format, **kwrgs):
def _strftime_p(self):
try:
if self.hour >= 12:
return format.replace("%p", self.j_ampm['PM'])
return format.replace("%p", self.j_ampm['AM'])
return self.j_ampm['PM']
return self.j_ampm['AM']
except Exception:
return format.replace("%p", self.j_ampm['AM'])
return self.j_ampm['AM']

def _strftime_z(self, format, **kwrgs):
def _strftime_z(self):
try:
sign = "+"
diff = self.utcoffset()
Expand All @@ -620,15 +620,15 @@ def _strftime_z(self, format, **kwrgs):
tmp_min = diff_sec / 60
diff_hour = tmp_min / 60
diff_min = tmp_min % 60
return format.replace("%z", '%s%02.d%02.d' % (sign, diff_hour, diff_min))
return '%s%02.d%02.d' % (sign, diff_hour, diff_min)
except AttributeError:
return format.replace("%z", '')
return ''

def _strftime_cap_z(self, format, **kwrgs):
def _strftime_cap_z(self):
if hasattr(self, 'tzname') and self.tzname() is not None:
return format.replace("%Z", self.tzname())
return self.tzname()
else:
return format.replace("%Z", '')
return ''

def strftime(self, format):
# Convert to unicode
Expand All @@ -645,12 +645,16 @@ def strftime(self, format):
for s, r in symbols.items():
format = format.replace(s, r)

for symbol in re.findall(r"\%-?[a-zA-z-]", format):
def repl(match):
symbol = match[0]
if symbol in STRFTIME_MAPPING:
replace_method_name, kwargs = STRFTIME_MAPPING[symbol]
kwargs.update({"format": format, "symbol": symbol})
format = getattr(self, replace_method_name)(**kwargs)
return format
return getattr(self, replace_method_name)(**kwargs)
if symbol == "%%":
return "%"
return symbol

return re.sub(r"%-?[A-Za-z%-]", repl, format)

def aslocale(self, locale):
return date(self.year, self.month, self.day, locale=locale)
Expand Down
8 changes: 8 additions & 0 deletions tests/test_jdatetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,14 @@ def test_strftime_single_digit(self):
"2 02 3 03 4 04 5 05 6 06",
)

def test_strftime_escape_percent(self):
dt = jdatetime.datetime(1402, 1, 7)
self.assertEqual(dt.strftime("%%d=%d"), "%d=07")
self.assertEqual(dt.strftime("%%%d"), "%07")

def test_strftime_unknown_directive(self):
self.assertEqual(jdatetime.date.today().strftime("%Q"), "%Q")

def test_kabiseh(self):
kabiseh_year = jdatetime.date.fromgregorian(date=datetime.date(2013, 3, 20))
self.assertTrue(kabiseh_year.isleap())
Expand Down