]> git.earman.xyz Git - sensor-watch.git/commitdiff
Fixed incorrect conversion from UNIX timestamp to watch_date_time.
authorKonrad Rieck <konrad@mlsec.org>
Fri, 11 Aug 2023 20:26:34 +0000 (22:26 +0200)
committerKonrad Rieck <konrad@mlsec.org>
Fri, 11 Aug 2023 20:26:34 +0000 (22:26 +0200)
watch-library/shared/watch/watch_utility.c

index 9e52476242cc6992b22a06308f9f084cebc47696..64b3bb791cfcd06ebe8f60542e326b7499b633df 100644 (file)
@@ -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;