Есть массив в котором лежат объекты с датами, необходимо отсортировать даты по убыванию

Дан массив:

const dates = [
  { date: "10.01.2017" },
  { date: "05.11.2016" },
  { date: "21.13.2002" },
]

Необходимо отсортировать массив по убыванию дат.

Примеры:

sortDates([
    {"date": "05.11.2016"},
    {"date": "21.13.2002"},
    {"date": "10.01.2017"},
]) --> [
    {"date": "10.01.2017"},
    {"date": "05.11.2016"},
    {"date": "21.01.2003"}
]
sortDates([
    {"date": "10.01.1997"},
    {"date": "05.11.1981"},
    {"date": "21.13.2004"}
]) --> [
    {"date": "21.01.2005"},
    {"date": "10.01.1997"},
    {"date": "05.11.1981"}
]

Теория: как решается задача по шагам

Почему нельзя сортировать строки напрямую

Строка "dd.mm.yyyy" при обычной сортировке строк сравнивает символы слева направо, поэтому лексикографический порядок не совпадает с хронологическим порядком дат.

Корректная сортировка требует привести дату либо к числу (timestamp), либо к строке формата, где порядок символов соответствует времени (например, "yyyy-mm-dd").

Почему нужен ручной разбор "dd.mm.yyyy"

Парсинг не-ISO форматов строк не гарантирован одинаково во всех реализациях, поэтому надежнее выделить dd, mm, yyyy регулярным выражением и преобразовать в числа.

Регулярное выражение ^(\d{2})\.(\d{2})\.(\d{4})$ гарантирует строго нужный формат, что упрощает обработку ошибок.

Нормализация переполнений в Date

При создании даты из числовых компонентов переполненные значения обычно “переносятся” (carry/borrow): лишние месяцы увеличивают год, значение дня 0 дает последний день предыдущего месяца, отрицательные значения уменьшают старшие компоненты.

Это позволяет преобразовать "21.13.2002" в "21.01.2003" без ручных вычислений: 13-й месяц становится январем следующего года при переносе.

Почему выбран UTC (а не local time)

Если создать дату как local time и затем форматировать ее, результат может зависеть от часового пояса и переходов на летнее/зимнее время, что иногда приводит к “сдвигам” при преобразованиях.

Для “чистых календарных дат” (без времени) стабильнее придерживаться UTC: создание через Date.UTC и форматирование через getUTC*.

Схема преобразования

  • Вход: "dd.mm.yyyy".
  • Шаг 1: выделение dd, mm, yyyy (regex).
  • Шаг 2: построение UTC-даты new Date(Date.UTC(yyyy, mm - 1, dd)) (автонормализация).
  • Шаг 3: число для сортировки: time = date.getTime().
  • Шаг 4: сортировка по убыванию time.
  • Шаг 5: форматирование результата в "dd.mm.yyyy" через getUTC* и padStart(2, "0").

Таблица: частые ошибки и решения

ОшибкаПочему плохоКак правильно
new Date("10.01.2017")Нестандартный формат, возможны различия интерпретацииРазбирать dd/mm/yyyy вручную и создавать дату из чисел
Месяц передается как 1..12 в конструктор из компонентовВ Date месяц обычно 0..11Использовать month - 1
Форматирование через local gettersВозможна зависимость от часового поясаДля “календарных дат” использовать getUTC*
Потеря ведущих нулей"5.1.2017" не соответствует требуемому видуИспользовать padStart(2, "0")

Кратко: необходимо разобрать "dd.mm.yyyy" на числа, создать дату через Date.UTC (что автоматически нормализует 13-й месяц), отсортировать по getTime() по убыванию и отформатировать обратно через UTC-геттеры с ведущими нулями.