1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Refactored some Time internals to rely on 64-bit OS time conversion functions.

This commit is contained in:
jules 2016-03-01 15:50:06 +00:00
parent dea899741d
commit 889a6e200f

View file

@ -28,93 +28,61 @@
namespace TimeHelpers
{
static struct tm millisecondsToTM (const int64 jdm) noexcept
static std::tm millisToLocal (int64 millis) noexcept
{
struct tm result;
const int days = (int) (jdm / 86400LL);
const int a = 32044 + days;
const int b = (4 * a + 3) / 146097;
const int c = a - (b * 146097) / 4;
const int d = (4 * c + 3) / 1461;
const int e = c - (d * 1461) / 4;
const int m = (5 * e + 2) / 153;
result.tm_mday = e - (153 * m + 2) / 5 + 1;
result.tm_mon = m + 2 - 12 * (m / 10);
result.tm_year = b * 100 + d - 6700 + (m / 10);
result.tm_wday = (days + 1) % 7;
result.tm_yday = -1;
int t = (int) (jdm % 86400LL);
result.tm_hour = t / 3600;
t %= 3600;
result.tm_min = t / 60;
result.tm_sec = t % 60;
result.tm_isdst = -1;
return result;
}
static bool isBeyond1970to2030Range (const int64 seconds)
{
return seconds < 86400LL || seconds >= 2145916800LL;
}
static struct tm millisToLocal (const int64 millis) noexcept
{
const int64 seconds = millis / 1000;
if (isBeyond1970to2030Range (seconds))
{
const int timeZoneAdjustment = 31536000 - (int) (Time (1971, 0, 1, 0, 0).toMilliseconds() / 1000);
return millisecondsToTM (seconds + timeZoneAdjustment + 210866803200LL);
}
struct tm result;
time_t now = static_cast<time_t> (seconds);
#if JUCE_WINDOWS && JUCE_MINGW
time_t now = (time_t) (millis / 1000);
return *localtime (&now);
#elif JUCE_WINDOWS
if (now >= 0 && now <= 0x793406fff)
localtime_s (&result, &now);
else
std::tm result;
millis /= 1000;
if (_localtime64_s (&result, &millis) != 0)
zerostruct (result);
#else
localtime_r (&now, &result); // more thread-safe
#endif
return result;
#else
std::tm result;
time_t now = (time_t) (millis / 1000);
if (localtime_r (&now, &result) == nullptr)
zerostruct (result);
return result;
#endif
}
static struct tm millisToUTC (const int64 millis) noexcept
static std::tm millisToUTC (int64 millis) noexcept
{
const int64 seconds = millis / 1000;
if (isBeyond1970to2030Range (seconds))
return millisecondsToTM (seconds + 210866803200LL);
struct tm result;
time_t now = static_cast<time_t> (seconds);
#if JUCE_WINDOWS && JUCE_MINGW
time_t now = (time_t) (millis / 1000);
return *gmtime (&now);
#elif JUCE_WINDOWS
if (now >= 0 && now <= 0x793406fff)
gmtime_s (&result, &now);
else
std::tm result;
millis /= 1000;
if (_gmtime64_s (&result, &millis) != 0)
zerostruct (result);
#else
gmtime_r (&now, &result); // more thread-safe
#endif
return result;
#else
std::tm result;
time_t now = (time_t) (millis / 1000);
if (gmtime_r (&now, &result) == nullptr)
zerostruct (result);
return result;
#endif
}
static int getUTCOffsetSeconds (const int64 millis) noexcept
{
struct tm utc = millisToUTC (millis);
std::tm utc = millisToUTC (millis);
utc.tm_isdst = -1; // Treat this UTC time as local to find the offset
return (int) ((millis / 1000) - (int64) mktime (&utc));
@ -126,7 +94,7 @@ namespace TimeHelpers
: (value - ((value / modulo) + 1) * modulo));
}
static inline String formatString (const String& format, const struct tm* const tm)
static inline String formatString (const String& format, const std::tm* const tm)
{
#if JUCE_ANDROID
typedef CharPointer_UTF8 StringType;
@ -160,22 +128,70 @@ namespace TimeHelpers
}
}
//==============================================================================
static inline bool isLeapYear (int year) noexcept
{
return (year % 400 == 0) || ((year % 100 != 0) && (year % 4 == 0));
}
static inline int daysFromJan1 (int year, int month) noexcept
{
const short dayOfYear[] = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335,
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
return dayOfYear [(isLeapYear (year) ? 12 : 0) + month];
}
static inline int64 daysFromYear0 (int year) noexcept
{
return 365 * (year - 1) + (year / 400) - (year / 100) + (year / 4);
}
static inline int64 daysFrom1970 (int year) noexcept
{
return daysFromYear0 (year) - daysFromYear0 (1970);
}
static inline int64 daysFrom1970 (int year, int month) noexcept
{
if (month > 11)
{
year += month / 12;
month %= 12;
}
else if (month < 0)
{
const int numYears = (11 - month) / 12;
year -= numYears;
month += 12 * numYears;
}
return daysFrom1970 (year) + daysFromJan1 (year, month);
}
// There's no posix function that does a UTC version of mktime,
// so annoyingly we need to implement this manually..
static inline int64 mktime_utc (const std::tm& t) noexcept
{
return 24 * 3600 * (daysFrom1970 (t.tm_year + 1900, t.tm_mon) + (t.tm_mday - 1))
+ 3600 * t.tm_hour
+ 60 * t.tm_min
+ t.tm_sec;
}
static uint32 lastMSCounterValue = 0;
}
//==============================================================================
Time::Time() noexcept
: millisSinceEpoch (0)
Time::Time() noexcept : millisSinceEpoch (0)
{
}
Time::Time (const Time& other) noexcept
: millisSinceEpoch (other.millisSinceEpoch)
Time::Time (const Time& other) noexcept : millisSinceEpoch (other.millisSinceEpoch)
{
}
Time::Time (const int64 ms) noexcept
: millisSinceEpoch (ms)
Time::Time (const int64 ms) noexcept : millisSinceEpoch (ms)
{
}
@ -188,41 +204,26 @@ Time::Time (const int year,
const int milliseconds,
const bool useLocalTime) noexcept
{
jassert (year > 100); // year must be a 4-digit version
std::tm t;
t.tm_year = year - 1900;
t.tm_mon = month;
t.tm_mday = day;
t.tm_hour = hours;
t.tm_min = minutes;
t.tm_sec = seconds;
t.tm_isdst = -1;
if (year < 1971 || year >= 2038 || ! useLocalTime)
const int64 time = useLocalTime ? (int64) mktime (&t)
: TimeHelpers::mktime_utc (t);
if (time >= 0)
{
// use extended maths for dates beyond 1970 to 2037..
const int timeZoneAdjustment = useLocalTime ? (31536000 - (int) (Time (1971, 0, 1, 0, 0).toMilliseconds() / 1000))
: 0;
const int a = (13 - month) / 12;
const int y = year + 4800 - a;
const int jd = day + (153 * (month + 12 * a - 2) + 2) / 5
+ (y * 365) + (y / 4) - (y / 100) + (y / 400)
- 32045;
const int64 s = ((int64) jd) * 86400LL - 210866803200LL;
millisSinceEpoch = 1000 * (s + (hours * 3600 + minutes * 60 + seconds - timeZoneAdjustment))
+ milliseconds;
millisSinceEpoch = 1000 * time + milliseconds;
}
else
{
struct tm t;
t.tm_year = year - 1900;
t.tm_mon = month;
t.tm_mday = day;
t.tm_hour = hours;
t.tm_min = minutes;
t.tm_sec = seconds;
t.tm_isdst = -1;
millisSinceEpoch = 1000 * (int64) mktime (&t);
if (millisSinceEpoch < 0)
millisSinceEpoch = 0;
else
millisSinceEpoch += milliseconds;
jassertfalse; // trying to create a date that is beyond the range that mktime supports!
millisSinceEpoch = 0;
}
}
@ -362,7 +363,7 @@ String Time::toString (const bool includeDate,
String Time::formatted (const String& format) const
{
struct tm t (TimeHelpers::millisToLocal (millisSinceEpoch));
std::tm t (TimeHelpers::millisToLocal (millisSinceEpoch));
return TimeHelpers::formatString (format, &t);
}
@ -659,6 +660,14 @@ public:
expect (Time::fromISO8601 ("20160216T150357.999Z") == Time (2016, 1, 16, 15, 3, 57, 999, false));
expect (Time::fromISO8601 ("2016-02-16T15:03:57.999-02:30") == Time (2016, 1, 16, 17, 33, 57, 999, false));
expect (Time::fromISO8601 ("20160216T150357.999-0230") == Time (2016, 1, 16, 17, 33, 57, 999, false));
expect (Time (1982, 1, 1, 12, 0, 0, 0, true) + RelativeTime::days (365) == Time (1983, 1, 1, 12, 0, 0, 0, true));
expect (Time (1970, 1, 1, 12, 0, 0, 0, true) + RelativeTime::days (365) == Time (1971, 1, 1, 12, 0, 0, 0, true));
expect (Time (2038, 1, 1, 12, 0, 0, 0, true) + RelativeTime::days (365) == Time (2039, 1, 1, 12, 0, 0, 0, true));
expect (Time (1982, 1, 1, 12, 0, 0, 0, false) + RelativeTime::days (365) == Time (1983, 1, 1, 12, 0, 0, 0, false));
expect (Time (1970, 1, 1, 12, 0, 0, 0, false) + RelativeTime::days (365) == Time (1971, 1, 1, 12, 0, 0, 0, false));
expect (Time (2038, 1, 1, 12, 0, 0, 0, false) + RelativeTime::days (365) == Time (2039, 1, 1, 12, 0, 0, 0, false));
}
};