xref: /reactos/sdk/lib/crt/time/mktime.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/mktime.c
5  * PURPOSE:     Implementation of mktime, _mkgmtime
6  * PROGRAMERS:  Timo Kreuzer
7  */
8 #include <precomp.h>
9 #include "bitsfixup.h"
10 
11 #define MAX_32BIT_TIME 0xFFFFFFFFULL
12 
13 static int g_monthdays[13] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
14 
15 __time64_t
mktime_worker(struct tm * ptm,int utc)16 mktime_worker(struct tm * ptm, int utc)
17 {
18     struct tm *ptm2;
19     __time64_t time;
20     int mons, years, leapyears;
21     TIME_ZONE_INFORMATION tzi;
22     DWORD ret;
23 
24     /* Normalize year and month */
25     if (ptm->tm_mon < 0)
26     {
27         mons = -ptm->tm_mon - 1;
28         ptm->tm_year -= 1 + mons / 12;
29         ptm->tm_mon = 11 - (mons % 12);
30     }
31     else if (ptm->tm_mon > 11)
32     {
33         mons = ptm->tm_mon;
34         ptm->tm_year += (mons / 12);
35         ptm->tm_mon = mons % 12;
36     }
37 
38     /* Is it inside margins */
39     if (ptm->tm_year < 70 || ptm->tm_year > 139) // FIXME: max year for 64 bits
40     {
41         return -1;
42     }
43 
44     years = ptm->tm_year - 70;
45 
46     /* Number of leapyears passed since 1970 */
47     leapyears = (years + 1) / 4;
48 
49     /* Calculate days up to 1st of Jan */
50     time = years * 365 + leapyears;
51 
52     /* Calculate days up to 1st of month */
53     time += g_monthdays[ptm->tm_mon];
54 
55     /* Check if we need to add a leap day */
56     if (((years + 2) % 4) == 0)
57     {
58         if (ptm->tm_mon > 2)
59         {
60             time++;
61         }
62     }
63 
64     time += ptm->tm_mday - 1;
65 
66     time *= 24;
67     time += ptm->tm_hour;
68 
69     time *= 60;
70     time += ptm->tm_min;
71 
72     time *= 60;
73     time += ptm->tm_sec;
74 
75     if (time < 0)
76     {
77         return -1;
78     }
79 
80     /* Finally get normalized tm struct */
81     ptm2 = _gmtime64(&time);
82     if (!ptm2)
83     {
84         return -1;
85     }
86     *ptm = *ptm2;
87 
88     /* Finally adjust by the difference to GMT in seconds */
89     ret = GetTimeZoneInformation(&tzi);
90     if (ret != TIME_ZONE_ID_INVALID)
91     {
92         time += tzi.Bias * 60;
93     }
94 
95     return time;
96 }
97 
98 /*    int tm_sec;
99     int tm_min;
100     int tm_hour;
101     int tm_mday;
102     int tm_mon;
103     int tm_year;
104     int tm_wday;
105     int tm_yday;
106     int tm_isdst;
107 */
108 
109 /**
110  * \name _mkgmtime
111  *
112  */
113 time_t
_mkgmtime(struct tm * ptm)114 _mkgmtime(struct tm *ptm)
115 {
116     __time64_t time = mktime_worker(ptm, 1);
117     return (time_t)((time > MAX_32BIT_TIME) ? -1 : time);
118 }
119 
120 time_t
mktime(struct tm * ptm)121 mktime(struct tm *ptm)
122 {
123     __time64_t time = mktime_worker(ptm, 0);
124     return (time_t)((time > MAX_32BIT_TIME) ? -1 : time);
125 }
126 
127 __time32_t
_mkgmtime32(struct tm * ptm)128 _mkgmtime32(struct tm *ptm)
129 {
130     __time64_t time = mktime_worker(ptm, 1);
131     return (__time32_t)((time > MAX_32BIT_TIME) ? -1 : time);
132 }
133 
134 __time32_t
_mktime32(struct tm * ptm)135 _mktime32(struct tm *ptm)
136 {
137     __time64_t time = mktime_worker(ptm, 0);
138     return (__time32_t)((time > MAX_32BIT_TIME) ? -1 : time);
139 }
140 
141 __time64_t
_mkgmtime64(struct tm * ptm)142 _mkgmtime64(struct tm *ptm)
143 {
144     return mktime_worker(ptm, 1);
145 }
146 
147 __time64_t
_mktime64(struct tm * ptm)148 _mktime64(struct tm *ptm)
149 {
150     return mktime_worker(ptm, 0);
151 }
152