void substract_minute(struct tm * const time, bool checkflag) { if (--time->tm_min == -1) { /* DST flag transmitted until 00:59:16 UTC */ if ((((announce & ANN_CHDST) == ANN_CHDST) || !checkflag) && get_utchour(*time) == 1 && time->tm_wday == 7 && time->tm_mday > (int)(lastday(*time) - 7)) { /* logic is backwards here */ if (time->tm_isdst == 1 && time->tm_mon == (int)wintermonth) time->tm_hour++; /* will become DST */ if (time->tm_isdst == 0 && time->tm_mon == (int)summermonth) time->tm_hour--; /* will become non-DST */ } time->tm_min = 59; if (--time->tm_hour == -1) { time->tm_hour = 23; if (--time->tm_wday == 0) time->tm_wday = 7; if (--time->tm_mday == 0) { if (--time->tm_mon == 0) { time->tm_mon = 12; if (--time->tm_year == BASEYEAR - 1) time->tm_year = BASEYEAR + 399; /* bump! */ } time->tm_mday = (int)lastday(*time); } } } }
void add_minute(struct tm * const time, bool checkflag) { /* time->tm_isdst indicates the old situation */ if (++time->tm_min == 60) { /* DST flag transmitted until 00:59:16 UTC */ if ((((announce & ANN_CHDST) == ANN_CHDST) || !checkflag) && get_utchour(*time) == 0 && time->tm_wday == 7 && time->tm_mday > (int)(lastday(*time) - 7)) { if (time->tm_isdst == 1 && time->tm_mon == (int)wintermonth) time->tm_hour--; /* will become non-DST */ if (time->tm_isdst == 0 && time->tm_mon == (int)summermonth) time->tm_hour++; /* will become DST */ } time->tm_min = 0; if (++time->tm_hour == 24) { time->tm_hour = 0; if (++time->tm_wday == 8) time->tm_wday = 1; time->tm_mday++; if (time->tm_mday > (int)lastday(*time)) { time->tm_mday = 1; if (++time->tm_mon == 13) { time->tm_mon = 1; if (++time->tm_year == BASEYEAR + 400) time->tm_year = BASEYEAR; /* bump! */ } } } } }
void TestCase4_How2UseCopyConstructor(void) { #if defined (COPY_CONSTRUCTOR) // 1st Date object Date birthday(1983, 1, 2); birthday.display(); // 2nd Date object Date newday = birthday; newday.display(); // 3rd Date object Date lastday(birthday); lastday.display(); return; #endif /* COPY_CONSTRUCTOR */ }
uint32_t decode_time(uint8_t init_min, uint8_t minlen, uint32_t acc_minlen, const uint8_t * const buffer, struct tm * const time) { struct tm newtime; uint32_t rval = 0; int16_t increase, i; uint8_t tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, utchour; int8_t centofs; bool generr, p1, p2, p3, ok; static uint32_t acc_minlen_partial, old_acc_minlen; static bool olderr, prev_toolong; memset(&newtime, 0, sizeof(newtime)); /* Initially, set time offset to unknown */ if (init_min == 2) time->tm_isdst = -1; newtime.tm_isdst = time->tm_isdst; /* save DST value */ if (minlen < 59) rval |= DT_SHORT; if (minlen > 60) rval |= DT_LONG; if (buffer[0] == 1) rval |= DT_B0; if (buffer[20] == 0) rval |= DT_B20; if (buffer[17] == buffer[18]) rval |= DT_DSTERR; generr = (rval != 0); /* do not decode if set */ if (buffer[15] == 1) rval |= DT_XMIT; /* See if there are any partial / split minutes to be combined: */ if (acc_minlen <= 59000) { acc_minlen_partial += acc_minlen; if (acc_minlen_partial >= 60000) { acc_minlen = acc_minlen_partial; acc_minlen_partial %= 60000; } } /* Calculate number of minutes to increase time with: */ if (prev_toolong) increase = (int16_t)((acc_minlen - old_acc_minlen) / 60000); else increase = (int16_t)(acc_minlen / 60000); if (acc_minlen >= 60000) acc_minlen_partial %= 60000; /* Account for complete minutes with a short acc_minlen: */ if (acc_minlen % 60000 > 59000) { increase++; acc_minlen_partial %= 60000; } prev_toolong = (minlen == 0xff); old_acc_minlen = acc_minlen - (acc_minlen % 60000); /* There is no previous time on the very first (partial) minute: */ if (init_min < 2) { for (i = increase; increase > 0 && i > 0; i--) add_minute(time, true); for (i = increase; increase < 0 && i < 0; i++) substract_minute(time, false); } p1 = getpar(buffer, 21, 28); tmp0 = getbcd(buffer, 21, 24); tmp1 = getbcd(buffer, 25, 27); if (!p1 || tmp0 > 9 || tmp1 > 5) { rval |= DT_MIN; p1 = false; } if ((init_min == 2 || increase != 0) && p1 && !generr) { newtime.tm_min = (int)(tmp0 + 10 * tmp1); if (init_min == 0 && time->tm_min != newtime.tm_min) rval |= DT_MINJUMP; } p2 = getpar(buffer, 29, 35); tmp0 = getbcd(buffer, 29, 32); tmp1 = getbcd(buffer, 33, 34); if (!p2 || tmp0 > 9 || tmp1 > 2 || tmp0 + 10 * tmp1 > 23) { rval |= DT_HOUR; p2 = false; } if ((init_min == 2 || increase != 0) && p2 && !generr) { newtime.tm_hour = (int)(tmp0 + 10 * tmp1); if (init_min == 0 && time->tm_hour != newtime.tm_hour) rval |= DT_HOURJUMP; } p3 = getpar(buffer, 36, 58); tmp0 = getbcd(buffer, 36, 39); tmp1 = getbcd(buffer, 40, 41); tmp2 = getbcd(buffer, 42, 44); tmp3 = getbcd(buffer, 45, 48); tmp4 = getbcd(buffer, 50, 53); tmp5 = getbcd(buffer, 54, 57); if (!p3 || tmp0 > 9 || tmp0 + 10 * tmp1 == 0 || tmp0 + 10 * tmp1 > 31 || tmp2 == 0 || tmp3 > 9 || tmp3 + 10 * buffer[49] == 0 || tmp3 + 10 * buffer[49] > 12 || tmp4 > 9 || tmp5 > 9) { rval |= DT_DATE; p3 = false; } if ((init_min == 2 || increase != 0) && p3 && !generr) { newtime.tm_mday = (int)(tmp0 + 10 * tmp1); newtime.tm_mon = (int)(tmp3 + 10 * buffer[49]); newtime.tm_year = (int)(tmp4 + 10 * tmp5); newtime.tm_wday = (int)tmp2; if (init_min == 0 && time->tm_mday != newtime.tm_mday) rval |= DT_MDAYJUMP; if (init_min == 0 && time->tm_wday != newtime.tm_wday) rval |= DT_WDAYJUMP; if (init_min == 0 && time->tm_mon != newtime.tm_mon) rval |= DT_MONTHJUMP; centofs = century_offset(newtime); if (centofs == -1) { rval |= DT_DATE; p3 = false; } else { if (init_min == 0 && time->tm_year != (int)(BASEYEAR + 100 * centofs + newtime.tm_year)) rval |= DT_YEARJUMP; newtime.tm_year += BASEYEAR + 100 * centofs; if (newtime.tm_mday > (int)lastday(newtime)) { rval |= DT_DATE; p3 = false; } } } ok = !generr && p1 && p2 && p3; /* shorthand */ utchour = get_utchour(*time); /* * h==23, last day of month (UTC) or h==0, first day of next month (UTC) * according to IERS Bulletin C * flag still set at 00:00 UTC, prevent DT_LEAPERR */ if (buffer[19] == 1 && ok) { if (time->tm_mday == 1 && is_leapsecmonth(*time) && ((time->tm_min > 0 && utchour == 23) || (time->tm_min == 0 && utchour == 0))) announce |= ANN_LEAP; else { announce &= ~ANN_LEAP; rval |= DT_LEAPERR; } } /* process possible leap second, always reset announcement at hh:00 */ if (((announce & ANN_LEAP) == ANN_LEAP) && time->tm_min == 0) { announce &= ~ANN_LEAP; rval |= DT_LEAP; if (minlen == 59) { /* leap second processed, but missing */ rval |= DT_SHORT; ok = false; generr = true; } else if (minlen == 60 && buffer[59] == 1) rval |= DT_LEAPONE; } if ((minlen == 60) && ((rval & DT_LEAP) == 0)) { /* leap second not processed, so bad minute */ rval |= DT_LONG; ok = false; generr = true; } /* h==0 (UTC) because sz->wz -> h==2 and wz->sz -> h==1, * last Sunday of month (reference?) */ if (buffer[16] == 1 && ok) { if ((time->tm_wday == 7 && time->tm_mday > (int)(lastday(*time) - 7) && (time->tm_mon == (int)summermonth || time->tm_mon == (int)wintermonth)) && ((time->tm_min > 0 && utchour == 0) || (time->tm_min == 0 && utchour == 1 + buffer[17] - buffer[18]))) announce |= ANN_CHDST; /* time zone just changed */ else { announce &= ~ANN_CHDST; rval |= DT_CHDSTERR; } } if ((int)buffer[17] != time->tm_isdst || (int)buffer[18] == time->tm_isdst) { /* Time offset change is OK if: * announced and time is Sunday, lastday, 01:00 UTC * there was an error but not any more (needed if decoding at * startup is problematic) * initial state (otherwise DST would never be valid) */ if ((((announce & ANN_CHDST) == ANN_CHDST) && time->tm_min == 0) || (olderr && ok) || ((rval & DT_DSTERR) == 0 && time->tm_isdst == -1)) newtime.tm_isdst = (int)buffer[17]; /* expected change */ else { if ((rval & DT_DSTERR) == 0) rval |= DT_DSTJUMP; /* sudden change, ignore */ ok = false; } } /* check if DST is within expected date range */ if ((time->tm_mon > (int)summermonth && time->tm_mon < (int)wintermonth) || (time->tm_mon == (int)summermonth && time->tm_wday < 7 && (int)(lastday(*time)) - time->tm_mday < 7) || (time->tm_mon == (int)summermonth && time->tm_wday == 7 && (int)(lastday(*time)) - time->tm_mday < 7 && utchour > 0) || (time->tm_mon == (int)wintermonth && time->tm_wday < 7 && (int)(lastday(*time)) - time->tm_mday >= 7) || (time->tm_mon == (int)wintermonth && time->tm_wday == 7 && (int)(lastday(*time)) - time->tm_mday < 7 && (utchour >= 22 /* previous day */ || utchour == 0))) { /* expect DST */ if (newtime.tm_isdst == 0 && (announce & ANN_CHDST) == 0 && utchour < 24) { rval |= DT_DSTJUMP; /* sudden change */ ok = false; } } else { /* expect non-DST */ if (newtime.tm_isdst == 1 && (announce & ANN_CHDST) == 0 && utchour < 24) { rval |= DT_DSTJUMP; /* sudden change */ ok = false; } } /* done with DST */ if (((announce & ANN_CHDST) == ANN_CHDST) && time->tm_min == 0) { announce &= ~ANN_CHDST; rval |= DT_CHDST; } newtime.tm_gmtoff = 3600 * (newtime.tm_isdst + 1); if (olderr && ok) olderr = false; if (!generr) { if (p1) time->tm_min = newtime.tm_min; if (p2) time->tm_hour = newtime.tm_hour; if (p3) { time->tm_mday = newtime.tm_mday; time->tm_mon = newtime.tm_mon; time->tm_year = newtime.tm_year; time->tm_wday = newtime.tm_wday; } if ((rval & DT_DSTJUMP) == 0) { time->tm_isdst = newtime.tm_isdst; time->tm_gmtoff = newtime.tm_gmtoff; } } if (!ok) olderr = true; return rval | announce; }