mirror of
https://github.com/ArduPilot/ardupilot.git
synced 2026-10-02 10:23:25 +08:00
AP_Common: update ap_mktime
This commit is contained in:
committed by
Peter Barker
parent
82055c8c58
commit
fad346a071
@@ -111,6 +111,31 @@ TEST(ap_mktime, MonthLoopRollover)
|
||||
struct tm t = make_tm(1970, 1, 1, 0, 0, 0);
|
||||
t.tm_mon = 12; // 13 iterations: Dec wraps m→0, y→1971, then Jan added
|
||||
EXPECT_EQ((time_t)(365 * 86400), ap_mktime(&t));
|
||||
|
||||
// tm_mon=14 is the largest a caller can produce: AP_Filesystem_FATFS
|
||||
// reads a 4-bit month field and subtracts one, so 0x0f arrives here
|
||||
// as 14. Fourteen months on from 1 January 1970 is 1 March 1971:
|
||||
// all of 1970, then January and February.
|
||||
t.tm_mon = 14;
|
||||
EXPECT_EQ((time_t)((365 + 31 + 28) * 86400), ap_mktime(&t));
|
||||
}
|
||||
|
||||
// Every caller computes tm_mon as "month - 1" from an external date
|
||||
// field, so a source reporting month 0 arrives here as -1. Such a
|
||||
// month must contribute nothing rather than index off the front of the
|
||||
// month table.
|
||||
TEST(ap_mktime, NegativeMonth)
|
||||
{
|
||||
struct tm jan1 = make_tm(1970, 1, 1, 0, 0, 0);
|
||||
struct tm neg = jan1;
|
||||
neg.tm_mon = -1;
|
||||
EXPECT_EQ(ap_mktime(&jan1), ap_mktime(&neg));
|
||||
|
||||
// and it must not disturb the rest of the fields
|
||||
struct tm neg_later = make_tm(2024, 1, 15, 6, 7, 8);
|
||||
neg_later.tm_mon = -1;
|
||||
struct tm jan15 = make_tm(2024, 1, 15, 6, 7, 8);
|
||||
EXPECT_EQ(ap_mktime(&jan15), ap_mktime(&neg_later));
|
||||
}
|
||||
|
||||
AP_GTEST_MAIN()
|
||||
|
||||
@@ -1,44 +1,48 @@
|
||||
#include "time.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
mktime replacement from Samba
|
||||
mktime replacement, originally from Samba
|
||||
*/
|
||||
time_t ap_mktime(const struct tm *t)
|
||||
{
|
||||
time_t epoch = 0;
|
||||
int n;
|
||||
int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, y, m, i;
|
||||
const unsigned MINUTE = 60;
|
||||
const unsigned HOUR = 60*MINUTE;
|
||||
const unsigned DAY = 24*HOUR;
|
||||
const unsigned YEAR = 365*DAY;
|
||||
// days elapsed from 1 January to the 1st of each month, common year
|
||||
static const uint16_t cumdays[12] = {
|
||||
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
|
||||
|
||||
if (t->tm_year < 70) {
|
||||
return (time_t)-1;
|
||||
}
|
||||
|
||||
n = t->tm_year + 1900 - 1;
|
||||
epoch = (t->tm_year - 70) * YEAR +
|
||||
((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
|
||||
|
||||
y = t->tm_year + 1900;
|
||||
m = 0;
|
||||
|
||||
for (i = 0; i < t->tm_mon; i++) {
|
||||
epoch += mon [m] * DAY;
|
||||
if (m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) {
|
||||
epoch += DAY;
|
||||
}
|
||||
|
||||
if (++m > 11) {
|
||||
m = 0;
|
||||
y++;
|
||||
}
|
||||
/*
|
||||
every caller derives tm_mon from an external date field as
|
||||
"month - 1", so it can land outside 0-11 when the source reports
|
||||
a zero or out-of-range month. Both cases are kept as the month
|
||||
loop this replaced behaved: it walked its own month and year
|
||||
counters forward, so months past December rolled into the
|
||||
following years, and a negative month added nothing because the
|
||||
loop simply never ran.
|
||||
*/
|
||||
int mon = t->tm_mon;
|
||||
int year_off = t->tm_year;
|
||||
if (mon > 11) {
|
||||
year_off += mon / 12;
|
||||
mon %= 12;
|
||||
} else if (mon < 0) {
|
||||
mon = 0;
|
||||
}
|
||||
|
||||
epoch += (t->tm_mday - 1) * DAY;
|
||||
epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
|
||||
const uint32_t year = (uint32_t)year_off + 1900U;
|
||||
const uint32_t n = year - 1U;
|
||||
const bool leap = (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0);
|
||||
|
||||
return epoch;
|
||||
// leap days since the epoch, as a closed form rather than a
|
||||
// per-year loop; 477 is the same count taken at 1969
|
||||
const uint32_t days = (uint32_t)(year_off - 70) * 365U
|
||||
+ (n/4U - n/100U + n/400U) - 477U
|
||||
+ cumdays[mon] + (leap && mon > 1)
|
||||
+ (uint32_t)t->tm_mday - 1U;
|
||||
|
||||
return (time_t)days * 86400 + t->tm_hour*3600 + t->tm_min*60 + t->tm_sec;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user