Merge lp:~epics-core/epics-base/tzwin32 into lp:~epics-core/epics-base/3.14

Proposed by mdavidsaver
Status: Merged
Merged at revision: 12607
Proposed branch: lp:~epics-core/epics-base/tzwin32
Merge into: lp:~epics-core/epics-base/3.14
Diff against target: 305 lines (+137/-133)
3 files modified
src/libCom/osi/os/WIN32/osdTime.cpp (+16/-133)
src/libCom/test/Makefile (+4/-0)
src/libCom/test/epicsTimeZoneTest.c (+117/-0)
To merge this branch: bzr merge lp:~epics-core/epics-base/tzwin32
Reviewer Review Type Date Requested Status
Andrew Johnson Approve
mdavidsaver Needs Information
Review via email: mp+281122@code.launchpad.net

Description of the change

osdTime: win32 use C89 localtime/gmtime

as recommended by Freddie Akeroyd

To post a comment you must log in.
Revision history for this message
mdavidsaver (mdavidsaver) wrote :

These changes are reported to fix the issue. I've verified with cross-mingw/wine, which also needs to link against -lwinpthread. This change almost falls below the threshold were I wouldn't bother with a merge proposal, but as I don't do much work with win32 I'd like to get it checked/tested by someone who does.

http://www.aps.anl.gov/epics/tech-talk/2015/msg01660.php

review: Needs Information
Revision history for this message
mdavidsaver (mdavidsaver) wrote :

oops, the dependency on winpthread is do to clock_gettime and isn't introduced by this change...

Revision history for this message
Andrew Johnson (anj) wrote :

New tests pass for me on cygwin-x86, windows-x64 (VS2010), windows-x64-mingw (Strawberry Perl 5.16.1) and win32-x86 (VS2010).

I will merge this into the 3.14 branch shortly.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/libCom/osi/os/WIN32/osdTime.cpp'
--- src/libCom/osi/os/WIN32/osdTime.cpp 2015-03-13 15:06:23 +0000
+++ src/libCom/osi/os/WIN32/osdTime.cpp 2015-12-21 16:35:36 +0000
@@ -121,148 +121,31 @@
121 return epicsTimeOK;121 return epicsTimeOK;
122}122}
123123
124inline void UnixTimeToFileTime ( const time_t * pAnsiTime, LPFILETIME pft )
125{
126 LONGLONG ll = Int32x32To64 ( *pAnsiTime, 10000000 ) + LL_CONSTANT(116444736000000000);
127 pft->dwLowDateTime = static_cast < DWORD > ( ll );
128 pft->dwHighDateTime = static_cast < DWORD > ( ll >>32 );
129}
130
131static int daysInMonth[] = { 31, 28, 31, 30, 31, 30, 31,
132 31, 30, 31, 30, 31 };
133
134static bool isLeapYear ( DWORD year )
135{
136 if ( (year % 4) == 0 ) {
137 return ( ( year % 100 ) != 0 || ( year % 400 ) == 0 );
138 } else {
139 return false;
140 }
141}
142
143static int dayOfYear ( DWORD day, DWORD month, DWORD year )
144{
145 DWORD nDays = 0;
146 for ( unsigned m = 1; m < month; m++ ) {
147 nDays += daysInMonth[m-1];
148 if ( m == 2 && isLeapYear(year) ) {
149 nDays++;
150 }
151 }
152 return nDays + day;
153}
154
155// synthesize a reentrant gmtime on WIN32124// synthesize a reentrant gmtime on WIN32
156int epicsShareAPI epicsTime_gmtime ( const time_t *pAnsiTime, struct tm *pTM )125int epicsShareAPI epicsTime_gmtime ( const time_t *pAnsiTime, struct tm *pTM )
157{126{
158 FILETIME ft;127 struct tm * pRet = gmtime ( pAnsiTime );
159 UnixTimeToFileTime ( pAnsiTime, &ft );128 if ( pRet ) {
160129 *pTM = *pRet;
161 SYSTEMTIME st;130 return epicsTimeOK;
162 BOOL status = FileTimeToSystemTime ( &ft, &st );131 }
163 if ( ! status ) {132 else {
164 return epicsTimeERROR;133 return errno;
165 }134 }
166
167 pTM->tm_sec = st.wSecond; // seconds after the minute - [0,59]
168 pTM->tm_min = st.wMinute; // minutes after the hour - [0,59]
169 pTM->tm_hour = st.wHour; // hours since midnight - [0,23]
170 assert ( st.wDay >= 1 && st.wDay <= 31 );
171 pTM->tm_mday = st.wDay; // day of the month - [1,31]
172 assert ( st.wMonth >= 1 && st.wMonth <= 12 );
173 pTM->tm_mon = st.wMonth - 1; // months since January - [0,11]
174 assert ( st.wYear >= 1900 );
175 pTM->tm_year = st.wYear - 1900; // years since 1900
176 pTM->tm_wday = st.wDayOfWeek; // days since Sunday - [0,6]
177 pTM->tm_yday = dayOfYear ( st.wDay, st.wMonth, st.wYear ) - 1;
178 pTM->tm_isdst = 0;
179
180 return epicsTimeOK;
181}135}
182136
183// synthesize a reentrant localtime on WIN32137// synthesize a reentrant localtime on WIN32
184int epicsShareAPI epicsTime_localtime (138int epicsShareAPI epicsTime_localtime (
185 const time_t * pAnsiTime, struct tm * pTM )139 const time_t * pAnsiTime, struct tm * pTM )
186{140{
187 FILETIME ft;141 struct tm * pRet = localtime ( pAnsiTime );
188 UnixTimeToFileTime ( pAnsiTime, & ft );142 if ( pRet ) {
189143 *pTM = *pRet;
190 TIME_ZONE_INFORMATION tzInfo;144 return epicsTimeOK;
191 DWORD tzStatus = GetTimeZoneInformation ( & tzInfo );145 }
192 if ( tzStatus == TIME_ZONE_ID_INVALID ) {146 else {
193 return epicsTimeERROR;147 return errno;
194 }148 }
195
196 //
197 // There are remarkable weaknessess in the FileTimeToLocalFileTime
198 // interface so we dont use it here. Unfortunately, there is no
199 // corresponding function that works on file time.
200 //
201 SYSTEMTIME st;
202 BOOL success = FileTimeToSystemTime ( & ft, & st );
203 if ( ! success ) {
204 return epicsTimeERROR;
205 }
206 SYSTEMTIME lst;
207 success = SystemTimeToTzSpecificLocalTime (
208 & tzInfo, & st, & lst );
209 if ( ! success ) {
210 return epicsTimeERROR;
211 }
212
213 //
214 // We must convert back to file time so that we can determine if DST
215 // is active...
216 //
217 FILETIME lft;
218 success = SystemTimeToFileTime ( & lst, & lft );
219 if ( ! success ) {
220 return epicsTimeERROR;
221 }
222
223 int is_dst = -1; // unknown state of dst
224 if ( tzStatus != TIME_ZONE_ID_UNKNOWN &&
225 tzInfo.StandardDate.wMonth != 0 &&
226 tzInfo.DaylightDate.wMonth != 0) {
227 // determine if the specified date is
228 // in daylight savings time
229 tzInfo.StandardDate.wYear = st.wYear;
230 FILETIME StandardDateFT;
231 success = SystemTimeToFileTime (
232 & tzInfo.StandardDate, & StandardDateFT );
233 if ( ! success ) {
234 return epicsTimeERROR;
235 }
236 tzInfo.DaylightDate.wYear = st.wYear;
237 FILETIME DaylightDateFT;
238 success = SystemTimeToFileTime (
239 & tzInfo.DaylightDate, & DaylightDateFT );
240 if ( ! success ) {
241 return epicsTimeERROR;
242 }
243 if ( CompareFileTime ( & lft, & DaylightDateFT ) >= 0
244 && CompareFileTime ( & lft, & StandardDateFT ) < 0 ) {
245 is_dst = 1;
246 }
247 else {
248 is_dst = 0;
249 }
250 }
251
252 pTM->tm_sec = lst.wSecond; // seconds after the minute - [0,59]
253 pTM->tm_min = lst.wMinute; // minutes after the hour - [0,59]
254 pTM->tm_hour = lst.wHour; // hours since midnight - [0,23]
255 assert ( lst.wDay >= 1 && lst.wDay <= 31 );
256 pTM->tm_mday = lst.wDay; // day of the month - [1,31]
257 assert ( lst.wMonth >= 1 && lst.wMonth <= 12 );
258 pTM->tm_mon = lst.wMonth - 1; // months since January - [0,11]
259 assert ( lst.wYear >= 1900 );
260 pTM->tm_year = lst.wYear - 1900; // years since 1900
261 pTM->tm_wday = lst.wDayOfWeek; // days since Sunday - [0,6]
262 pTM->tm_yday = dayOfYear ( lst.wDay, lst.wMonth, lst.wYear ) - 1;
263 pTM->tm_isdst = is_dst;
264
265 return epicsTimeOK;
266}149}
267150
268currentTime::currentTime () :151currentTime::currentTime () :
269152
=== modified file 'src/libCom/test/Makefile'
--- src/libCom/test/Makefile 2013-12-16 18:48:25 +0000
+++ src/libCom/test/Makefile 2015-12-21 16:35:36 +0000
@@ -68,6 +68,10 @@
68testHarness_SRCS += epicsTimeTest.cpp68testHarness_SRCS += epicsTimeTest.cpp
69TESTS += epicsTimeTest69TESTS += epicsTimeTest
7070
71TESTPROD_HOST += epicsTimeZoneTest
72epicsTimeZoneTest_SRCS += epicsTimeZoneTest.c
73TESTS += epicsTimeZoneTest
74
71TESTPROD_HOST += epicsThreadTest75TESTPROD_HOST += epicsThreadTest
72epicsThreadTest_SRCS += epicsThreadTest.cpp76epicsThreadTest_SRCS += epicsThreadTest.cpp
73testHarness_SRCS += epicsThreadTest.cpp77testHarness_SRCS += epicsThreadTest.cpp
7478
=== added file 'src/libCom/test/epicsTimeZoneTest.c'
--- src/libCom/test/epicsTimeZoneTest.c 1970-01-01 00:00:00 +0000
+++ src/libCom/test/epicsTimeZoneTest.c 2015-12-21 16:35:36 +0000
@@ -0,0 +1,117 @@
1/*************************************************************************\
2* Copyright (c) 2015 Michael Davidsaver
3* EPICS BASE is distributed subject to a Software License Agreement found
4* in file LICENSE that is included with this distribution.
5\*************************************************************************/
6
7#include <stdio.h>
8
9#include "envDefs.h"
10#include "epicsTime.h"
11#include "epicsUnitTest.h"
12
13#include "testMain.h"
14
15#if defined(_WIN32)
16# define tzset _tzset
17#endif
18
19static
20void setTZ(const char *base, const char *dst, int offset)
21{
22 char tz[20];
23 if(offset!=0 || dst)
24 sprintf(tz, "%s%d%s", base, offset/3600, dst);
25 else
26 sprintf(tz, "%s", base);
27 testDiag("TZ=\"%s\"", tz);
28
29 epicsEnvSet("TZ", tz);
30 tzset();
31}
32
33static
34void test_localtime(time_t T, int sec, int min, int hour,
35 int mday, int mon, int year,
36 int wday, int yday, int isdst)
37{
38 struct tm B;
39 testDiag("test_localtime(%ld, ...)", (long)T);
40 if(epicsTime_localtime(&T, &B)!=epicsTimeOK) {
41 testFail("epicsTime_localtime() error");
42 testSkip(9, "epicsTime_localtime() failed");
43 } else {
44 B.tm_year += 1900; /* for readability */
45 testPass("epicsTime_localtime() success");
46#define TEST(FLD) testOk(B.tm_##FLD==FLD, "%s %d==%d", #FLD, B.tm_##FLD, FLD)
47 TEST(sec);
48 TEST(min);
49 TEST(hour);
50 TEST(mday);
51 TEST(mon);
52 TEST(year);
53 TEST(wday);
54 TEST(yday);
55 TEST(isdst);
56#undef TEST
57 }
58}
59
60static
61void test_gmtime(time_t T, int sec, int min, int hour,
62 int mday, int mon, int year,
63 int wday, int yday, int isdst)
64{
65 struct tm B;
66 testDiag("test_gmtime(%ld, ...)", (long)T);
67 if(epicsTime_gmtime(&T, &B)!=epicsTimeOK) {
68 testFail("epicsTime_localtime() error");
69 testSkip(9, "epicsTime_localtime() failed");
70 } else {
71 B.tm_year += 1900; /* for readability */
72 testPass("epicsTime_localtime() success");
73#define TEST(FLD) testOk(B.tm_##FLD==FLD, "%s %d==%d", #FLD, B.tm_##FLD, FLD)
74 TEST(sec);
75 TEST(min);
76 TEST(hour);
77 TEST(mday);
78 TEST(mon);
79 TEST(year);
80 TEST(wday);
81 TEST(yday);
82 TEST(isdst);
83#undef TEST
84 }
85}
86
87MAIN(epicsTimeZoneTest)
88{
89 testPlan(80);
90 /* 1445259616
91 * Mon Oct 19 09:00:16 2015 EDT
92 * Mon Oct 19 08:00:16 2015 CDT
93 * Mon Oct 19 13:00:16 2015 UTC
94 */
95 testDiag("POSIX 1445259616");
96 setTZ("EST", "EDT", 5*3600);
97 test_localtime(1445259616ul, 16, 0, 9, 19, 9, 2015, 1, 291, 1);
98 setTZ("CST", "CDT", 6*3600);
99 test_localtime(1445259616ul, 16, 0, 8, 19, 9, 2015, 1, 291, 1);
100 setTZ("UTC", NULL, 0);
101 test_localtime(1445259616ul, 16, 0, 13, 19, 9, 2015, 1, 291, 0);
102 test_gmtime(1445259616ul, 16, 0, 13, 19, 9, 2015, 1, 291, 0);
103 /* 1421244931
104 * Wed Jan 14 09:15:31 2015 EST
105 * Wed Jan 14 08:15:31 2015 CST
106 * Wed Jan 14 14:15:31 2015 UTC
107 */
108 testDiag("POSIX 1421244931");
109 setTZ("EST", "EDT", 5*3600);
110 test_localtime(1421244931ul, 31, 15, 9, 14, 0, 2015, 3, 13, 0);
111 setTZ("CST", "CDT", 6*3600);
112 test_localtime(1421244931ul, 31, 15, 8, 14, 0, 2015, 3, 13, 0);
113 setTZ("UTC", NULL, 0);
114 test_localtime(1421244931ul, 31, 15, 14, 14, 0, 2015, 3, 13, 0);
115 test_gmtime(1421244931ul, 31, 15, 14, 14, 0, 2015, 3, 13, 0);
116 return testDone();
117}

Subscribers

People subscribed via source and target branches