Как найти дату предыдущего понедельника в C ++ - PullRequest
3 голосов
/ 08 июня 2019

Я хочу создать программу, которая не принимает никаких данных и возвращает дату предыдущего понедельника. (Меня не волнуют часовые пояса. И меня беспокоит только григорианский календарь). Я использую дату от Говарда Хиннанта . Вот как я это делаю сейчас:

#include <iostream>
#include <date/date.h>

int main() {

    auto todays_day = date::year_month_weekday(date::floor<date::days>(std::chrono::system_clock::now()));

    auto todays_date = date::floor<date::days>(std::chrono::system_clock::now());

    int offset = 0;

    auto weekday = todays_day.weekday();

    if(weekday == date::Tuesday)
        offset = 1;
    else if (weekday == date::Wednesday)
        offset = 2;
    else if (weekday == date::Thursday)
        offset = 3;
    else if (weekday == date::Friday)
        offset = 4;
    else if (weekday == date::Saturday)
        offset = 5;
    else if (weekday == date::Sunday)
        offset = 6;

    auto lastMonday = date::year_month_day(todays_date - date::days(offset));

    std::cout << lastMonday;
}

Есть ли лучший способ сделать это без boost :: previous_weekday ? (Это не требование, чтобы не использовать повышение. Мне просто интересно, если это возможно)

1 Ответ

5 голосов
/ 08 июня 2019

Ключом к пониманию того, как сделать это проще, является знание этого факта о библиотеке дат Говарда Хиннанта :

weekday разница круговая (или по модулю 7, если вы предпочитаете). То есть любое weekday, вычитаемое из любого weekday, приводит к числу days в диапазоне [0, 6]. Это эффективно скрывает основную кодировку weekday.

Таким образом, нет необходимости переводить [понедельник, воскресенье] в [0, 6] (или любую другую кодировку):

#include "date/date.h"
#include <iostream>

int
main()
{
    auto todays_date = date::floor<date::days>(std::chrono::system_clock::now());
    date::year_month_day lastMonday = todays_date -
                                      (date::weekday{todays_date} - date::Monday);
    std::cout << lastMonday << '\n';
}

Вместо этого вам просто нужно решить, сколько дней вам нужно вычесть из sys_days (todays_date в этом примере). Это число дней сегодня weekday минус Monday. Если сегодня Monday, результат days{0}. Если сегодня Sunday, результат days{6}. С тем же успехом мы могли бы говорить о поиске предыдущей пятницы. Логика не изменится.

Также можно напрямую конвертировать sys_days в weekday. Не нужно идти, хотя year_month_weekday.

Код в вопросе OP считает «предыдущий понедельник» сегодняшним днем, если сегодня понедельник. И это нормально. Это то, что желательно во многих алгоритмах «предыдущего дня недели». И это логика, которую я кодировал выше.

Но также часто требуется, чтобы алгоритм предыдущего дня недели приводил к результату на прошлой неделе, если день недели, который вы ищете, сегодня. То есть если сегодня понедельник, вычислите неделю назад вместо сегодняшнего дня. Это тоже легко выполнимо, и почти по тому же алгоритму. Нужно только вычесть день в начале алгоритма, если вы хотите такое поведение:

auto todays_date = ...
todays_date -= date::days{1};
date::year_month_day lastMonday = ...
...