Определение ближайшего курса валюты по указанной дате

Найдите ближайшую запись не позже даты и ближайшую не раньше неё, затем сравните два расстояния. Индекс по datetime позволяет избежать сортировки всей таблицы по вычисляемой разнице.

Короткий ответ

Что ответить на собеседовании

Найдите ближайшую запись не позже даты и ближайшую не раньше неё, затем сравните два расстояния. Индекс по datetime позволяет избежать сортировки всей таблицы по вычисляемой разнице.

Подробный разбор

Ответ с пояснениями

Условие

Необходимо реализовать API‑endpoint, принимающий дату от клиента и возвращающий запись курса валюты, ближайшую к этой дате из таблицы CurrencyRate. Если в базе существует точное совпадение по полю datetime, его следует вернуть; если такого значения нет – выбрать запись с минимальной разницей во времени, независимо от того, находится она раньше или позже запрошенного момента.

class CurrencyRate(models.Model):
    rate = models.DecimalField(...)
    datetime = models.DateTimeField(...)
+--------+----------------------------+
| rate   | datetime                   |
+--------+----------------------------+
| 34.9   | 1999-05-21 15:44:12.983411 |
| 70.3   | 2022-12-20 08:30:16.123351 |
| 68.1   | 2023-01-09 10:13:30.431559 |
| 68.2   | 2023-01-10 10:00:12.123471 |
+--------+----------------------------+
import datetime as dt

def index(request):
    my_dt: dt.datetime = get_dt_from_request(request)
    ...

Ответ

Найдите ближайшую запись не позже даты и ближайшую не раньше неё, затем сравните два расстояния. Индекс по datetime позволяет избежать сортировки всей таблицы по вычисляемой разнице.

После валидации даты и согласования часового пояса:

from django.http import JsonResponse, Http404

def index(request):
    target = get_dt_from_request(request)
    before = CurrencyRate.objects.filter(datetime__lte=target).order_by('-datetime', 'pk').first()
    after = CurrencyRate.objects.filter(datetime__gte=target).order_by('datetime', 'pk').first()
    candidates = [item for item in (before, after) if item is not None]
    if not candidates:
        raise Http404('No rates')
    nearest = min(candidates, key=lambda item: (
        abs(item.datetime - target), item.datetime, item.pk
    ))
    return JsonResponse({'rate': str(nearest.rate), 'datetime': nearest.datetime.isoformat()})

При равенстве расстояний выбирается более ранняя запись. Для строгой согласованности двух чтений при конкурентных изменениях нужен общий snapshot либо единый SQL-запрос. Если валют несколько, обязательно добавьте фильтр валюты.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее