static void days_since_epoch_into_ymd( uint32_t days, uint16_t * pYear, uint8_t * pMonth, uint8_t * pDay) { uint16_t year = 1900; uint8_t month = 1; uint8_t day = 1; while (days >= 365) { if ((is_leap_year(year)) && (days == 365)) break; days -= 365; if (is_leap_year(year)) --days; year++; } while (days >= (uint32_t) month_days(year, month)) { days -= month_days(year, month); month++; } day = (uint8_t) (day + days); if (pYear) *pYear = year; if (pMonth) *pMonth = month; if (pDay) *pDay = day; return; }
/* * add @n months to date */ Date& Date::add_month(int n) { if (n) { int mm; int yy; yy = n / 12; mm = m + n % 12; // left n add m great than 12 if (mm > 12) { yy++; mm -= 12; } // month first m = Month(mm); if (d > month_days(m, y)) d = month_days(m, y); add_year(yy); cache->valid = false; } return *this; }
/* Adjust time T by adding SECONDS. The absolute value of SECONDS cannot exceed 59 * INT_MAX, and also cannot exceed one month's worth of seconds; this is enough to handle any POSIX or real-life daylight-saving offset. Adjust only T's year, mon, mday, hour, min and sec members; plus adjust wday if it is defined. */ void adjzone (register struct tm *t, long seconds) { int days = 0; /* This code can be off by a second if SECONDS is not a multiple of 60, if T is local time, and if a leap second happens during this minute. But this bug has never occurred, and most likely will not ever occur. Liberia, the last country for which SECONDS % 60 was nonzero, switched to UTC in May 1972; the first leap second was in June 1972. */ int leap_second = t->tm_sec == 60; long sec = seconds + (t->tm_sec - leap_second); if (sec < 0) { if ((t->tm_min -= (59 - sec) / 60) < 0 && (t->tm_hour -= (59 - t->tm_min) / 60) < 0) { days = - ((23 - t->tm_hour) / 24); if ((t->tm_mday += days) <= 0) { if (--t->tm_mon < 0) { --t->tm_year; t->tm_mon = 11; } t->tm_mday += month_days (t); } } } else { if (60 <= (t->tm_min += sec / 60) && (24 <= (t->tm_hour += t->tm_min / 60))) { days = t->tm_hour / 24; if (month_days (t) < (t->tm_mday += days)) { if (11 < ++t->tm_mon) { ++t->tm_year; t->tm_mon = 0; } t->tm_mday = 1; } } } if (TM_DEFINED (t->tm_wday)) t->tm_wday = MOD (t->tm_wday + days, 7); t->tm_hour = MOD (t->tm_hour, 24); t->tm_min = MOD (t->tm_min, 60); t->tm_sec = (int) MOD (sec, 60) + leap_second; }
unsigned date::day_in_year(unsigned y, unsigned m, unsigned d) { unsigned days = 0; for(unsigned i = 1; i < m; ++i) days += month_days(y, i); return days + d; }
date date::_m_sub(unsigned x) const { date d(*this); while(x) { if(d.value_.day <= x) { if(d.value_.month == 1) { d.value_.month = 12; -- d.value_.year; } else -- d.value_.month; d.value_.day = month_days(d.value_.year, d.value_.month); x -= d.value_.day; } else { d.value_.day -= x; break; } } return d; }
void testDateEpoch( Test * pTest) { uint32_t days = 0; uint16_t year = 0, test_year = 0; uint8_t month = 0, test_month = 0; uint8_t day = 0, test_day = 0; days = days_since_epoch(1900, 1, 1); ct_test(pTest, days == 0); days_since_epoch_into_ymd(days, &year, &month, &day); ct_test(pTest, year == 1900); ct_test(pTest, month == 1); ct_test(pTest, day == 1); for (year = 1900; year <= 2154; year++) { for (month = 1; month <= 12; month++) { for (day = 1; day <= month_days(year, month); day++) { days = days_since_epoch(year, month, day); days_since_epoch_into_ymd(days, &test_year, &test_month, &test_day); ct_test(pTest, year == test_year); ct_test(pTest, month == test_month); ct_test(pTest, day == test_day); } } } }
date date::_m_add(unsigned x) const { date d(*this); while(x) { unsigned off = month_days(d.value_.year, d.value_.month) - d.value_.day; if(off < x) { d.value_.day = 1; if(d.value_.month == 12) { d.value_.month = 1; ++ d.value_.year; } else ++ d.value_.month; x -= (off + 1); } else if(off >= x) { d.value_.day += x; break; } } return d; }
/* * add @n year to date */ Date& Date::add_year(int n) { if (n) { int yy; yy = y + n; if (d == month_days(m, y)) if ( (!leapyear(y) && leapyear(yy)) || (leapyear(y) && !leapyear(yy)) ) d = month_days(m, yy); y = yy; cache->valid = false; } return *this; }
/* * add @n days to date */ Date& Date::add_day(int n) { if (n) { int left = n; while ( (left + d) > month_days(m, y)) { left -= (month_days(m, y) - d + 1); d = 1; add_month(1); } if (left) d += left; cache->valid = false; } return *this; }
static void progress_date(unsigned * Y, unsigned * M, unsigned * D, const bool is_leapyear) { if (++(*D) > month_days(*M, is_leapyear)) { *D = 1; if (++(*M) > 12) { *M = 1; ++(*Y); } } }
/* * Does the rtc_time represent a valid date/time? */ int rtc_valid_tm(struct rtc_time *tm) { if (tm->tm_year < 70 || tm->tm_mon >= 12 || tm->tm_mday < 1 || tm->tm_mday > month_days(tm->tm_mon, tm->tm_year + 1900) || tm->tm_hour >= 24 || tm->tm_min >= 60 || tm->tm_sec >= 60) return -EINVAL; return 0; }
date_t plusab(date_t *date, day_t days) { /* todo: eliminate loops, handle year <== 1752 */ /* Normalize the days to be less then 1 year */ while(days < 0){ date->year -= 1; days += year_days(date->year); }; while(days > year_days(date->year)){ days -= year_days(date->year); date->year += 1; }; date->month_day += days; /* Normalize the days to be the same month */ while(date->month_day > month_days(date->year, date->month)){ date->month_day -= month_days(date->year, date->month); date->month += 1; if(date->month > year_months){ date->month -= year_months; date->year += 1; } } date->week_day = week_day(*date); return *date; }
static bool date_is_valid( uint16_t year, uint8_t month, uint8_t day) { bool status = false; /* true if value date */ uint8_t monthdays; /* days in a month */ monthdays = month_days(year, month); if ((year >= 1900) && (monthdays) && (day >= 1) && (day <= monthdays)) { status = true; } return status; }
void tui_set_clock(void) { struct mtm tm; timer_get_time(&tm); tm.sec = 0; uint16_t year = tui_gen_nummenu(PSTR("YEAR"),TIME_EPOCH_YEAR,TIME_EPOCH_YEAR+130,tm.year+TIME_EPOCH_YEAR); uint8_t month = tui_gen_nummenu(PSTR("MONTH"),1,12,tm.month); year = year - TIME_EPOCH_YEAR; if ((tm.month != month)||(tm.year != year)) { // Day count in the month possibly changed, cannot start from old day. tm.day = 1; } tm.day = tui_gen_nummenu(PSTR("DAY"),1,month_days(year,month-1),tm.day); tm.year = year; tm.month = month; tm.hour = tui_gen_nummenu(PSTR("HOURS"), 0, 23, tm.hour); tm.min = tui_gen_nummenu(PSTR("MINUTES"),0, 59, tm.min); timer_set_time(&tm); }
/* * the constructor of Date, it'll throw a BadDate exception if * the input date is illegal. */ Date::Date(int dd, Month mm, int yy) { dd = dd ? dd : default_date.d; mm = mm ? mm : default_date.m; yy = yy ? yy : default_date.y; if (mm < jan || mm > dec) throw BadDate("incorrect month"); if (dd < 1 || dd > month_days(mm, yy)) throw BadDate("incorrect day"); d = dd; m = mm; y = yy; cache = new Cache(); cache->valid = false; }
static uint32_t days_since_epoch( uint16_t year, uint8_t month, uint8_t day) { uint32_t days = 0; /* return value */ uint16_t years = 0; /* loop counter for years */ uint8_t months = 0; /* loop counter for months */ if (date_is_valid(year, month, day)) { for (years = 1900; years < year; years++) { days += 365; if (is_leap_year(years)) days++; } for (months = 1; months < month; months++) { days += month_days(years, months); } days += (day - 1); } return (days); }
/* * Convert seconds since 01-01-1970 00:00:00 to Gregorian date. */ void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) { int days, month, year; days = time / 86400; time -= days * 86400; tm->tm_wday = (days + 4) % 7; year = 1970 + days / 365; days -= (year - 1970) * 365 + LEAPS_THRU_END_OF(year - 1) - LEAPS_THRU_END_OF(1970 - 1); if (days < 0) { year -= 1; days += 365 + LEAP_YEAR(year); } tm->tm_year = year - 1900; tm->tm_yday = days + 1; for (month = 0; month < 11; month++) { int newdays; newdays = days - month_days(month, year); if (newdays < 0) break; days = newdays; } tm->tm_mon = month; tm->tm_mday = days + 1; tm->tm_hour = time / 3600; time -= tm->tm_hour * 3600; tm->tm_min = time / 60; tm->tm_sec = time - tm->tm_min * 60; }
day_t year_days(year_t year) /* Ignore 1752 CE for the moment */ { return (month_days(year, 2) == 28) ? 365 : 366; }