diff options
| author | Wesley Aptekar-Cassels <me@wesleyac.com> | 2023-11-19 00:10:19 -0500 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-11-19 00:10:19 -0500 | 
| commit | 76b580a5be70df3e06dadb42fe328d66e1f83d31 (patch) | |
| tree | 2901eac995e0a372c406f7f96b5a30e898adb779 | |
| parent | c4a5cb463e0d7843dc3ee24b15933bd4d3979121 (diff) | |
| parent | 0f9bb0bd37c8183cf8eb0f3385c831503d1f76bf (diff) | |
| download | Sensor-Watch-76b580a5be70df3e06dadb42fe328d66e1f83d31.tar.gz Sensor-Watch-76b580a5be70df3e06dadb42fe328d66e1f83d31.tar.bz2 Sensor-Watch-76b580a5be70df3e06dadb42fe328d66e1f83d31.zip | |
Merge pull request #262 from rieck/timestamp-fix
Fix for incorrect conversion from `watch_date_time` to Unix time.
| -rw-r--r-- | watch-library/shared/watch/watch_utility.c | 78 | 
1 files changed, 73 insertions, 5 deletions
| diff --git a/watch-library/shared/watch/watch_utility.c b/watch-library/shared/watch/watch_utility.c index 9e524762..64b3bb79 100644 --- a/watch-library/shared/watch/watch_utility.c +++ b/watch-library/shared/watch/watch_utility.c @@ -102,13 +102,81 @@ uint16_t watch_utility_days_since_new_year(uint16_t year, uint8_t month, uint8_t      return (is_leap(year) && (month > 2) ? 1 : 0) + DAYS_SO_FAR[month - 1] + day;  } +// Function taken from `src/time/__year_to_secs.c` of musl libc +// https://musl.libc.org +static uint32_t __year_to_secs(uint32_t year, int *is_leap) +{ +	if (year-2ULL <= 136) { +		int y = year; +		int leaps = (y-68)>>2; +		if (!((y-68)&3)) { +			leaps--; +			if (is_leap) *is_leap = 1; +		} else if (is_leap) *is_leap = 0; +		return 31536000*(y-70) + 86400*leaps; +	} + +	int cycles, centuries, leaps, rem; + +	if (!is_leap) is_leap = &(int){0}; +	cycles = (year-100) / 400; +	rem = (year-100) % 400; +	if (rem < 0) { +		cycles--; +		rem += 400; +	} +	if (!rem) { +		*is_leap = 1; +		centuries = 0; +		leaps = 0; +	} else { +		if (rem >= 200) { +			if (rem >= 300) centuries = 3, rem -= 300; +			else centuries = 2, rem -= 200; +		} else { +			if (rem >= 100) centuries = 1, rem -= 100; +			else centuries = 0; +		} +		if (!rem) { +			*is_leap = 0; +			leaps = 0; +		} else { +			leaps = rem / 4U; +			rem %= 4U; +			*is_leap = !rem; +		} +	} + +	leaps += 97*cycles + 24*centuries - *is_leap; + +	return (year-100) * 31536000LL + leaps * 86400LL + 946684800 + 86400; +} + +// Function taken from `src/time/__month_to_secs.c` of musl libc +// https://musl.libc.org +static int __month_to_secs(int month, int is_leap) +{ +	static const int secs_through_month[] = { +		0, 31*86400, 59*86400, 90*86400, +		120*86400, 151*86400, 181*86400, 212*86400, +		243*86400, 273*86400, 304*86400, 334*86400 }; +	int t = secs_through_month[month]; +	if (is_leap && month >= 2) t+=86400; +	return t; +} + +// Function adapted from `src/time/__tm_to_secs.c` of musl libc +// https://musl.libc.org  uint32_t watch_utility_convert_to_unix_time(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, uint32_t utc_offset) { -    uint32_t year_adj = year + 4800; -    uint32_t leap_days = 1 + (year_adj / 4) - (year_adj / 100) + (year_adj / 400); -    uint32_t days = 365 * year_adj + leap_days + watch_utility_days_since_new_year(year, month, day) - 1; -    days -= 2472692;  /* Adjust to Unix epoch. */ +    int is_leap; + +    // POSIX tm struct starts year at 1900 and month at 0 +    // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/time.h.html  +    uint32_t timestamp = __year_to_secs(year - 1900, &is_leap); +    timestamp += __month_to_secs(month - 1, is_leap); -    uint32_t timestamp = days * 86400; +    // Regular conversion from musl libc +    timestamp += (day - 1) * 86400;      timestamp += hour * 3600;      timestamp += minute * 60;      timestamp += second; | 
