Add $datetime() function and associated tests

This commit is contained in:
Bob Swift
2020-02-04 14:24:35 -07:00
committed by Philipp Wolfer
parent f090c06572
commit 7762f9b929
2 changed files with 89 additions and 0 deletions

View File

@@ -21,6 +21,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from collections import namedtuple
import datetime
from functools import reduce
from inspect import getfullargspec
import operator
@@ -1201,3 +1202,28 @@ def func_slice(parser, multi, start_index, end_index, separator=MULTI_VALUED_JOI
return separator.join(multi_var[start:end])
except IndexError:
return ''
@script_function()
def func_datetime(parser, format=None):
"""Return the current date and time as a string.
Arguments:
parser: The ScriptParser object used to parse the script.
format: A string or the ScriptVariable/Function that evaluates to the
string used to format the output. Default is '%Y-%m-%d %H:%M:%S'
if blank. Uses strftime() format.
Returns:
Returns the current date and time as a string.
"""
# local_tz required for Python 3.5 which does not allow setting astimezone()
# on a naive datetime.datetime object. This provides timezone information to
# allow the use of %Z and %z in the output format.
local_tz = datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo
# Handle case where format evaluates to ''
if not format:
format = '%Y-%m-%d %H:%M:%S'
return datetime.datetime.now(tz=local_tz).strftime(format)

View File

@@ -1,3 +1,4 @@
import datetime
from unittest.mock import MagicMock
from test.picardtestcase import PicardTestCase
@@ -16,6 +17,38 @@ from picard.script import (
)
class _TestTimezone(datetime.tzinfo):
def utcoffset(self, dt):
# Set to GMT+2
return datetime.timedelta(hours=2) + self.dst(dt)
def dst(self, dt):
d = datetime.datetime(dt.year, 4, 1)
self.dston = d - datetime.timedelta(days=d.weekday() + 1)
d = datetime.datetime(dt.year, 11, 1)
self.dstoff = d - datetime.timedelta(days=d.weekday() + 1)
if self.dston <= dt.replace(tzinfo=None) < self.dstoff:
return datetime.timedelta(hours=1)
else:
return datetime.timedelta(0)
def tzname(self,dt):
return "TZ Test"
class _DateTime(datetime.datetime):
@classmethod
def now(cls, tz=None):
return datetime.datetime(2020, 1, 2, hour=12, minute=34, second=56, microsecond=789, tzinfo=tz)
def astimezone(self, tz=None):
# Ignore tz passed to the method and force use of test timezone.
tz = _TestTimezone()
utc = (self - self.utcoffset()).replace(tzinfo=tz)
# Convert from UTC to tz's local time.
return tz.fromutc(utc)
class ScriptParserTest(PicardTestCase):
def setUp(self):
@@ -943,3 +976,33 @@ class ScriptParserTest(PicardTestCase):
self.parser.eval("$slice(abc; def,0)")
with self.assertRaisesRegex(ScriptError, areg):
self.parser.eval("$slice(abc; def),0,1,:,extra")
def test_cmd_datetime(self):
# Save origninal datetime object and substitute one returning
# a fixed now() value for testing.
original_datetime = datetime.datetime
datetime.datetime = _DateTime
try:
context = Metadata()
context["foo"] = "%Y%m%d%H%M%S.%f"
# Tests with context
self.assertScriptResultEquals("$datetime(%foo%)", "20200102123456.000789", context)
self.assertScriptResultEquals("$datetime($initials())", "2020-01-02 12:34:56", context)
# Tests with static input
self.assertScriptResultEquals("$datetime(\%Y\%m\%d\%H\%M\%S.\%f)", "20200102123456.000789", context)
# Tests with timezones
self.assertScriptResultEquals("$datetime(\%H\%M\%S \%z \%Z)", "123456 +0200 TZ Test", context)
# Tests with missing input
self.assertScriptResultEquals("$datetime()", "2020-01-02 12:34:56", context)
# Tests with invalid format
self.assertScriptResultEquals("$datetime(xxx)", "xxx", context)
# Tests with invalid number of arguments
areg = r"^Wrong number of arguments for \$datetime: Expected between 0 and 1, "
with self.assertRaisesRegex(ScriptError, areg):
self.parser.eval("$datetime(abc,def)")
except (AssertionError, ValueError, IndexError) as err:
raise err
finally:
# Restore origninal datetime object
datetime.datetime = original_datetime