From a1d8ca936408a0fb4908b541225e2faa21e0c6cc Mon Sep 17 00:00:00 2001 From: Rebecca Law Date: Mon, 9 Jan 2017 15:34:24 +0000 Subject: [PATCH] Use a variable for the massive month date conversion. Document the massive date function. Document the get_april_fools function. --- app/dao/notifications_dao.py | 36 +++++++++++++++----------- tests/app/dao/test_notification_dao.py | 4 ++- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/app/dao/notifications_dao.py b/app/dao/notifications_dao.py index 4295eb48b..3f08f8889 100644 --- a/app/dao/notifications_dao.py +++ b/app/dao/notifications_dao.py @@ -215,28 +215,28 @@ def get_notifications_for_job(service_id, job_id, filter_dict=None, page=1, page def get_notification_billable_unit_count_per_month(service_id, year): start, end = get_financial_year(year) + """ + The query needs to sum the billable_units per month, but this needs to be the month in BST (Britsh Standard Time). + The database stores all timestamps as UTC without the timezone. + - First get the created_at as Europe/London or BST + - then extract the timezone portion of the datetime + - then add the timezone portion to the created_at datetime + - lastly truncate the datetime to month to group the sum of the billable_units + """ + month = func.date_trunc("month", (NotificationHistory.created_at + + extract("timezone", + func.timezone("Europe/London", + NotificationHistory.created_at)) * timedelta(seconds=1))) notifications = db.session.query( - func.date_trunc("month", - (NotificationHistory.created_at + - extract("timezone", func.timezone("Europe/London", - NotificationHistory.created_at)) * timedelta(seconds=1))), + month, func.sum(NotificationHistory.billable_units) ).filter( NotificationHistory.billable_units != 0, NotificationHistory.service_id == service_id, NotificationHistory.created_at >= start, NotificationHistory.created_at < end - ).group_by(func.date_trunc("month", - (NotificationHistory.created_at + - extract("timezone", - func.timezone("Europe/London", - NotificationHistory.created_at)) * timedelta(seconds=1))) - ).order_by(func.date_trunc("month", - (NotificationHistory.created_at + - extract("timezone", - func.timezone("Europe/London", - NotificationHistory.created_at)) * timedelta( - seconds=1)))).all() + ).group_by(month + ).order_by(month).all() return [(datetime.strftime(x[0], "%B"), x[1]) for x in notifications] @@ -389,5 +389,11 @@ def get_financial_year(year): def get_april_fools(year): + """ + This function converts the start of the financial year April 1, 00:00 as BST (British Standard Time) to UTC, + the tzinfo is lastly removed from the datetime becasue the database stores the timestamps without timezone. + :param year: the year to calculate the April 1, 00:00 BST for + :return: the datetime of April 1 for the given year, for example 2016 = 2016-03-31 23:00:00 + """ return pytz.timezone('Europe/London').localize(datetime(year, 4, 1, 0, 0, 0)).astimezone(pytz.UTC).replace( tzinfo=None) diff --git a/tests/app/dao/test_notification_dao.py b/tests/app/dao/test_notification_dao.py index e686deca8..50777beb6 100644 --- a/tests/app/dao/test_notification_dao.py +++ b/tests/app/dao/test_notification_dao.py @@ -1209,4 +1209,6 @@ def test_get_financial_year(): def test_get_april_fools(): - assert str(get_april_fools(2016)) == '2016-03-31 23:00:00' + april_fools = get_april_fools(2016) + assert str(april_fools) == '2016-03-31 23:00:00' + assert april_fools.tzinfo is None