time.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /*
  2. * time.c
  3. *
  4. * Copyright (C) 2021 bzt (bztsrc@gitlab)
  5. *
  6. * Permission is hereby granted, free of charge, to any person
  7. * obtaining a copy of this software and associated documentation
  8. * files (the "Software"), to deal in the Software without
  9. * restriction, including without limitation the rights to use, copy,
  10. * modify, merge, publish, distribute, sublicense, and/or sell copies
  11. * of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be
  15. * included in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. * DEALINGS IN THE SOFTWARE.
  25. *
  26. * This file is part of the POSIX-UEFI package.
  27. * @brief Implementing functions which are defined in time.h
  28. *
  29. */
  30. #include <uefi.h>
  31. static struct tm __tm;
  32. time_t __mktime_efi(efi_time_t *t);
  33. /* from musl */
  34. static uint64_t __year_to_secs(uint64_t year, int *is_leap)
  35. {
  36. int y, cycles, centuries, leaps, rem;
  37. if (year-2ULL <= 136) {
  38. y = (int)year;
  39. leaps = (y-68)>>2;
  40. if (!((y-68)&3)) {
  41. leaps--;
  42. if (is_leap) *is_leap = 1;
  43. } else if (is_leap) *is_leap = 0;
  44. return 31536000ULL*(uint64_t)(y-70) + 86400ULL*(uint64_t)leaps;
  45. }
  46. if (!is_leap) is_leap = &(int){0};
  47. cycles = (int)((year-100) / 400);
  48. rem = (year-100) % 400;
  49. if (rem < 0) {
  50. cycles--;
  51. rem += 400;
  52. }
  53. if (!rem) {
  54. *is_leap = 1;
  55. centuries = 0;
  56. leaps = 0;
  57. } else {
  58. if (rem >= 200) {
  59. if (rem >= 300) { centuries = 3; rem -= 300; }
  60. else { centuries = 2; rem -= 200; }
  61. } else {
  62. if (rem >= 100) { centuries = 1; rem -= 100; }
  63. else centuries = 0;
  64. }
  65. if (!rem) {
  66. *is_leap = 0;
  67. leaps = 0;
  68. } else {
  69. leaps = rem / 4;
  70. rem %= 4;
  71. *is_leap = !rem;
  72. }
  73. }
  74. leaps += 97*cycles + 24*centuries - *is_leap;
  75. return (uint64_t)(year-100) * 31536000ULL + (uint64_t)leaps * 86400ULL + 946684800ULL + 86400ULL;
  76. }
  77. time_t __mktime_efi(efi_time_t *t)
  78. {
  79. __tm.tm_year = t->Year + (/* workaround some buggy firmware*/ t->Year > 2000 ? -1900 : 98);
  80. __tm.tm_mon = t->Month - 1;
  81. __tm.tm_mday = t->Day;
  82. __tm.tm_hour = t->Hour;
  83. __tm.tm_min = t->Minute;
  84. __tm.tm_sec = t->Second;
  85. __tm.tm_isdst = t->Daylight;
  86. return mktime(&__tm);
  87. }
  88. /**
  89. * This isn't POSIX, no arguments. Just returns the current time in struct tm
  90. */
  91. struct tm *localtime (const time_t *__timer)
  92. {
  93. efi_time_t t = {0};
  94. (void)__timer;
  95. ST->RuntimeServices->GetTime(&t, NULL);
  96. __mktime_efi(&t);
  97. return &__tm;
  98. }
  99. time_t mktime(const struct tm *tm)
  100. {
  101. static const uint64_t secs_through_month[] = {
  102. 0, 31*86400, 59*86400, 90*86400,
  103. 120*86400, 151*86400, 181*86400, 212*86400,
  104. 243*86400, 273*86400, 304*86400, 334*86400 };
  105. int is_leap;
  106. uint64_t year = (uint64_t)tm->tm_year, t, adj;
  107. int month = tm->tm_mon;
  108. if (month >= 12 || month < 0) {
  109. adj = (uint64_t)month / 12;
  110. month %= 12;
  111. if (month < 0) {
  112. adj--;
  113. month += 12;
  114. }
  115. year += adj;
  116. }
  117. t = __year_to_secs(year, &is_leap);
  118. t += secs_through_month[month];
  119. if (is_leap && month >= 2) t += 86400;
  120. t += 86400ULL * (uint64_t)(tm->tm_mday-1);
  121. t += 3600ULL * (uint64_t)tm->tm_hour;
  122. t += 60ULL * (uint64_t)tm->tm_min;
  123. t += (uint64_t)tm->tm_sec;
  124. return (time_t)t;
  125. }
  126. time_t time(time_t *__timer)
  127. {
  128. time_t ret;
  129. efi_time_t t = {0};
  130. ST->RuntimeServices->GetTime(&t, NULL);
  131. ret = __mktime_efi(&t);
  132. if(__timer) *__timer = ret;
  133. return ret;
  134. }