Как я могу посчитать воскресенья в текущем месяце?
Я сделал светодиодные настенные часы и календарь на основе 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