offtime.c 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. /* Copyright (C) 1991-2026 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. The GNU C Library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public
  5. License as published by the Free Software Foundation; either
  6. version 2.1 of the License, or (at your option) any later version.
  7. The GNU C Library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public
  12. License along with the GNU C Library; if not, see
  13. <https://www.gnu.org/licenses/>. */
  14. #include <errno.h>
  15. #include <time.h>
  16. #define SECS_PER_HOUR (60 * 60)
  17. #define SECS_PER_DAY (SECS_PER_HOUR * 24)
  18. /* Compute the `struct tm' representation of T,
  19. offset OFFSET seconds east of UTC,
  20. and store year, yday, mon, mday, wday, hour, min, sec into *TP.
  21. Return nonzero if successful. */
  22. int
  23. __offtime (__time64_t t, long int offset, struct tm *tp)
  24. {
  25. __time64_t days, rem, y;
  26. const unsigned short int *ip;
  27. days = t / SECS_PER_DAY;
  28. rem = t % SECS_PER_DAY;
  29. rem += offset;
  30. while (rem < 0)
  31. {
  32. rem += SECS_PER_DAY;
  33. --days;
  34. }
  35. while (rem >= SECS_PER_DAY)
  36. {
  37. rem -= SECS_PER_DAY;
  38. ++days;
  39. }
  40. tp->tm_hour = rem / SECS_PER_HOUR;
  41. rem %= SECS_PER_HOUR;
  42. tp->tm_min = rem / 60;
  43. tp->tm_sec = rem % 60;
  44. /* January 1, 1970 was a Thursday. */
  45. tp->tm_wday = (4 + days) % 7;
  46. if (tp->tm_wday < 0)
  47. tp->tm_wday += 7;
  48. y = 1970;
  49. #define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
  50. #define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
  51. while (days < 0 || days >= (__isleap (y) ? 366 : 365))
  52. {
  53. /* Guess a corrected year, assuming 365 days per year. */
  54. __time64_t yg = y + days / 365 - (days % 365 < 0);
  55. /* Adjust DAYS and Y to match the guessed year. */
  56. days -= ((yg - y) * 365
  57. + LEAPS_THRU_END_OF (yg - 1)
  58. - LEAPS_THRU_END_OF (y - 1));
  59. y = yg;
  60. }
  61. tp->tm_year = y - 1900;
  62. if (tp->tm_year != y - 1900)
  63. {
  64. /* The year cannot be represented due to overflow. */
  65. __set_errno (EOVERFLOW);
  66. return 0;
  67. }
  68. tp->tm_yday = days;
  69. ip = __mon_yday[__isleap(y)];
  70. for (y = 11; days < (long int) ip[y]; --y)
  71. continue;
  72. days -= ip[y];
  73. tp->tm_mon = y;
  74. tp->tm_mday = days + 1;
  75. return 1;
  76. }