diff --git a/bacnet-stack/datetime.c b/bacnet-stack/datetime.c index 96fe851d..9d23448e 100644 --- a/bacnet-stack/datetime.c +++ b/bacnet-stack/datetime.c @@ -87,7 +87,7 @@ static uint32_t days_since_epoch(uint16_t year, uint8_t month, uint8_t day) } for (months = 1; months < month; months++) { - days += month_days(months,year); + days += month_days(years, months); } days += (day - 1); } @@ -95,6 +95,45 @@ static uint32_t days_since_epoch(uint16_t year, uint8_t month, uint8_t day) return (days); } +static void days_since_epoch_into_ymd( + uint32_t days, + uint16_t *pYear, + uint8_t *pMonth, + uint8_t *pDay) +{ + int year = 1900; + int month = 1; + int day = 1; + + while (days >= 365) + { + if ((is_leap_year(year)) && days == 365) + break; + days -= 365; + if (is_leap_year(year)) + --days; + year++; + } + + while (days >= month_days(year, month)) + { + days -= month_days(year, month); + month++; + } + + day += days; + + if (pYear) + *pYear = year; + if (pMonth) + *pMonth = month; + if (pDay) + *pDay = day; + + return; +} + + /* Jan 1, 1900 is a Monday */ /* wday 1=Monday...7=Sunday */ static uint8_t day_of_week(uint16_t year, uint8_t month, uint8_t day) @@ -243,11 +282,131 @@ void datetime_set_values(BACNET_DATE_TIME * bdatetime, } } +static uint32_t seconds_since_midnight(uint8_t hours, uint8_t minutes, + uint8_t seconds) +{ + return ((hours * 60 * 60) + (minutes * 60) + seconds); +} + +static void seconds_since_midnight_into_hms(uint32_t seconds, + uint8_t * pHours, + uint8_t *pMinutes, + uint8_t *pSeconds) +{ + uint8_t hour = 0; + uint8_t minute = 0; + + hour = seconds / (60 * 60); + seconds -= (hour * 60 * 60); + minute = seconds / 60; + seconds -= (minute * 60); + + if (pHours) + *pHours = hour; + if (pMinutes) + *pMinutes = minute; + if (pSeconds) + *pSeconds = seconds; +} + +void datetime_add_minutes(BACNET_DATE_TIME * bdatetime, uint32_t minutes) +{ + uint32_t bdatetime_minutes = 0; + uint32_t bdatetime_days = 0; + uint32_t days = 0; + + /* convert bdatetime to seconds and days */ + bdatetime_minutes = seconds_since_midnight( + bdatetime->time.hour, + bdatetime->time.min, + bdatetime->time.sec) / 60; + bdatetime_days = days_since_epoch( + bdatetime->date.year, + bdatetime->date.month, + bdatetime->date.day); + + /* add */ + days = minutes / (24*60); + bdatetime_days += days; + minutes -= (days * 24 * 60); + bdatetime_minutes += minutes; + days = bdatetime_minutes / (24*60); + bdatetime_days += days; + + /* convert bdatetime from seconds and days */ + seconds_since_midnight_into_hms(bdatetime_minutes * 60, + &bdatetime->time.hour, + &bdatetime->time.min, + &bdatetime->time.sec); + days_since_epoch_into_ymd( + bdatetime_days, + &bdatetime->date.year, + &bdatetime->date.month, + &bdatetime->date.day); + bdatetime->date.wday = day_of_week( + bdatetime->date.year, + bdatetime->date.month, + bdatetime->date.day); +} + #ifdef TEST #include #include #include "ctest.h" +void testBACnetDateTimeAdd(Test * pTest) +{ + BACNET_DATE_TIME bdatetime, test_bdatetime; + uint32_t minutes = 0; + int diff = 0; + + datetime_set_values(&bdatetime, 1900,1,1,0,0,0,0); + datetime_copy(&test_bdatetime,&bdatetime); + datetime_add_minutes(&bdatetime, minutes); + diff = datetime_compare(&test_bdatetime, &bdatetime); + ct_test(pTest, diff == 0); + + datetime_set_values(&bdatetime, 1900,1,1,0,0,0,0); + datetime_add_minutes(&bdatetime, 60); + datetime_set_values(&test_bdatetime, 1900,1,1,1,0,0,0); + diff = datetime_compare(&test_bdatetime, &bdatetime); + ct_test(pTest, diff == 0); + + datetime_set_values(&bdatetime, 1900,1,1,0,0,0,0); + datetime_add_minutes(&bdatetime, (24*60)); + datetime_set_values(&test_bdatetime, 1900,1,2,0,0,0,0); + diff = datetime_compare(&test_bdatetime, &bdatetime); + ct_test(pTest, diff == 0); + + datetime_set_values(&bdatetime, 1900,1,1,0,0,0,0); + datetime_add_minutes(&bdatetime, (31*24*60)); + datetime_set_values(&test_bdatetime, 1900,2,1,0,0,0,0); + diff = datetime_compare(&test_bdatetime, &bdatetime); + ct_test(pTest, diff == 0); +} + + + +void testBACnetDateTimeSeconds(Test * pTest) +{ + uint8_t hour = 0, minute = 0, second = 0; + uint8_t test_hour = 0, test_minute = 0, test_second = 0; + uint32_t seconds = 0, test_seconds; + + for (hour = 0; hour < 24; hour++) { + for (minute = 0; minute < 60; minute+=3) { + for (second = 0; second < 60; second+=17) { + seconds = seconds_since_midnight(hour, minute, second); + seconds_since_midnight_into_hms(seconds, + &test_hour, &test_minute, &test_second); + test_seconds = seconds_since_midnight( + test_hour, test_minute, test_second); + ct_test(pTest, seconds == test_seconds); + } + } + } +} + void testBACnetDate(Test * pTest) { BACNET_DATE bdate1, bdate2; @@ -425,6 +584,35 @@ void testBACnetDateTime(Test * pTest) return; } +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); + } + } + } +} + void testBACnetDayOfWeek(Test * pTest) { uint8_t dow = 0; @@ -451,7 +639,6 @@ void testBACnetDayOfWeek(Test * pTest) dow = day_of_week(2007, 1, 31); ct_test(pTest, dow == 3); - } #ifdef TEST_DATE_TIME @@ -470,6 +657,12 @@ int main(void) assert(rc); rc = ct_addTestFunction(pTest, testBACnetDayOfWeek); assert(rc); + rc = ct_addTestFunction(pTest, testDateEpoch); + assert(rc); + rc = ct_addTestFunction(pTest, testBACnetDateTimeSeconds); + assert(rc); + rc = ct_addTestFunction(pTest, testBACnetDateTimeAdd); + assert(rc); ct_setStream(pTest, stdout); ct_run(pTest); diff --git a/bacnet-stack/datetime.h b/bacnet-stack/datetime.h index ea1b7076..b091aafa 100644 --- a/bacnet-stack/datetime.h +++ b/bacnet-stack/datetime.h @@ -91,6 +91,9 @@ extern "C" { BACNET_DATE_TIME * datetime1, BACNET_DATE_TIME * datetime2); + /* utility add function */ + void datetime_add_minutes(BACNET_DATE_TIME * bdatetime, uint32_t minutes); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/bacnet-stack/datetime.ide b/bacnet-stack/datetime.ide index 2c329d3b..cd384851 100644 Binary files a/bacnet-stack/datetime.ide and b/bacnet-stack/datetime.ide differ