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;
224 uint32 juce_millisecondsSinceStartup() noexcept;
226 uint32
Time::getMillisecondCounter() 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();
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
311 << (mins < 10 ?
":0" :
":") << mins;
316 result << (secs < 10 ?
":0" :
":") << secs;
319 if (! use24HourClock)
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); }
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 };
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];
393 if (zone[0].length() > 3
404 return TimeHelpers::getUTCOffsetSeconds (millisSinceEpoch);
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",
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);
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);
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]);
568 Time operator- (Time time, RelativeTime delta) noexcept { Time t (time);
return t -= delta; }
569 Time operator+ (RelativeTime delta, Time time) noexcept { Time t (time);
return t += delta; }
570 const RelativeTime operator- (Time time1, Time time2) noexcept {
return RelativeTime::milliseconds (time1.toMilliseconds() - time2.toMilliseconds()); }
572 bool operator== (Time time1, Time time2) noexcept {
return time1.toMilliseconds() == time2.toMilliseconds(); }
573 bool operator!= (Time time1, Time time2) noexcept {
return time1.toMilliseconds() != time2.toMilliseconds(); }
574 bool operator< (Time time1, Time time2) noexcept {
return time1.toMilliseconds() < time2.toMilliseconds(); }
575 bool operator> (Time time1, Time time2) noexcept {
return time1.toMilliseconds() > time2.toMilliseconds(); }
576 bool operator<= (Time time1, Time time2) noexcept {
return time1.toMilliseconds() <= time2.toMilliseconds(); }
577 bool operator>= (Time time1, Time time2) noexcept {
return time1.toMilliseconds() >= time2.toMilliseconds(); }
579 static int getMonthNumberForCompileDate (
const String& m)
581 for (
int i = 0; i < 12; ++i)
582 if (m.equalsIgnoreCase (shortMonthNames[i]))
600 return Time (dateTokens[2].getIntValue(),
601 getMonthNumberForCompileDate (dateTokens[0]),
602 dateTokens[1].getIntValue(),
603 timeTokens[0].getIntValue(),
604 timeTokens[1].getIntValue());
615 TimeTests() :
UnitTest (
"Time",
"Time") {}
617 void runTest()
override
627 expect (t.getTimeZone().isNotEmpty());
628 expect (t.getUTCOffsetString (
true) ==
"Z" || t.getUTCOffsetString (
true).length() == 6);
629 expect (t.getUTCOffsetString (
false) ==
"Z" || t.getUTCOffsetString (
false).length() == 5);
634 expect (
Time::fromISO8601 (
"2016-02-16") == Time (2016, 1, 16, 0, 0, 0, 0,
false));
635 expect (
Time::fromISO8601 (
"20160216Z") == Time (2016, 1, 16, 0, 0, 0, 0,
false));
636 expect (
Time::fromISO8601 (
"2016-02-16T15:03:57+00:00") == Time (2016, 1, 16, 15, 3, 57, 0,
false));
637 expect (
Time::fromISO8601 (
"20160216T150357+0000") == Time (2016, 1, 16, 15, 3, 57, 0,
false));
638 expect (
Time::fromISO8601 (
"2016-02-16T15:03:57.999+00:00") == Time (2016, 1, 16, 15, 3, 57, 999,
false));
639 expect (
Time::fromISO8601 (
"20160216T150357.999+0000") == Time (2016, 1, 16, 15, 3, 57, 999,
false));
640 expect (
Time::fromISO8601 (
"2016-02-16T15:03:57.999Z") == Time (2016, 1, 16, 15, 3, 57, 999,
false));
641 expect (
Time::fromISO8601 (
"20160216T150357.999Z") == Time (2016, 1, 16, 15, 3, 57, 999,
false));
642 expect (
Time::fromISO8601 (
"2016-02-16T15:03:57.999-02:30") == Time (2016, 1, 16, 17, 33, 57, 999,
false));
643 expect (
Time::fromISO8601 (
"20160216T150357.999-0230") == Time (2016, 1, 16, 17, 33, 57, 999,
false));
645 expect (Time (1970, 0, 1, 0, 0, 0, 0,
false) == Time (0));
646 expect (Time (2106, 1, 7, 6, 28, 15, 0,
false) == Time (4294967295000));
647 expect (Time (2007, 10, 7, 1, 7, 20, 0,
false) == Time (1194397640000));
648 expect (Time (2038, 0, 19, 3, 14, 7, 0,
false) == Time (2147483647000));
649 expect (Time (2016, 2, 7, 11, 20, 8, 0,
false) == Time (1457349608000));
650 expect (Time (1969, 11, 31, 23, 59, 59, 0,
false) == Time (-1000));
651 expect (Time (1901, 11, 13, 20, 45, 53, 0,
false) == Time (-2147483647000));
653 expect (Time (1982, 1, 1, 12, 0, 0, 0,
true) +
RelativeTime::days (365) == Time (1983, 1, 1, 12, 0, 0, 0,
true));
654 expect (Time (1970, 1, 1, 12, 0, 0, 0,
true) +
RelativeTime::days (365) == Time (1971, 1, 1, 12, 0, 0, 0,
true));
655 expect (Time (2038, 1, 1, 12, 0, 0, 0,
true) +
RelativeTime::days (365) == Time (2039, 1, 1, 12, 0, 0, 0,
true));
657 expect (Time (1982, 1, 1, 12, 0, 0, 0,
false) +
RelativeTime::days (365) == Time (1983, 1, 1, 12, 0, 0, 0,
false));
658 expect (Time (1970, 1, 1, 12, 0, 0, 0,
false) +
RelativeTime::days (365) == Time (1971, 1, 1, 12, 0, 0, 0,
false));
659 expect (Time (2038, 1, 1, 12, 0, 0, 0,
false) +
RelativeTime::days (365) == Time (2039, 1, 1, 12, 0, 0, 0,
false));
663 static TimeTests timeTests;