mirror of
https://github.com/GSA/notifications-api.git
synced 2026-02-03 18:01:08 -05:00
Standardise how we query midnight-to-midnight
Partially addresses [1] (lots more detail to read in the comment). I've also added some tests for the status DAO function to confirm it behaves as expected across timezones. [1]: https://github.com/alphagov/notifications-api/pull/3437#discussion_r802634913
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
from datetime import date, datetime, time, timedelta
|
from datetime import date, datetime, timedelta
|
||||||
|
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from notifications_utils.timezones import convert_bst_to_utc, convert_utc_to_bst
|
from notifications_utils.timezones import convert_utc_to_bst
|
||||||
from sqlalchemy import Date, Integer, and_, desc, func
|
from sqlalchemy import Date, Integer, and_, desc, func
|
||||||
from sqlalchemy.dialects.postgresql import insert
|
from sqlalchemy.dialects.postgresql import insert
|
||||||
from sqlalchemy.sql.expression import case, literal
|
from sqlalchemy.sql.expression import case, literal
|
||||||
@@ -317,8 +317,8 @@ def delete_billing_data_for_service_for_day(process_day, service_id):
|
|||||||
|
|
||||||
|
|
||||||
def fetch_billing_data_for_day(process_day, service_id=None, check_permissions=False):
|
def fetch_billing_data_for_day(process_day, service_id=None, check_permissions=False):
|
||||||
start_date = convert_bst_to_utc(datetime.combine(process_day, time.min))
|
start_date = get_london_midnight_in_utc(process_day)
|
||||||
end_date = convert_bst_to_utc(datetime.combine(process_day + timedelta(days=1), time.min))
|
end_date = get_london_midnight_in_utc(process_day + timedelta(days=1))
|
||||||
current_app.logger.info("Populate ft_billing for {} to {}".format(start_date, end_date))
|
current_app.logger.info("Populate ft_billing for {} to {}".format(start_date, end_date))
|
||||||
transit_data = []
|
transit_data = []
|
||||||
if not service_id:
|
if not service_id:
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
from datetime import datetime, time, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from notifications_utils.timezones import convert_bst_to_utc
|
|
||||||
from sqlalchemy import Date, case, func
|
from sqlalchemy import Date, case, func
|
||||||
from sqlalchemy.dialects.postgresql import insert
|
from sqlalchemy.dialects.postgresql import insert
|
||||||
from sqlalchemy.sql.expression import extract, literal
|
from sqlalchemy.sql.expression import extract, literal
|
||||||
@@ -36,8 +35,8 @@ from app.utils import (
|
|||||||
|
|
||||||
|
|
||||||
def fetch_status_data_for_service_and_day(process_day, service_id, notification_type):
|
def fetch_status_data_for_service_and_day(process_day, service_id, notification_type):
|
||||||
start_date = convert_bst_to_utc(datetime.combine(process_day, time.min))
|
start_date = get_london_midnight_in_utc(process_day)
|
||||||
end_date = convert_bst_to_utc(datetime.combine(process_day + timedelta(days=1), time.min))
|
end_date = get_london_midnight_in_utc(process_day + timedelta(days=1))
|
||||||
|
|
||||||
# query notifications or notification_history for the day, depending on their data retention
|
# query notifications or notification_history for the day, depending on their data retention
|
||||||
service = Service.query.get(service_id)
|
service = Service.query.get(service_id)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from notifications_utils.template import (
|
|||||||
LetterPrintTemplate,
|
LetterPrintTemplate,
|
||||||
SMSMessageTemplate,
|
SMSMessageTemplate,
|
||||||
)
|
)
|
||||||
from notifications_utils.timezones import convert_utc_to_bst
|
from notifications_utils.timezones import convert_bst_to_utc, convert_utc_to_bst
|
||||||
from sqlalchemy import func
|
from sqlalchemy import func
|
||||||
|
|
||||||
DATETIME_FORMAT_NO_TIMEZONE = "%Y-%m-%d %H:%M:%S.%f"
|
DATETIME_FORMAT_NO_TIMEZONE = "%Y-%m-%d %H:%M:%S.%f"
|
||||||
@@ -64,9 +64,7 @@ def get_london_midnight_in_utc(date):
|
|||||||
:param date: the day to calculate the London midnight in UTC for
|
:param date: the day to calculate the London midnight in UTC for
|
||||||
:return: the datetime of London midnight in UTC, for example 2016-06-17 = 2016-06-16 23:00:00
|
:return: the datetime of London midnight in UTC, for example 2016-06-17 = 2016-06-16 23:00:00
|
||||||
"""
|
"""
|
||||||
return local_timezone.localize(datetime.combine(date, datetime.min.time())).astimezone(
|
return convert_bst_to_utc(datetime.combine(date, datetime.min.time()))
|
||||||
pytz.UTC).replace(
|
|
||||||
tzinfo=None)
|
|
||||||
|
|
||||||
|
|
||||||
def get_midnight_for_day_before(date):
|
def get_midnight_for_day_before(date):
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ from app.dao.fact_notification_status_dao import (
|
|||||||
fetch_notification_status_totals_for_all_services,
|
fetch_notification_status_totals_for_all_services,
|
||||||
fetch_notification_statuses_for_job,
|
fetch_notification_statuses_for_job,
|
||||||
fetch_stats_for_all_services_by_date_range,
|
fetch_stats_for_all_services_by_date_range,
|
||||||
|
fetch_status_data_for_service_and_day,
|
||||||
get_total_notifications_for_date_range,
|
get_total_notifications_for_date_range,
|
||||||
)
|
)
|
||||||
from app.models import (
|
from app.models import (
|
||||||
@@ -607,3 +608,23 @@ def test_get_total_notifications_for_date_range(sample_service):
|
|||||||
|
|
||||||
assert len(results) == 1
|
assert len(results) == 1
|
||||||
assert results[0] == ("2021-03-01", 15, 20, 3)
|
assert results[0] == ("2021-03-01", 15, 20, 3)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('created_at_utc,process_day,expected_count', [
|
||||||
|
# Clocks change on the 27th of March 2022, so the query needs to look at the
|
||||||
|
# time range 00:00 - 23:00 (UTC) thereafter.
|
||||||
|
('2022-03-27T00:30', date(2022, 3, 27), 1), # 27/03 00:30 GMT
|
||||||
|
('2022-03-27T22:30', date(2022, 3, 27), 1), # 27/03 23:30 BST
|
||||||
|
('2022-03-27T23:30', date(2022, 3, 27), 0), # 28/03 00:30 BST
|
||||||
|
('2022-03-26T23:30', date(2022, 3, 26), 1), # 26/03 23:30 GMT
|
||||||
|
])
|
||||||
|
def test_fetch_status_data_for_service_and_day_respects_gmt_bst(
|
||||||
|
sample_template,
|
||||||
|
sample_service,
|
||||||
|
created_at_utc,
|
||||||
|
process_day,
|
||||||
|
expected_count,
|
||||||
|
):
|
||||||
|
create_notification(template=sample_template, created_at=created_at_utc)
|
||||||
|
rows = fetch_status_data_for_service_and_day(process_day, sample_service.id, SMS_TYPE)
|
||||||
|
assert len(rows) == expected_count
|
||||||
|
|||||||
Reference in New Issue
Block a user