gmtime.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. /*
  2. * Copyright (c) 2019 Peter Bigot Consulting, LLC
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. /*
  7. * The time_civil_from_days function is derived directly from public
  8. * domain content written by Howard Hinnant and available at:
  9. * http://howardhinnant.github.io/date_algorithms.html#civil_from_days
  10. */
  11. #include <time.h>
  12. /* A signed type with the representation of time_t without its
  13. * impliciations.
  14. */
  15. typedef time_t bigint_type;
  16. /** Convert a UNIX time to civil time.
  17. *
  18. * This converts integral seconds since (before) 1970-01-01T00:00:00
  19. * to the POSIX standard civil time representation. Any adjustments
  20. * due to time zone, leap seconds, or a different epoch must be
  21. * applied to @p time before invoking this function.
  22. *
  23. * @param time the time represented as seconds.
  24. *
  25. * @return the time information for corresponding to the provided
  26. * instant.
  27. *
  28. * @see http://howardhinnant.github.io/date_algorithms.html#civil_from_days
  29. */
  30. static void time_civil_from_days(bigint_type z,
  31. struct tm *_MLIBC_RESTRICT tp)
  32. {
  33. tp->tm_wday = (z >= -4) ? ((z + 4) % 7) : ((z + 5) % 7 + 6);
  34. z += 719468;
  35. bigint_type era = ((z >= 0) ? z : (z - 146096)) / 146097;
  36. unsigned int doe = (z - era * (bigint_type)146097);
  37. unsigned int yoe = (doe - doe / 1460U + doe / 36524U - doe / 146096U)
  38. / 365U;
  39. bigint_type y = (time_t)yoe + era * 400;
  40. unsigned int doy = doe - (365U * yoe + yoe / 4U - yoe / 100U);
  41. unsigned int mp = (5U * doy + 2U) / 153U;
  42. unsigned int d = doy - (153U * mp + 2U) / 5U + 1U;
  43. unsigned int m = mp + ((mp < 10) ? 3 : -9);
  44. tp->tm_year = y + (m <= 2) - 1900;
  45. tp->tm_mon = m - 1;
  46. tp->tm_mday = d;
  47. /* Everything above is explained on the referenced page, but
  48. * doy is relative to --03-01 and we need it relative to
  49. * --01-01.
  50. *
  51. * doy=306 corresponds to --01-01, doy=364 to --02-28, and
  52. * doy=365 to --02-29. So we can just subtract 306 to handle
  53. * January and February.
  54. *
  55. * For doy<306 we have to add the number of days before
  56. * --03-01, which is 59 in a common year and 60 in a leap
  57. * year. Note that the first year in the era is a leap year.
  58. */
  59. if (doy >= 306U) {
  60. tp->tm_yday = doy - 306U;
  61. } else {
  62. tp->tm_yday = doy + 59U + (((yoe % 4U == 0U) && (yoe % 100U != 0U)) || (yoe == 0U));
  63. }
  64. }
  65. /* Convert a UNIX time to civil time.
  66. *
  67. * This converts integral seconds since (before) 1970-01-01T00:00:00
  68. * to the POSIX standard civil time representation. Any adjustments
  69. * due to time zone, leap seconds, or a different epoch must be
  70. * applied to @p time before invoking this function.
  71. */
  72. struct tm *gmtime_r(const time_t *_MLIBC_RESTRICT timep,
  73. struct tm *_MLIBC_RESTRICT result)
  74. {
  75. time_t z = *timep;
  76. bigint_type days = (z >= 0 ? z : z - 86399) / 86400;
  77. unsigned int rem = z - days * 86400;
  78. *result = (struct tm){ 0 };
  79. time_civil_from_days(days, result);
  80. result->tm_hour = rem / 60U / 60U;
  81. rem -= result->tm_hour * 60 * 60;
  82. result->tm_min = rem / 60;
  83. result->tm_sec = rem - result->tm_min * 60;
  84. return result;
  85. }
  86. struct tm *gmtime(const time_t *timep)
  87. {
  88. static struct tm shared;
  89. return gmtime_r(timep, &shared);
  90. }