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

Subscribers

People subscribed via source and target branches