Before calling mktime()
all fields, except tm_yday
and tm_wday
need to be set. Obviously we need to set tm_mon
and tm_mday
for Jan 1.
Important to set the tm_hour
to midday (12) and/or tm_isdst
to -1 to insure the recalculated time is not impacted by daylight saving time. Consider what would happen if the current time was near midnight and the DST setting for now was different than Jan 1. The re-calculation could push time out of Jan 1 to Jan 2 or Dec 31.
int getFirstSunday(void) {
time_t rawtime;
struct tm * timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
timeinfo->tm_mon = 0; // set to January which is 0 "Months since January"
timeinfo->tm_mday = 1; // Set to the 1st of the month
timeinfo->tm_hour = 12; // Set to avoid getting the wrong DST setting for Jan 1.
timeinfo->tm_isdst = -1; // Set to avoid getting the wrong DST setting for Jan 1.
if (mktime(timeinfo) == -1) return -1;
int DaysSinceSundayForJan1 = timeinfo->tm_wday; // days since Sunday — [0, 6]
int DaysAfterJan1toNextSunday = 7 - DaysSinceSundayForJan1;
int DaysAfterJan1toFirstSunday = DaysAfterJan1toNextSunday%7;
// Convert to "day of the month"
return DaysAfterJan1toFirstSunday + 1;
}