Вопрос по date, c++ – Как получить первую и последнюю даты (день и месяц) указанного номера недели (1-53) в конкретном году?

2

Если указан номер недели в определенном году, как я могу легко определить первые и последние даты (день и месяц) недели с помощью C / C ++? Заранее спасибо!

подветренный

Если вы не покажете, приложили ли вы какие-либо усилия с вашей стороны, люди собираются понизить ваш вопрос! DumbCoder
Идти вперед или назад во времени? И где? В регионе, где я живу, у нас были номера недель, аналогичные модели в США, но теперь они меняются на стандартные номера недель ISO. Bo Persson
Я знаю, что первая неделя данного года может включать в себя последние или более одного дня предыдущего года. И мы, как правило, идем вперед во времени. Я бы лучше использовал стандартное недельное соглашение о нумерации ISO. Спасибо всем за внимание к моему вопросу. GoldenLee
Возможно, вам нужно быть более точным. Существуют разные типы стандартов нумерации недель. Вы должны знать, какой вы хотите. Прошло так много времени с тех пор, как я делал C, я не могу вспомнить, как он работает с датами. Нет ли в конструкции формата чего-то, что позволяло бы вытащить разные маски даты (like in PHP:) cartbeforehorse

Ваш Ответ

2   ответа
2

Этот ответ включает код, который был предложен для стандартизации и отклонен. Причина, по которой я упоминаю, состоит в том, что код находится в пространстве именstd::chrono для целей предложения. Но важно понимать, что это предложение не было принято, и поэтому, если вы его используете, вам, вероятно, следует переместить предложенные части в ваше собственное пространство имен. Они не являются частью какого-либо стандарта и даже не рассматриваются для стандартизации!

Вотпользовательская документация для моего класса даты что делает это вычисление довольно простым (при условии стандартной нумерации по ISO). Документация указывает на один заголовок<date> и один источникdate.cpp который реализует предложение.

Используя эти источники и две очень короткие вспомогательные функции, показанные ниже, вот программа, которая берет номер недели и год и распечатывает первые (понедельник) и последние (воскресенье) дни этой недели в гражданском (григорианском) календаре:

#include "date"
#include <utility>
#include <iostream>

std::chrono::date
week_to_date(int weeknum, std::chrono::weekday wd, std::chrono::year y)
{
    using namespace std::chrono;
    return (mon <= jan/_4th/y) + days((weeknum - 1)*7 + (wd == 0 ? 6 : wd - 1));
}

std::pair<std::chrono::date, std::chrono::date>
get_dates(unsigned week_num, unsigned y)
{
    using namespace std::chrono;
    return std::make_pair(week_to_date(week_num, mon, year(y)),
                          week_to_date(week_num, sun, year(y)));
}

int main()
{
    auto p = get_dates(9, 2013);
    std::cout << p.first << '\n';
    std::cout << p.second << '\n';
}

Для меня это распечатывает:

2013-02-25
2013-03-03

Заявление о возврате вweek_to_date Можно использовать небольшое объяснение:

(mon <= jan/_4th/y)

Вышеупомянутое выражение создает дату, которая является понедельником 4 января или раньше года y. Затем я добавляю 7 дней для каждой недели доweeknum к этой дате:

+ days((weeknum - 1)*7

И наконец, если день недели (wd) это воскресенье, я добавляю 6 дней, еще я добавляюwd-1 дни, когда дни нумеруются с понедельника == 1, вторника == 2, до субботы == 6 (воскресенье == 0).

+ (wd == 0 ? 6 : wd - 1))

Этот последний шаг - то, что принимает во внимание, что недельная календарная неделя ISO начинается в понедельник, тогда как эта реализация класса даты следует соглашению C / C ++ недели, начинающейся в воскресенье.

предложение на самом деле включает в себя определениеweek_to_date и недельный год ИСО, хотя они указаны в предложении просто как примеры того, как работать с классом дат, и не являются частью предложения.

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

Update

Ссылки на этот ответ устарели, и я обновил их. Однако в дополнение к обновлению ссылок я хотел бы обратить внимание на редизайн библиотеки, указанной выше. Редизайн по-новому сфокусирован на эффективности, включая вычисления даты во время компиляции, когда все входные данные известны во время компиляции.

Это "константы даты" теперь реальны, учитывая поддержку C ++ 14.

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

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

constexpr
date::year_month_day
week_to_date(int weeknum, date::weekday wd, date::year y)
{
    using namespace date;
    auto const dp = sys_days(jan/4/y);
    auto const wdjan4 = weekday(dp);
    return dp - (wdjan4 - mon)
       + days((weeknum - 1)*7 + (wd == sun ? 6 : static_cast<unsigned>(wd) - 1));
}

constexpr
std::pair<date::year_month_day, date::year_month_day>
get_dates(int week_num, date::year y)
{
    using namespace date;
    return std::make_pair(week_to_date(week_num, mon, y),
                          week_to_date(week_num, sun, y));
}

int
main()
{
    using namespace date;
    constexpr auto p = get_dates(9, 2013_y);
    static_assert(p.first == feb/25/2013, "");
    static_assert(p.second == 2013_y/mar/3, "");
    std::cout << p.first << '\n';
    std::cout << p.second << '\n';
}

Два основных различия заключаются в том, что (в C ++ 14) вычисления могут быть сделаныconstexpr, Иoperator<= больше не доступен для поиска даты с рабочим днем, равным или предшествующим дате. Вместо этого эта функция обрабатывается «вычитанием дня недели», которое всегда приводит к положительному числу (сколько дней требуется, чтобы перейти от дня недели1 до дня недели2?).

Эта программа выводит то же, что и предыдущая версия:

2013-02-25
2013-03-03

Большая разница в том, что константы времени компиляции выводятся вstd::cout, Но тот же код (минусstatic_asserts) прекрасно работает с входными данными во время выполнения.

And the beat goes on

Объединение библиотеки, представленной выше, с новым и совместимым"iso_week.h" библиотека, синтаксис для вышеупомянутых вычислений значительно упрощен:

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

int
main()
{
    using namespace iso_week::literals;
    auto y = 2013_y;
    auto wn = 9_w;
    std::cout << "The dates for " << y/wn << " are "
              << date::year_month_day{y/wn/mon} << " through "
              << date::year_month_day{y/wn/sun} << '\n';
}

какие выводы:

The dates for 2013-W09 are 2013-02-25 through 2013-03-03
Спасибо за обновление.
1

райней мере два общих правила для того, какой день недели является началом недели, есть три общих правила для того, какая неделя имеет номер 1 в начале года.

Избегайте бесконечно возиться с таким кодом и использовать библиотеку. Библиотека ICU покрывает это своими классами Календаря. Соответствующая страница введенияэто здесь, Проверьте заметки в поле WEEK_OF_YEAR внизу страницы.

Хмя, типичный ISO продукт. Это не стандарт, это компромисс, который делает всех одинаково несчастными.
Я не понимаю. WP описывает это какan international standard [...], Так что еслиthat не является стандартом, тогда что?
This is heavily affected by local rules for week numberin Нет,ISO 8601 довольно ясно о недельной нумерации. Если, увы, ваш пользователь не использует его.

Похожие вопросы