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,
188 bool useLocalTime) noexcept
191 t.tm_year = year - 1900;
199 millisSinceEpoch = 1000 * (useLocalTime ? (int64) mktime (&t)
200 : TimeHelpers::mktime_utc (t))
207 #if JUCE_WINDOWS && ! JUCE_MINGW 210 return ((int64) t.time) * 1000 + t.millitm;
213 gettimeofday (&tv,
nullptr);
214 return ((int64) tv.tv_sec) * 1000 + tv.tv_usec / 1000;
220 return Time (currentTimeMillis());
224 uint32 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();
249 return t == 0 ? getMillisecondCounter() : t;
256 auto now = getMillisecondCounter();
258 if (now >= targetTime)
261 auto toWait = (int) (targetTime - now);
271 for (
int i = 10; --i >= 0;)
280 return ticks / (double) getHighResolutionTicksPerSecond();
285 return (int64) (seconds * (double) getHighResolutionTicksPerSecond());
292 bool use24HourClock)
const 298 result << getDayOfMonth() <<
' ' 299 << getMonthName (
true) <<
' ' 308 auto mins = getMinutes();
310 result << (use24HourClock ? getHours() : getHoursInAmPmFormat())
311 << (mins < 10 ?
":0" :
":") << mins;
315 auto secs = getSeconds();
316 result << (secs < 10 ?
":0" :
":") << secs;
319 if (! use24HourClock)
320 result << (isAfternoon() ?
"pm" :
"am");
328 std::tm t (TimeHelpers::millisToLocal (millisSinceEpoch));
329 return TimeHelpers::formatString (format, &t);
333 int Time::getYear() const noexcept {
return TimeHelpers::millisToLocal (millisSinceEpoch).tm_year + 1900; }
334 int Time::getMonth() const noexcept {
return TimeHelpers::millisToLocal (millisSinceEpoch).tm_mon; }
335 int Time::getDayOfYear() const noexcept {
return TimeHelpers::millisToLocal (millisSinceEpoch).tm_yday; }
336 int Time::getDayOfMonth() const noexcept {
return TimeHelpers::millisToLocal (millisSinceEpoch).tm_mday; }
337 int Time::getDayOfWeek() const noexcept {
return TimeHelpers::millisToLocal (millisSinceEpoch).tm_wday; }
338 int Time::getHours() const noexcept {
return TimeHelpers::millisToLocal (millisSinceEpoch).tm_hour; }
339 int Time::getMinutes() const noexcept {
return TimeHelpers::millisToLocal (millisSinceEpoch).tm_min; }
340 int Time::getSeconds() const noexcept {
return TimeHelpers::extendedModulo (millisSinceEpoch / 1000, 60); }
345 auto hours = getHours();
347 if (hours == 0)
return 12;
348 if (hours <= 12)
return hours;
355 return getHours() >= 12;
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 };
375 _get_tzname (&length, name,
sizeof (name) - 1, i);
379 #warning "Can't find a replacement for tzset on mingw - ideas welcome!" 384 auto zonePtr = (
const char**) tzname;
385 zone[0] = zonePtr[0];
386 zone[1] = zonePtr[1];
389 if (isDaylightSavingTime())
393 if (zone[0].length() > 3
404 return TimeHelpers::getUTCOffsetSeconds (millisSinceEpoch);
409 if (
auto seconds = getUTCOffsetSeconds())
411 auto minutes = seconds / 60;
424 return String::formatted (includeDividerCharacters ?
"%04d-%02d-%02dT%02d:%02d:%06.03f" 425 :
"%04d%02d%02dT%02d%02d%06.03f",
431 getSeconds() + getMilliseconds() / 1000.0)
432 + getUTCOffsetString (includeDividerCharacters);
435 static int parseFixedSizeIntAndSkip (String::CharPointerType& t,
int numChars,
char charToSkip) noexcept
439 for (
int i = numChars; --i >= 0;)
441 auto digit = (int) (*t -
'0');
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;
506 auto nextChar = t.getAndAdvance();
508 if (nextChar ==
'-' || nextChar ==
'+')
510 auto offsetHours = parseFixedSizeIntAndSkip (t, 2,
':');
515 auto offsetMinutes = parseFixedSizeIntAndSkip (t, 2, 0);
517 if (offsetMinutes < 0)
520 auto offsetMs = (offsetHours * 60 + offsetMinutes) * 60 * 1000;
521 milliseconds += nextChar ==
'-' ? offsetMs : -offsetMs;
523 else if (nextChar != 0 && nextChar !=
'Z')
528 return Time (year, month - 1, day, hours, minutes, 0, milliseconds,
false);
533 return getMonthName (getMonth(), threeLetterVersion);
538 return getWeekdayName (getDayOfWeek(), threeLetterVersion);
541 static const char*
const shortMonthNames[] = {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec" };
542 static const char*
const longMonthNames[] = {
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December" };
548 return TRANS (threeLetterVersion ? shortMonthNames [monthNumber]
549 : longMonthNames [monthNumber]);
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" };
559 return TRANS (threeLetterVersion ? shortDayNames [day]
560 : longDayNames [day]);
579 static int getMonthNumberForCompileDate (
const String& m)
581 for (
int i = 0; i < 12; ++i)
600 return Time (dateTokens[2].getIntValue(),
601 getMonthNumberForCompileDate (dateTokens[0]),
602 dateTokens[1].getIntValue(),
603 timeTokens[0].getIntValue(),
604 timeTokens[1].getIntValue());
616 :
UnitTest (
"Time", UnitTestCategories::time)
619 void runTest()
override 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));
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));
672 static TimeTests timeTests;
bool isDaylightSavingTime() const noexcept
int getDayOfYear() const noexcept
static void waitForMillisecondCounter(uint32 targetTime) noexcept
static RelativeTime days(double numberOfDays) noexcept
bool isNotEmpty() const noexcept
String toString(bool includeDate, bool includeTime, bool includeSeconds=true, bool use24HourClock=false) const
static Time getCompilationDate()
int getDayOfWeek() const noexcept
void removeEmptyStrings(bool removeWhitespaceStrings=true)
String formatted(const String &format) const
String getMonthName(bool threeLetterVersion) const
int getUTCOffsetSeconds() const noexcept
static uint32 getApproximateMillisecondCounter() noexcept
int getMonth() const noexcept
int64 toMilliseconds() const noexcept
static RelativeTime milliseconds(int milliseconds) noexcept
static Time JUCE_CALLTYPE getCurrentTime() noexcept
static int64 currentTimeMillis() noexcept
static void JUCE_CALLTYPE yield()
int addTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
bool equalsIgnoreCase(const String &other) const noexcept
String substring(int startIndex, int endIndex) const
static double highResolutionTicksToSeconds(int64 ticks) noexcept
bool contains(StringRef text) const noexcept
int getMilliseconds() const noexcept
String toISO8601(bool includeDividerCharacters) const
String getTimeZone() const
bool containsIgnoreCase(StringRef text) const noexcept
int getHoursInAmPmFormat() const noexcept
static Time fromISO8601(StringRef iso8601)
int getMinutes() const noexcept
String::CharPointerType text
String getUTCOffsetString(bool includeDividerCharacters) const
static String formatted(const String &formatStr, Args... args)
int getDayOfMonth() const noexcept
int getSeconds() const noexcept
bool isAfternoon() const noexcept
Time & operator-=(RelativeTime delta) noexcept
static void JUCE_CALLTYPE sleep(int milliseconds)
int getHours() const noexcept
int length() const noexcept
Time & operator+=(RelativeTime delta) noexcept
static int64 secondsToHighResolutionTicks(double seconds) noexcept
String getWeekdayName(bool threeLetterVersion) const
int getYear() const noexcept
static uint32 getMillisecondCounter() noexcept