TimeZone.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #include "il2cpp-config.h"
  2. #if IL2CPP_TARGET_POSIX && !RUNTIME_TINY
  3. #include "os/TimeZone.h"
  4. #include <sys/time.h>
  5. #include <time.h>
  6. namespace il2cpp
  7. {
  8. namespace os
  9. {
  10. /*
  11. * Magic number to convert a time which is relative to
  12. * Jan 1, 1970 into a value which is relative to Jan 1, 0001.
  13. */
  14. const uint64_t TZ_EPOCH_ADJUST = ((uint64_t)62135596800LL);
  15. /*
  16. * Return's the offset from GMT of a local time.
  17. *
  18. * tm is a local time
  19. * t is the same local time as seconds.
  20. */
  21. static int
  22. GMTOffset(struct tm *tm, time_t t)
  23. {
  24. #if defined(HAVE_TM_GMTOFF)
  25. return tm->tm_gmtoff;
  26. #else
  27. struct tm g;
  28. time_t t2;
  29. g = *gmtime(&t);
  30. g.tm_isdst = tm->tm_isdst;
  31. t2 = mktime(&g);
  32. return (int)difftime(t, t2);
  33. #endif
  34. }
  35. bool TimeZone::GetTimeZoneData(int32_t year, int64_t data[4], std::string names[2], bool* daylight_inverted)
  36. {
  37. struct tm start, tt;
  38. time_t t;
  39. long int gmtoff, gmtoff_start;
  40. int is_transitioned = 0, day;
  41. char tzone[64];
  42. /*
  43. * no info is better than crashing: we'll need our own tz data
  44. * to make this work properly, anyway. The range is probably
  45. * reduced to 1970 .. 2037 because that is what mktime is
  46. * guaranteed to support (we get into an infinite loop
  47. * otherwise).
  48. */
  49. memset(&start, 0, sizeof(start));
  50. start.tm_mday = 1;
  51. start.tm_year = year - 1900;
  52. t = mktime(&start);
  53. if ((year < 1970) || (year > 2037) || (t == -1))
  54. {
  55. t = time(NULL);
  56. tt = *localtime(&t);
  57. strftime(tzone, sizeof(tzone), "%Z", &tt);
  58. names[0] = tzone;
  59. names[1] = tzone;
  60. *daylight_inverted = false;
  61. return true;
  62. }
  63. *daylight_inverted = start.tm_isdst;
  64. #ifdef DO_NOT_CALCULATE_DST_FOR_GMT_AND_UTC
  65. // If we got here then probably there is no tz database in the system.
  66. // The default time zone is GMT which has no daylight saving time (same for UTC).
  67. tt = *localtime(&t);
  68. strftime(tzone, sizeof(tzone), "%Z", &tt);
  69. if (tzone[0] == 0 || memcmp(tzone, "GMT", 3) == 0 || memcmp(tzone, "UTC", 3) == 0)
  70. {
  71. names[0] = tzone;
  72. names[1] = tzone;
  73. return true;
  74. }
  75. #endif // DO_NOT_CALCULATE_DST_FOR_GMT_AND_UTC
  76. gmtoff = GMTOffset(&start, t);
  77. gmtoff_start = gmtoff;
  78. /* For each day of the year, calculate the tm_gmtoff. */
  79. for (day = 0; day < 365; day++)
  80. {
  81. t += 3600 * 24;
  82. tt = *localtime(&t);
  83. /* Daylight saving starts or ends here. */
  84. if (GMTOffset(&tt, t) != gmtoff)
  85. {
  86. struct tm tt1;
  87. time_t t1;
  88. /* Try to find the exact hour when daylight saving starts/ends. */
  89. t1 = t;
  90. do
  91. {
  92. t1 -= 3600;
  93. tt1 = *localtime(&t1);
  94. }
  95. while (GMTOffset(&tt1, t1) != gmtoff);
  96. /* Try to find the exact minute when daylight saving starts/ends. */
  97. do
  98. {
  99. t1 += 60;
  100. tt1 = *localtime(&t1);
  101. }
  102. while (GMTOffset(&tt1, t1) == gmtoff);
  103. t1 += gmtoff;
  104. strftime(tzone, sizeof(tzone), "%Z", &tt);
  105. /* Write data, if we're already in daylight saving, we're done. */
  106. if (is_transitioned)
  107. {
  108. if (!start.tm_isdst)
  109. names[0] = tzone;
  110. else
  111. names[1] = tzone;
  112. data[1] = ((int64_t)t1 + TZ_EPOCH_ADJUST) * 10000000L;
  113. return true;
  114. }
  115. else
  116. {
  117. if (!start.tm_isdst)
  118. names[1] = tzone;
  119. else
  120. names[0] = tzone;
  121. data[0] = ((int64_t)t1 + TZ_EPOCH_ADJUST) * 10000000L;
  122. is_transitioned = 1;
  123. }
  124. /* This is only set once when we enter daylight saving. */
  125. if (!*daylight_inverted)
  126. {
  127. data[2] = (int64_t)gmtoff * 10000000L;
  128. data[3] = (int64_t)(GMTOffset(&tt, t) - gmtoff) * 10000000L;
  129. }
  130. else
  131. {
  132. data[2] = (int64_t)(gmtoff_start + (GMTOffset(&tt, t) - gmtoff)) * 10000000L;
  133. data[3] = (int64_t)(gmtoff - GMTOffset(&tt, t)) * 10000000L;
  134. }
  135. gmtoff = GMTOffset(&tt, t);
  136. }
  137. }
  138. if (!is_transitioned)
  139. {
  140. strftime(tzone, sizeof(tzone), "%Z", &tt);
  141. names[0] = tzone;
  142. names[1] = tzone;
  143. data[0] = 0;
  144. data[1] = 0;
  145. data[2] = (int64_t)gmtoff * 10000000L;
  146. data[3] = 0;
  147. *daylight_inverted = false;
  148. }
  149. return true;
  150. }
  151. }
  152. }
  153. #endif