28 static std::tm millisToLocal (int64 millis)
noexcept
30 #if JUCE_WINDOWS && JUCE_MINGW
31 auto now = (time_t) (millis / 1000);
32 return *localtime (&now);
38 if (_localtime64_s (&result, &millis) != 0)
45 auto now = (time_t) (millis / 1000);
47 if (localtime_r (&now, &result) ==
nullptr)
54 static std::tm millisToUTC (int64 millis)
noexcept
56 #if JUCE_WINDOWS && JUCE_MINGW
57 auto now = (time_t) (millis / 1000);
58 return *gmtime (&now);
64 if (_gmtime64_s (&result, &millis) != 0)
71 auto now = (time_t) (millis / 1000);
73 if (gmtime_r (&now, &result) ==
nullptr)
80 static int getUTCOffsetSeconds (
const int64 millis)
noexcept
82 auto utc = millisToUTC (millis);
85 return (
int) ((millis / 1000) - (int64) mktime (&utc));
88 static int extendedModulo (
const int64 value,
const int modulo)
noexcept
90 return (
int) (value >= 0 ? (value % modulo)
91 : (value - ((value / modulo) + 1) * modulo));
94 static inline String formatString (
const String& format,
const std::tm*
const tm)
97 using StringType = CharPointer_UTF8;
99 using StringType = CharPointer_UTF16;
101 using StringType = CharPointer_UTF32;
105 if (tm->tm_year < -1900 || tm->tm_year > 8099)
109 for (
size_t bufferSize = 256; ; bufferSize += 256)
111 HeapBlock<StringType::CharType> buffer (bufferSize);
115 strftime (buffer, bufferSize - 1, format.toUTF8(), tm);
117 wcsftime (buffer, bufferSize - 1, format.toWideCharPointer(), tm);
119 wcsftime (buffer, bufferSize - 1, format.toUTF32(), tm);
122 if (numChars > 0 || format.isEmpty())
123 return String (StringType (buffer),
124 StringType (buffer) + (
int) numChars);
129 static inline bool isLeapYear (
int year)
noexcept
131 return (year % 400 == 0) || ((year % 100 != 0) && (year % 4 == 0));
134 static inline int daysFromJan1 (
int year,
int month)
noexcept
136 const short dayOfYear[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
137 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
139 return dayOfYear [(isLeapYear (year) ? 12 : 0) + month];
142 static inline int64 daysFromYear0 (
int year)
noexcept
145 return 365 * year + (year / 400) - (year / 100) + (year / 4);
148 static inline int64 daysFrom1970 (
int year)
noexcept
150 return daysFromYear0 (year) - daysFromYear0 (1970);
153 static inline int64 daysFrom1970 (
int year,
int month)
noexcept
162 auto numYears = (11 - month) / 12;
164 month += 12 * numYears;
167 return daysFrom1970 (year) + daysFromJan1 (year, month);
172 static inline int64 mktime_utc (
const std::tm& t)
noexcept
174 return 24 * 3600 * (daysFrom1970 (t.tm_year + 1900, t.tm_mon) + (t.tm_mday - 1))
180 static Atomic<uint32> lastMSCounterValue { (uint32) 0 };
187 int hours,
int minutes,
int seconds,
int milliseconds,
191 t.tm_year =
year - 1900;
200 : TimeHelpers::mktime_utc (
t))
207 #if JUCE_WINDOWS && ! JUCE_MINGW
210 return ((int64)
t.time) * 1000 +
t.millitm;
214 return ((int64)
tv.tv_sec) * 1000 +
tv.tv_usec / 1000;
224uint32 juce_millisecondsSinceStartup()
noexcept;
228 auto now = juce_millisecondsSinceStartup();
230 if (
now < TimeHelpers::lastMSCounterValue.get())
235 if (
now < TimeHelpers::lastMSCounterValue.get() - (uint32) 1000)
236 TimeHelpers::lastMSCounterValue =
now;
240 TimeHelpers::lastMSCounterValue =
now;
248 auto t = TimeHelpers::lastMSCounterValue.get();
256 auto now = getMillisecondCounter();
271 for (
int i = 10; --i >= 0;)
280 return ticks / (
double) getHighResolutionTicksPerSecond();
285 return (int64) (seconds * (
double) getHighResolutionTicksPerSecond());
311 << (
mins < 10 ?
":0" :
":") <<
mins;
316 result << (
secs < 10 ?
":0" :
":") <<
secs;
328 std::tm
t (TimeHelpers::millisToLocal (millisSinceEpoch));
329 return TimeHelpers::formatString (format, &
t);
347 if (hours == 0)
return 12;
348 if (hours <= 12)
return hours;
360 return TimeHelpers::millisToLocal (millisSinceEpoch).tm_isdst != 0;
368 #if JUCE_MSVC || JUCE_CLANG
371 for (
int i = 0; i < 2; ++i)
373 char name[128] = { 0 };
379 #warning "Can't find a replacement for tzset on mingw - ideas welcome!"
393 if (zone[0].length() > 3
404 return TimeHelpers::getUTCOffsetSeconds (millisSinceEpoch);
411 auto minutes = seconds / 60;
425 :
"%04d%02d%02dT%02d%02d%06.03f",
435static int parseFixedSizeIntAndSkip (String::CharPointerType&
t,
int numChars,
char charToSkip)
noexcept
443 if (! isPositiveAndBelow (
digit, 10))
450 if (charToSkip != 0 && *t == (juce_wchar) charToSkip)
459 auto year = parseFixedSizeIntAndSkip (
t, 4,
'-');
464 auto month = parseFixedSizeIntAndSkip (
t, 2,
'-');
469 auto day = parseFixedSizeIntAndSkip (
t, 2, 0);
474 int hours = 0, minutes = 0, milliseconds = 0;
479 hours = parseFixedSizeIntAndSkip (
t, 2,
':');
484 minutes = parseFixedSizeIntAndSkip (
t, 2,
':');
489 auto seconds = parseFixedSizeIntAndSkip (
t, 2, 0);
494 if (*
t ==
'.' || *
t ==
',')
497 milliseconds = parseFixedSizeIntAndSkip (
t, 3, 0);
499 if (milliseconds < 0)
503 milliseconds += 1000 * seconds;
510 auto offsetHours = parseFixedSizeIntAndSkip (
t, 2,
':');
541static const char*
const shortMonthNames[] = {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec" };
542static const char*
const longMonthNames[] = {
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December" };
554 static const char*
const shortDayNames[] = {
"Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat" };
555 static const char*
const longDayNames[] = {
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday" };
568Time operator- (Time time, RelativeTime delta)
noexcept { Time t (time);
return t -= delta; }
569Time operator+ (RelativeTime delta, Time time)
noexcept { Time t (time);
return t += delta; }
570const RelativeTime operator- (Time time1, Time time2)
noexcept {
return RelativeTime::milliseconds (time1.toMilliseconds() - time2.toMilliseconds()); }
572bool operator== (Time time1, Time time2)
noexcept {
return time1.toMilliseconds() == time2.toMilliseconds(); }
573bool operator!= (Time time1, Time time2)
noexcept {
return time1.toMilliseconds() != time2.toMilliseconds(); }
574bool operator< (Time time1, Time time2)
noexcept {
return time1.toMilliseconds() < time2.toMilliseconds(); }
575bool operator> (Time time1, Time time2)
noexcept {
return time1.toMilliseconds() > time2.toMilliseconds(); }
576bool operator<= (Time time1, Time time2)
noexcept {
return time1.toMilliseconds() <= time2.toMilliseconds(); }
577bool operator>= (Time time1, Time time2)
noexcept {
return time1.toMilliseconds() >= time2.toMilliseconds(); }
579static int getMonthNumberForCompileDate (
const String& m)
581 for (
int i = 0; i < 12; ++i)
582 if (m.equalsIgnoreCase (shortMonthNames[i]))
616 :
UnitTest (
"Time", UnitTestCategories::time)
619 void runTest()
override
629 expect (
t.getTimeZone().isNotEmpty());
630 expect (
t.getUTCOffsetString (
true) ==
"Z" ||
t.getUTCOffsetString (
true).length() == 6);
631 expect (
t.getUTCOffsetString (
false) ==
"Z" ||
t.getUTCOffsetString (
false).length() == 5);
636 expect (
Time::fromISO8601 (
"2016-02-16") == Time (2016, 1, 16, 0, 0, 0, 0,
false));
637 expect (
Time::fromISO8601 (
"20160216Z") == Time (2016, 1, 16, 0, 0, 0, 0,
false));
639 expect (
Time::fromISO8601 (
"2016-02-16T15:03:57+00:00") == Time (2016, 1, 16, 15, 3, 57, 0,
false));
640 expect (
Time::fromISO8601 (
"20160216T150357+0000") == Time (2016, 1, 16, 15, 3, 57, 0,
false));
642 expect (
Time::fromISO8601 (
"2016-02-16T15:03:57.999+00:00") == Time (2016, 1, 16, 15, 3, 57, 999,
false));
643 expect (
Time::fromISO8601 (
"20160216T150357.999+0000") == Time (2016, 1, 16, 15, 3, 57, 999,
false));
644 expect (
Time::fromISO8601 (
"2016-02-16T15:03:57.999Z") == Time (2016, 1, 16, 15, 3, 57, 999,
false));
645 expect (
Time::fromISO8601 (
"2016-02-16T15:03:57,999Z") == Time (2016, 1, 16, 15, 3, 57, 999,
false));
646 expect (
Time::fromISO8601 (
"20160216T150357.999Z") == Time (2016, 1, 16, 15, 3, 57, 999,
false));
647 expect (
Time::fromISO8601 (
"20160216T150357,999Z") == Time (2016, 1, 16, 15, 3, 57, 999,
false));
649 expect (
Time::fromISO8601 (
"2016-02-16T15:03:57.999-02:30") == Time (2016, 1, 16, 17, 33, 57, 999,
false));
650 expect (
Time::fromISO8601 (
"2016-02-16T15:03:57,999-02:30") == Time (2016, 1, 16, 17, 33, 57, 999,
false));
651 expect (
Time::fromISO8601 (
"20160216T150357.999-0230") == Time (2016, 1, 16, 17, 33, 57, 999,
false));
652 expect (
Time::fromISO8601 (
"20160216T150357,999-0230") == Time (2016, 1, 16, 17, 33, 57, 999,
false));
654 expect (Time (1970, 0, 1, 0, 0, 0, 0,
false) == Time (0));
655 expect (Time (2106, 1, 7, 6, 28, 15, 0,
false) == Time (4294967295000));
656 expect (Time (2007, 10, 7, 1, 7, 20, 0,
false) == Time (1194397640000));
657 expect (Time (2038, 0, 19, 3, 14, 7, 0,
false) == Time (2147483647000));
658 expect (Time (2016, 2, 7, 11, 20, 8, 0,
false) == Time (1457349608000));
659 expect (Time (1969, 11, 31, 23, 59, 59, 0,
false) == Time (-1000));
660 expect (Time (1901, 11, 13, 20, 45, 53, 0,
false) == Time (-2147483647000));
662 expect (Time (1982, 1, 1, 12, 0, 0, 0,
true) +
RelativeTime::days (365) == Time (1983, 1, 1, 12, 0, 0, 0,
true));
663 expect (Time (1970, 1, 1, 12, 0, 0, 0,
true) +
RelativeTime::days (365) == Time (1971, 1, 1, 12, 0, 0, 0,
true));
664 expect (Time (2038, 1, 1, 12, 0, 0, 0,
true) +
RelativeTime::days (365) == Time (2039, 1, 1, 12, 0, 0, 0,
true));
666 expect (Time (1982, 1, 1, 12, 0, 0, 0,
false) +
RelativeTime::days (365) == Time (1983, 1, 1, 12, 0, 0, 0,
false));
667 expect (Time (1970, 1, 1, 12, 0, 0, 0,
false) +
RelativeTime::days (365) == Time (1971, 1, 1, 12, 0, 0, 0,
false));
668 expect (Time (2038, 1, 1, 12, 0, 0, 0,
false) +
RelativeTime::days (365) == Time (2039, 1, 1, 12, 0, 0, 0,
false));
672static TimeTests timeTests;
static RelativeTime milliseconds(int milliseconds) noexcept
static RelativeTime days(double numberOfDays) noexcept
bool containsIgnoreCase(StringRef text) const noexcept
static String formatted(const String &formatStr, Args... args)
bool contains(StringRef text) const noexcept
String substring(int startIndex, int endIndex) const
static void JUCE_CALLTYPE sleep(int milliseconds)
static void JUCE_CALLTYPE yield()
bool isDaylightSavingTime() const noexcept
static uint32 getApproximateMillisecondCounter() noexcept
String getTimeZone() const
String getUTCOffsetString(bool includeDividerCharacters) const
int getHoursInAmPmFormat() const noexcept
static Time fromISO8601(StringRef iso8601)
int getMilliseconds() const noexcept
String getWeekdayName(bool threeLetterVersion) const
int getDayOfMonth() const noexcept
static int64 currentTimeMillis() noexcept
int getUTCOffsetSeconds() const noexcept
int getMonth() const noexcept
static Time JUCE_CALLTYPE getCurrentTime() noexcept
String toString(bool includeDate, bool includeTime, bool includeSeconds=true, bool use24HourClock=false) const
bool isAfternoon() const noexcept
Time & operator-=(RelativeTime delta) noexcept
int getYear() const noexcept
static Time getCompilationDate()
static double highResolutionTicksToSeconds(int64 ticks) noexcept
int getDayOfYear() const noexcept
static int64 secondsToHighResolutionTicks(double seconds) noexcept
String getMonthName(bool threeLetterVersion) const
int getMinutes() const noexcept
Time & operator+=(RelativeTime delta) noexcept
static void waitForMillisecondCounter(uint32 targetTime) noexcept
String formatted(const String &format) const
String toISO8601(bool includeDividerCharacters) const
int getHours() const noexcept
static uint32 getMillisecondCounter() noexcept
int getSeconds() const noexcept
int getDayOfWeek() const noexcept