TimeZone.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  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. gmtoff = GMTOffset(&start, t);
  65. gmtoff_start = gmtoff;
  66. /* For each day of the year, calculate the tm_gmtoff. */
  67. for (day = 0; day < 365; day++)
  68. {
  69. t += 3600 * 24;
  70. tt = *localtime(&t);
  71. /* Daylight saving starts or ends here. */
  72. if (GMTOffset(&tt, t) != gmtoff)
  73. {
  74. struct tm tt1;
  75. time_t t1;
  76. /* Try to find the exact hour when daylight saving starts/ends. */
  77. t1 = t;
  78. do
  79. {
  80. t1 -= 3600;
  81. tt1 = *localtime(&t1);
  82. }
  83. while (GMTOffset(&tt1, t1) != gmtoff);
  84. /* Try to find the exact minute when daylight saving starts/ends. */
  85. do
  86. {
  87. t1 += 60;
  88. tt1 = *localtime(&t1);
  89. }
  90. while (GMTOffset(&tt1, t1) == gmtoff);
  91. t1 += gmtoff;
  92. strftime(tzone, sizeof(tzone), "%Z", &tt);
  93. /* Write data, if we're already in daylight saving, we're done. */
  94. if (is_transitioned)
  95. {
  96. if (!start.tm_isdst)
  97. names[0] = tzone;
  98. else
  99. names[1] = tzone;
  100. data[1] = ((int64_t)t1 + TZ_EPOCH_ADJUST) * 10000000L;
  101. return true;
  102. }
  103. else
  104. {
  105. if (!start.tm_isdst)
  106. names[1] = tzone;
  107. else
  108. names[0] = tzone;
  109. data[0] = ((int64_t)t1 + TZ_EPOCH_ADJUST) * 10000000L;
  110. is_transitioned = 1;
  111. }
  112. /* This is only set once when we enter daylight saving. */
  113. if (!*daylight_inverted)
  114. {
  115. data[2] = (int64_t)gmtoff * 10000000L;
  116. data[3] = (int64_t)(GMTOffset(&tt, t) - gmtoff) * 10000000L;
  117. }
  118. else
  119. {
  120. data[2] = (int64_t)(gmtoff_start + (GMTOffset(&tt, t) - gmtoff)) * 10000000L;
  121. data[3] = (int64_t)(gmtoff - GMTOffset(&tt, t)) * 10000000L;
  122. }
  123. gmtoff = GMTOffset(&tt, t);
  124. }
  125. }
  126. if (!is_transitioned)
  127. {
  128. strftime(tzone, sizeof(tzone), "%Z", &tt);
  129. names[0] = tzone;
  130. names[1] = tzone;
  131. data[0] = 0;
  132. data[1] = 0;
  133. data[2] = (int64_t)gmtoff * 10000000L;
  134. data[3] = 0;
  135. *daylight_inverted = false;
  136. }
  137. return true;
  138. }
  139. }
  140. }
  141. #endif