xref: /reactos/sdk/lib/crt/time/gmtime.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:   LGPL, See LGPL.txt in the top level directory
3  * PROJECT:     ReactOS CRT library
4  * FILE:        lib/sdk/crt/time/gmtime.c
5  * PURPOSE:     Implementation of gmtime, _gmtime32, _gmtime64
6  * PROGRAMERS:  Timo Kreuzer
7  */
8 #include <precomp.h>
9 
10 unsigned int g_monthdays[13] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
11 unsigned int g_lpmonthdays[13] = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366};
12 
13 struct tm *
_gmtime_worker(struct tm * ptm,__time64_t time,int do_dst)14 _gmtime_worker(struct tm *ptm, __time64_t time, int do_dst)
15 {
16     unsigned int days, daystoyear, dayinyear, leapdays, leapyears, years, month;
17     unsigned int secondinday, secondinhour;
18     unsigned int *padays;
19 
20     if (time < 0)
21     {
22         return 0;
23     }
24 
25     /* Divide into date and time */
26     days = (unsigned int)(time / SECONDSPERDAY);
27     secondinday = time % SECONDSPERDAY;
28 
29     /* Shift to days from 1.1.1601 */
30     days += DIFFDAYS;
31 
32     /* Calculate leap days passed till today */
33     leapdays = leapdays_passed(days);
34 
35     /* Calculate number of full leap years passed */
36     leapyears = leapyears_passed(days);
37 
38     /* Are more leap days passed than leap years? */
39     if (leapdays > leapyears)
40     {
41         /* Yes, we're in a leap year */
42         padays = g_lpmonthdays;
43     }
44     else
45     {
46         /* No, normal year */
47         padays = g_monthdays;
48     }
49 
50     /* Calculate year */
51     years = (days - leapdays) / 365;
52     ptm->tm_year = years - 299;
53 
54     /* Calculate number of days till 1.1. of this year */
55     daystoyear = years * 365 + leapyears;
56 
57     /* Calculate the day in this year */
58     dayinyear = days - daystoyear;
59 
60     /* Shall we do DST corrections? */
61     ptm->tm_isdst = 0;
62     if (do_dst)
63     {
64         int yeartime = dayinyear * SECONDSPERDAY + secondinday ;
65         if (yeartime >= dst_begin && yeartime <= dst_end) // FIXME! DST in winter
66         {
67             time -= _dstbias;
68             days = (unsigned int)(time / SECONDSPERDAY + DIFFDAYS);
69             dayinyear = days - daystoyear;
70             ptm->tm_isdst = 1;
71         }
72     }
73 
74     ptm->tm_yday = dayinyear;
75 
76     /* dayinyear < 366 => terminates with i <= 11 */
77     for (month = 0; dayinyear >= padays[month+1]; month++)
78         ;
79 
80     /* Set month and day in month */
81     ptm->tm_mon = month;
82     ptm->tm_mday = 1 + dayinyear - padays[month];
83 
84     /* Get weekday */
85     ptm->tm_wday = (days + 1) % 7;
86 
87     /* Calculate hour and second in hour */
88     ptm->tm_hour = secondinday / SECONDSPERHOUR;
89     secondinhour = secondinday % SECONDSPERHOUR;
90 
91     /* Calculate minute and second */
92     ptm->tm_min = secondinhour / 60;
93     ptm->tm_sec = secondinhour % 60;
94 
95     return ptm;
96 }
97 
98 /******************************************************************************
99  * \name _gmtime64
100  * \brief
101  * \param ptime Pointer to a variable of type __time64_t containing the time.
102  */
103 struct tm *
_gmtime64(const __time64_t * ptime)104 _gmtime64(const __time64_t * ptime)
105 {
106     thread_data_t *data = msvcrt_get_thread_data();
107 
108     /* Validate parameters */
109     if (!ptime || *ptime < 0)
110     {
111         return NULL;
112     }
113 
114     if(!data->time_buffer)
115         data->time_buffer = malloc(sizeof(struct tm));
116 
117     /* Use _gmtime_worker to do the real work */
118     return _gmtime_worker(data->time_buffer, *ptime, 0);
119 }
120 
121 errno_t
_gmtime64_s(struct tm * ptm,const __time64_t * ptime)122 _gmtime64_s(
123    struct tm* ptm,
124    const __time64_t* ptime)
125 {
126     __time64_t time;
127 
128     if (!ptm)
129     {
130         MSVCRT_INVALID_PMT("ptm == NULL", ERROR_BAD_COMMAND);
131         return ERROR_BAD_COMMAND;
132     }
133 
134     if (!ptime)
135     {
136         MSVCRT_INVALID_PMT("ptime == NULL", ERROR_BAD_COMMAND);
137         return ERROR_BAD_COMMAND;
138     }
139 
140     time = *ptime;
141 
142     _gmtime_worker(ptm, time, 0);
143 
144     return ERROR_SUCCESS;
145 }
146 
147 /******************************************************************************
148  * \name _gmtime32
149  * \brief
150  * \param ptime Pointer to a variable of type __time32_t containing the time.
151  */
152 struct tm *
_gmtime32(const __time32_t * ptime)153 _gmtime32(const __time32_t * ptime)
154 {
155     __time64_t time64;
156 
157     if (!ptime)
158         return NULL;
159     time64 = *ptime;
160     return _gmtime64(&time64);
161 }
162 
163 errno_t
_gmtime32_s(struct tm * ptm,const __time32_t * ptime)164 _gmtime32_s(
165    struct tm* ptm,
166    const __time32_t* ptime)
167 {
168     __time64_t time = *ptime;
169     if (!ptm)
170     {
171         MSVCRT_INVALID_PMT("ptm == NULL", ERROR_BAD_COMMAND);
172         return ERROR_BAD_COMMAND;
173     }
174 
175     if (!ptime)
176     {
177         MSVCRT_INVALID_PMT("ptime == NULL", ERROR_BAD_COMMAND);
178         return ERROR_BAD_COMMAND;
179     }
180 
181     _gmtime_worker(ptm, time, 0);
182 
183     return ERROR_SUCCESS;
184 }
185 
186 /******************************************************************************
187  * \name gmtime
188  * \brief
189  * \param ptime Pointer to a variable of type time_t containing the time.
190  */
191 struct tm *
gmtime(const time_t * ptime)192 gmtime(const time_t * ptime)
193 {
194     __time64_t time64;
195 
196     if (!ptime)
197         return NULL;
198     time64 = *ptime;
199     return _gmtime64(&time64);
200 }
201