Как я могу посчитать воскресенья в текущем месяце?

Я сделал светодиодные настенные часы и календарь на основе Arduino некоторое время назад, и теперь я хочу изменить их, чтобы добавить переменную для автоматической настройки смещения для летнего времени. Я уже опрашиваю интернет-сервер времени 2 раза в день, чтобы гарантировать точность, но серверы времени обычно не предоставляют информацию о летнем времени. Изменение происходит во второе воскресенье марта и первое воскресенье ноября. ( https://www.nist.gov/pml/time-and-frequency-division/popular-links/daylight-saving-time-dst) По сути, мне нужно знать, когда наступает второе воскресенье марта, и сообщить об этом отрегулируйте смещение часового пояса на +1, затем на -1 в первое воскресенье ноября. Я просто не уверен, как это реализовать.

Я думаю что-то вроде:

если месяц == 3 или 11 И если день недели == 1; затем воскресенье + 1; иначе воскресенье = 0;

если воскресенье == 2; И месяц == 3; тогда isDST = TRUE;

если воскресенье == 1; И месяц == 11; тогда isDST = FALSE;

Я надеюсь, что это достаточно хороший пример того, что я хочу сделать. Я ненавижу использовать так много вложенных if, но это лучшее, что я могу придумать, оставаясь относительным новичком. Будет ли это даже работать или есть лучший способ сделать это? Любая помощь с этим будет принята с благодарностью.

2 ответа

Вот статья с календарными алгоритмами, которую можно использовать для вычисления таких вещей, как 2-е воскресенье марта. См. Пример: Поиск n-го дня недели месяца.

Если у вас есть C++11, вы можете использовать эту бесплатную библиотеку дат с открытым исходным кодом, чтобы вычислять такие вещи с использованием синтаксиса очень высокого уровня. Библиотека использует алгоритмы из бумаги под капотом. Например:

std::chrono::system_clock::time_point
DST_US(std::chrono::system_clock::time_point tp, std::chrono::hours std_offset)
{
    using namespace date;
    using namespace std::chrono;
    const auto y = year_month_day{floor<days>(tp)}.year();
    const auto begin = sys_days{sun[2]/mar/y} + 2h - std_offset; // DT begins at this UTC time
    const auto end   = sys_days{sun[1]/nov/y} + 1h - std_offset; // ST begins at this UTC time
    if (tp < begin || end <= tp)
        return tp + std_offset;
    return tp + std_offset + 1h;
}

Не стесняйтесь использовать библиотеку datetime, если у вас есть C++11 (она переносимая), и в противном случае создавать свои собственные, используя алгоритмы, описанные в статье.

Отказ от ответственности: правила часовых поясов все время меняются. Вышесказанного вполне достаточно для самодельных часов. Для промышленных приложений, нуждающихся в современных правилах часовых поясов, используйте библиотеку на основе базы данных часовых поясов IANA, такую ​​как эта.

Здесь я сделал код C++ для вас. Вам не нужен C++11 для запуска этого.

Как это работает, он получает текущий месяц и год. Проверяет, является ли год високосным, затем устанавливает максимальное количество дней. Допустим, 2017 год август. Максимальный день будет 31.

Программа начинает работать и считает sundayCounter вверх, если день поражения воскресенье.

Таким образом, вы получите количество воскресений в текущем месяце автоматически.

Вот мой код, не стесняйтесь использовать его. Это именно то, что вы хотите сделать. Ваша желаемая переменная sundayCounter, Повеселись.

#include <iostream>
#include <ctime>
using namespace std;

int main()
{
    bool isLeap = false;
    int sundayCounter = 0;
    int MAX_DAY;
    int month, year;
    string monthText;

    time_t theTime = time(NULL);
    struct tm *aTime = localtime(&theTime);
    month = aTime->tm_mon;
    year = aTime->tm_year;

    if (year % 4 == 0)
        {;
            if (year % 100 == 0)
            {
                if (year % 400 == 0)
                    isLeap = true;
                else
                    isLeap = false;
            }
            else
                isLeap = true;
        }
    else {
        isLeap = false;
    }

    switch(month)
    {
    case 0:
        MAX_DAY = 31;
        break;
    case 1:
        if(isLeap)
            MAX_DAY = 29;
        else
            MAX_DAY = 28;
        break;
    case 2:
        MAX_DAY = 31;
        break;
    case 3:
        MAX_DAY = 30;
        break;
    case 4:
        MAX_DAY = 31;
        break;
    case 5:
        MAX_DAY = 30;
        break;
    case 6:
        MAX_DAY = 31;
        break;
    case 7:
        MAX_DAY = 31;
        break;
    case 8:
        MAX_DAY = 30;
        break;
    case 9:
        MAX_DAY = 31;
        break;
    case 10:
        MAX_DAY = 30;
        break;
    case 11:
        MAX_DAY = 31;
        break;
    }

    for(int day = 0; day <= MAX_DAY; day++) {
        struct tm time_in = { 0, 0, 0, // second, minute, hour
                day, month + 1, year - 1900 }; // 1-based day, 0-based month, year since 1900

        time_t time_temp = mktime( & time_in );

        // the return value from localtime is a static global - do not call
        // this function from more than one thread!
        tm const *time_out = localtime( & time_temp );

        switch(time_out->tm_wday)
        {
        case 0:
            sundayCounter++;
            break;
        }
    }

    const char* month_list[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
    int current_month = month+1;
    const char* current_month_name = month_list[current_month-1];
    cout << "Sunday amount in " << current_month_name << " " << (year + 1900) << ": " << sundayCounter;
    cout << endl;
    return 0;
}

Выход:

Sunday amount in August 2017: 4
Другие вопросы по тегам