diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index a4c56f92bc..2b90ff03e8 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -2027,27 +2027,30 @@ static APKNode *AddAPKDirs(char *path, APKNode *parent) static SDL_Time ZipDosTimeToSDLTime(Uint32 dostime) { - Uint32 dosdate; - struct tm unixtime; - SDL_zero(unixtime); + // Note that DOS-style datetimes in a zip don't have timezone info, etc, + // so these are treated as UTC for lack of a better option. Also, they have + // 2-second precision and the year bits are going to roll over in 2108. + // There are possibly better timestamps in extended fields (!!! FIXME: add + // support for those), but this field is guaranteed to exist with all its + // flaws and is probably Good Enough anyhow. + const Uint32 dosdate = (Uint32) ((dostime >> 16) & 0xFFFF); + const Uint32 dostime16 = dostime & 0xFFFF; - dosdate = (Uint32) ((dostime >> 16) & 0xFFFF); - dostime &= 0xFFFF; + const int m = (int) ((dosdate >> 5) & 0x0F); + const int d = (int) ((dosdate >> 0) & 0x1F) + 1; + const int y = (int) (((dosdate >> 9) & 0x7F) + 1980) - (m <= 2 ? 1 : 0); + const int hour = (int) ((dostime16 >> 11) & 0x1F); + const int minute = (int) ((dostime16 >> 5) & 0x3F); + const int sec = (int) ((dostime16 << 1) & 0x3E); - /* dissect date */ - unixtime.tm_year = ((dosdate >> 9) & 0x7F) + 80; - unixtime.tm_mon = ((dosdate >> 5) & 0x0F) - 1; - unixtime.tm_mday = ((dosdate ) & 0x1F); - - /* dissect time */ - unixtime.tm_hour = ((dostime >> 11) & 0x1F); - unixtime.tm_min = ((dostime >> 5) & 0x3F); - unixtime.tm_sec = ((dostime << 1) & 0x3E); - - /* let mktime calculate daylight savings time. */ - unixtime.tm_isdst = -1; - - return ((SDL_Time) mktime(&unixtime)); + // days since 1/1/1970: https://howardhinnant.github.io/date_algorithms.html#days_from_civil + const int era = ((y >= 0) ? y : (y - 399)) / 400; + const unsigned int yoe = (unsigned int) (y - era * 400); // [0, 399] + const unsigned int doy = (((153 * ((m > 2) ? (m - 3) : (m + 9))) + 2) / 5) + (d - 1); // [0, 365] + const unsigned int doe = (yoe * 365) + (yoe / 4) - (yoe / 100) + doy; // [0, 146096] + const int days = (era * 146097) + ((int) doe) - 719468; + const int seconds = (hour * (60 * 60)) + (minute * 60) + (sec); + return (SDL_Time) (((Sint64) days) * 86400) + seconds; }