1 /*
2 * Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 * of conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "tzdst.h"
33 #include "tzdst_pri.h"
34 #include "stdio.h"
35 #include "stdlib.h"
36 #include "unistd.h"
37 #include "los_printf.h"
38 #include "los_typedef.h"
39 #include "securec.h"
40
41
42 /* 2: leap year or normal year */
43 STATIC const INT32 g_monLengths[2][MONSPERYEAR] = {
44 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
45 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
46 };
47
48 /* Time Zone functions */
49 #define IS_NUM(x) (((x) >= '0') && ((x) <= '9'))
50
51 long int timezone;
52
BufferInsert(CHAR * buf,size_t bufLen,size_t positions,CHAR data)53 STATIC VOID BufferInsert(CHAR *buf, size_t bufLen, size_t positions, CHAR data)
54 {
55 if (bufLen <= positions) {
56 return;
57 }
58 if (memmove_s(&buf[positions + 1], bufLen - positions - 1, &buf[positions], bufLen - positions - 1) != EOK) {
59 PRINTK("%s falied \n", __FUNCTION__);
60 return;
61 }
62
63 buf[positions] = data;
64 }
65
66 #define OPERATE_OFF 3
67 #define HOUR_HIGH_OFF 4
68 #define HOUR_LOW_OFF 5
69 #define MIN_HIGH_OFF 7
70 #define MIN_LOW_OFF 8
71 #define SEC_HIGH_OFF 10
72 #define SEC_LOW_OFF 11
73
74 /*
75 * tzn[+/-]hh[:mm[:ss]][dzn]
76 * tzn + 11 :30 : 7 dzn
77 * tzn - 9 : 7 :11 dzn
78 */
TimezoneFormat(CHAR * standardString,size_t bufLen)79 STATIC BOOL TimezoneFormat(CHAR *standardString, size_t bufLen)
80 {
81 if ((standardString[OPERATE_OFF] == '-') || (standardString[OPERATE_OFF] == '+')) {
82 if (!IS_NUM(standardString[OPERATE_OFF + 1])) {
83 return FALSE;
84 }
85 } else if (IS_NUM(standardString[OPERATE_OFF])) {
86 BufferInsert(standardString, bufLen, OPERATE_OFF, '+'); /* no operate is default to add */
87 } else {
88 return FALSE;
89 }
90
91 if (!IS_NUM(standardString[HOUR_LOW_OFF])) {
92 BufferInsert(standardString, bufLen, HOUR_HIGH_OFF, '0'); /* hour only one bit, padding 0 to high bit */
93 }
94
95 if (standardString[HOUR_LOW_OFF + 1] == ':') {
96 if (!IS_NUM(standardString[MIN_HIGH_OFF])) {
97 return FALSE;
98 } else if (!IS_NUM(standardString[MIN_LOW_OFF])) {
99 BufferInsert(standardString, bufLen, MIN_HIGH_OFF, '0'); /* minute only one bit, padding 0 to high bit */
100 }
101 } else {
102 /* no minute bits, default is 0 */
103 BufferInsert(standardString, bufLen, HOUR_LOW_OFF + 1, ':');
104 BufferInsert(standardString, bufLen, MIN_HIGH_OFF, '0');
105 BufferInsert(standardString, bufLen, MIN_LOW_OFF, '0');
106 }
107
108 if (standardString[MIN_LOW_OFF + 1] == ':') {
109 if (!IS_NUM(standardString[SEC_HIGH_OFF])) {
110 return FALSE;
111 } else if (!IS_NUM(standardString[SEC_LOW_OFF])) {
112 BufferInsert(standardString, bufLen, SEC_HIGH_OFF, '0'); /* second only one bit, padding 0 to high bit */
113 }
114 } else {
115 /* no second bits, default is 0 */
116 BufferInsert(standardString, bufLen, MIN_LOW_OFF + 1, ':');
117 BufferInsert(standardString, bufLen, SEC_HIGH_OFF, '0');
118 BufferInsert(standardString, bufLen, SEC_LOW_OFF, '0');
119 }
120 return TRUE;
121 }
122
StringToDigital(CHAR high,CHAR low)123 STATIC INLINE INT32 StringToDigital(CHAR high, CHAR low)
124 {
125 /* 10: decimal base number */
126 return ((high - '0') * 10) + (low - '0');
127 }
128
129 /*
130 * tzn[+/-]hh[:mm[:ss]][dzn]
131 * tzn + 11 :30 : 7 dzn
132 * tzn - 9 : 7 :11 dzn
133 */
settimezone(const char * buff)134 void settimezone(const char *buff)
135 {
136 #define STANDARD_TZ_LEN 15
137 #define MIN_BUF_LEN (OPERATE_OFF + 1)
138 INT32 hour;
139 INT32 minute;
140 INT32 second;
141 size_t buffLen;
142 CHAR standardString[STANDARD_TZ_LEN] = {0};
143
144 if (buff == NULL) {
145 goto ERROR;
146 }
147
148 buffLen = strlen(buff);
149 if (buffLen < MIN_BUF_LEN) {
150 goto ERROR;
151 }
152
153 (VOID)memset_s(standardString, STANDARD_TZ_LEN, '#', STANDARD_TZ_LEN);
154 if (memcpy_s(standardString, STANDARD_TZ_LEN, buff, buffLen) != EOK) {
155 goto ERROR;
156 }
157
158 if (!TimezoneFormat(standardString, STANDARD_TZ_LEN)) {
159 goto ERROR;
160 }
161
162 hour = StringToDigital(standardString[HOUR_HIGH_OFF], standardString[HOUR_LOW_OFF]);
163 minute = StringToDigital(standardString[MIN_HIGH_OFF], standardString[MIN_LOW_OFF]);
164 second = StringToDigital(standardString[SEC_HIGH_OFF], standardString[SEC_LOW_OFF]);
165 /* [-12:00:00, +14:00:00] limits */
166 if ((minute > 59 || second > 59) ||
167 ((standardString[OPERATE_OFF] == '-') && ((hour > 12) || ((hour == 12) && ((minute != 0) || (second != 0))))) ||
168 ((standardString[OPERATE_OFF] == '+') && ((hour > 14) || ((hour == 14) && ((minute != 0) || (second != 0)))))) {
169 goto ERROR;
170 }
171
172 if (lock()) {
173 goto ERROR;
174 }
175
176 /* 1h: 3600s, 1min: 60s */
177 timezone = hour * 3600 + minute * 60 + second;
178 if (standardString[OPERATE_OFF] == '-') {
179 timezone = -timezone;
180 }
181
182 unlock();
183
184 return;
185
186 ERROR:
187 PRINT_ERR("TZ file data error\n");
188 }
189
190 /* DST functions */
191 #define DST_STR_LEN_FORMAT_MDAY 15 /* for example "Feb-03 03:00:00" */
192 #define DST_STR_LEN_FORMAT_WDAY 20 /* for example "Oct-1st-Fri 02:59:59" */
193 #define DST_SET_LENGTH_MAX (DST_STR_LEN_FORMAT_WDAY + 1)
194
195 #define MONTH_NAME_LEN 3
196 STATIC const CHAR *g_strMonth[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
197 "Aug", "Sep", "Oct", "Nov", "Dec" };
198 STATIC const CHAR *g_strMonthWeek[] = { "1st", "2nd", "3rd", "4th", "5th" };
199 STATIC const CHAR *g_strWeekDay[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
200
201 STATIC BOOL g_isDstWork = FALSE;
202 INT32 g_dstForwardSeconds = 0;
203 STATIC CHAR g_strDstStart[DST_SET_LENGTH_MAX] = {0};
204 STATIC CHAR g_strDstEnd[DST_SET_LENGTH_MAX] = {0};
205
DstForwardSecondGet(VOID)206 INT32 DstForwardSecondGet(VOID)
207 {
208 return g_dstForwardSeconds;
209 }
210
GetMonthFromString(const CHAR * strMonth)211 STATIC INT32 GetMonthFromString(const CHAR *strMonth)
212 {
213 UINT32 index;
214 for (index = 0; index < sizeof(g_strMonth) / sizeof(CHAR *); index++) {
215 if (strncmp(strMonth, g_strMonth[index], MONTH_NAME_LEN) == 0) {
216 /* A legal month is from 0 to 11. */
217 return (int)index;
218 }
219 }
220
221 return -1;
222 }
223
GetWeekDayFromString(const CHAR * strWeekDay)224 STATIC INT32 GetWeekDayFromString(const CHAR *strWeekDay)
225 {
226 UINT32 index;
227 for (index = 0; index < sizeof(g_strWeekDay) / sizeof(CHAR *); index++) {
228 if (strncmp(strWeekDay, g_strWeekDay[index], MONTH_NAME_LEN) == 0) {
229 /* Day of the week (0-6, Sunday = 0) */
230 return (INT32)index;
231 }
232 }
233
234 return -1;
235 }
236
GetMonthWeekFromString(const CHAR * strMonthWeek)237 STATIC INT32 GetMonthWeekFromString(const CHAR *strMonthWeek)
238 {
239 UINT32 index;
240 for (index = 0; index < sizeof(g_strMonthWeek) / sizeof(CHAR *); index++) {
241 if (strncmp(strMonthWeek, g_strMonthWeek[index], MONTH_NAME_LEN) == 0) {
242 /* Month of the week (1-5) */
243 return (INT32)(index + 1);
244 }
245 }
246
247 return -1;
248 }
249
250 /* Day of the month 1 ~ 31 */
GetMonthDayFromString(INT32 month,const CHAR * strMonDay)251 STATIC INT32 GetMonthDayFromString(INT32 month, const CHAR *strMonDay)
252 {
253 INT32 monDay;
254
255 if (((strMonDay[0] < '0') || (strMonDay[0] > '9')) ||
256 ((strMonDay[1] < '0') || (strMonDay[1] > '9'))) {
257 return -1;
258 }
259
260 monDay = StringToDigital(strMonDay[0], strMonDay[1]);
261 if (monDay > 31) {
262 return -1;
263 }
264
265 /* Not every year have 29 days in Feb when set DST. */
266 if ((monDay == 29) && ((month + 1) == 2)) {
267 return -1;
268 }
269
270 if (monDay > g_monLengths[0][month]) {
271 return -1;
272 }
273
274 /* Day of the month (1-31) */
275 return monDay;
276 }
277
278 /*
279 * time format HH:MM:SS
280 * index 01234567
281 * 0~23 for hours per day
282 * 0~59 for minutes per hour
283 * 0~59 for seconds per minute
284 */
GetDaySecondsFromString(const CHAR * strTimeString)285 STATIC INT32 GetDaySecondsFromString(const CHAR *strTimeString)
286 {
287 INT32 hour, min, sec;
288
289 if (((strTimeString[0] < '0') || (strTimeString[0] > '9')) ||
290 ((strTimeString[1] < '0') || (strTimeString[1] > '9'))) {
291 return -1;
292 }
293
294 if (((strTimeString[3] < '0') || (strTimeString[3] > '9')) ||
295 ((strTimeString[4] < '0') || (strTimeString[4] > '9'))) {
296 return -1;
297 }
298
299 if (((strTimeString[6] < '0') || (strTimeString[6] > '9')) ||
300 ((strTimeString[7] < '0') || (strTimeString[7] > '9'))) {
301 return -1;
302 }
303
304 if ((strTimeString[2] != ':') || (strTimeString[5] != ':')) {
305 return -1;
306 }
307
308 hour = StringToDigital(strTimeString[0], strTimeString[1]);
309 min = StringToDigital(strTimeString[3], strTimeString[4]);
310 sec = StringToDigital(strTimeString[6], strTimeString[7]);
311 /* Hours (0-23) */
312 if ((hour < 0) || (hour > 23)) {
313 return -1;
314 }
315
316 /* Minutes (0-59) */
317 if ((min < 0) || (min > 59)) {
318 return -1;
319 }
320
321 /* Seconds (0-59), not consider of the leap seconds in DST. */
322 if ((sec < 0) || (sec > 59)) {
323 return -1;
324 }
325 /* 1h: 3600s, 1min: 60s */
326 return hour * 3600 + min * 60 + sec;
327 }
328
DstGetDayOfMonth(INT32 year,INT32 month,INT32 mweek,INT32 wday)329 STATIC INT32 DstGetDayOfMonth(INT32 year, INT32 month, INT32 mweek, INT32 wday)
330 {
331 #define FIRST_DAY 4 /* the first day of 1970.1.1 is Thursday. */
332 INT32 firstWeekDay; /* First week day in this month of the specified year. */
333 INT32 firstMdayOfTargetWday; /* First target month day in this month of the specified year. */
334 INT32 targetMdayOfTargetWday; /* The target month day specified by user. */
335 struct tm time = {0};
336 INT64 seconds, days;
337
338 time.tm_year = year;
339 time.tm_mon = month;
340 time.tm_mday = 1;
341 /* 14: Hour-value range is [0,23] */
342 time.tm_hour = 14;
343 time.tm_isdst = 0;
344
345 seconds = mktime(&time);
346
347 if (seconds == -1) {
348 return -1;
349 }
350 days = seconds / SECSPERDAY;
351 if (days < 0) {
352 days = -days;
353 firstWeekDay = DAYSPERWEEK - (days - (DAYSPERWEEK - FIRST_DAY)) % DAYSPERWEEK;
354 } else {
355 if (days > FIRST_DAY) {
356 firstWeekDay = 1 + (days - FIRST_DAY) % DAYSPERWEEK;
357 } else {
358 firstWeekDay = FIRST_DAY;
359 }
360 }
361
362 firstMdayOfTargetWday = 1 + (DAYSPERWEEK + wday - firstWeekDay) % DAYSPERWEEK;
363 /*
364 * Users may use 5th weekday to represent the last week of this month
365 * for example "Oct-5th-Fri", but there does not exist the 5th Friday in October, so the last monweek is 4th.
366 */
367 targetMdayOfTargetWday = firstMdayOfTargetWday + (mweek - 1) * DAYSPERWEEK;
368 if (targetMdayOfTargetWday > g_monLengths[(INT32)isleap(year + TM_YEAR_BASE)][month]) {
369 targetMdayOfTargetWday -= 7;
370 }
371
372 return targetMdayOfTargetWday;
373 }
374
375 /*
376 * time format decode
377 * 1. Feb-03 03:00:00
378 * idx 012345678901234
379 * 2. Oct-1st-Fri 02:59:59
380 * idx 12345678901234567890
381 */
DateDecode(INT32 year,const CHAR * dstString,INT32 * month,INT32 * monDay,INT32 * sec)382 STATIC INT32 DateDecode(INT32 year, const CHAR *dstString, INT32 *month, INT32 *monDay, INT32 *sec)
383 {
384 INT32 monWeek, weekDay;
385 /* For example "Feb-03 03:00:00" */
386 if (strlen(dstString) == DST_STR_LEN_FORMAT_MDAY) {
387 if ((dstString[3] != '-') || (dstString[6] != ' ')) {
388 return -1;
389 }
390
391 *month = GetMonthFromString(&dstString[0]);
392 if (*month == -1) {
393 return -1;
394 }
395
396 *monDay = GetMonthDayFromString(*month, &dstString[4]);
397 if (*monDay == -1) {
398 return -1;
399 }
400
401 *sec = GetDaySecondsFromString(&dstString[7]);
402 if (*sec == -1) {
403 return -1;
404 }
405 } else if (strlen(dstString) == DST_STR_LEN_FORMAT_WDAY) {
406 /* For example "Oct-1st-Fri 02:59:59" */
407 if ((dstString[3] != '-') || (dstString[7] != '-') || (dstString[11] != ' ')) {
408 return -1;
409 }
410
411 *month = GetMonthFromString(&dstString[0]);
412 if (*month == -1) {
413 return -1;
414 }
415
416 monWeek = GetMonthWeekFromString(&dstString[4]);
417 if (monWeek == -1) {
418 return -1;
419 }
420
421 weekDay = GetWeekDayFromString(&dstString[8]);
422 if (weekDay == -1) {
423 return -1;
424 }
425
426 *sec = GetDaySecondsFromString(&dstString[12]);
427 if (*sec == -1) {
428 return -1;
429 }
430
431 *monDay = DstGetDayOfMonth(year, *month, monWeek, weekDay);
432 if (*monDay == -1) {
433 return -1;
434 }
435 } else {
436 return -1;
437 }
438
439 return 0;
440 }
441
DstConfigDecode(INT32 year,const CHAR * dstString)442 STATIC INT64 DstConfigDecode(INT32 year, const CHAR *dstString)
443 {
444 INT32 month, monDay, sec;
445 INT32 ret;
446 struct tm time = {0};
447 INT64 dstSeconds;
448
449 ret = DateDecode(year, dstString, &month, &monDay, &sec);
450 if (ret == -1) {
451 return -1;
452 }
453 /* get the DST period */
454 time.tm_year = year;
455 time.tm_mon = month;
456 time.tm_mday = monDay;
457 time.tm_isdst = 0;
458
459 dstSeconds = mktime(&time);
460
461 if (dstSeconds == -1) {
462 return -1;
463 }
464
465 return dstSeconds + sec;
466 }
467
DstConfigCheck(const CHAR * strDstStart,const CHAR * strDstEnd)468 STATIC BOOL DstConfigCheck(const CHAR *strDstStart, const CHAR *strDstEnd)
469 {
470 INT64 dstStart, dstEnd;
471 const INT32 year = 70; /* 70 stands for epoch time */
472
473 if ((strDstStart == NULL) || (strDstEnd == NULL)) {
474 return FALSE;
475 }
476
477 dstStart = DstConfigDecode(year, strDstStart);
478 dstEnd = DstConfigDecode(year, strDstEnd);
479 if ((dstStart < 0) || (dstEnd < 0)) {
480 return FALSE;
481 }
482
483 if (dstStart >= dstEnd) {
484 return FALSE;
485 }
486
487 return TRUE;
488 }
489
CheckDstPeriodInner(const struct tm * const tm,INT64 seconds,INT64 dstStart,INT64 dstEnd)490 STATIC BOOL CheckDstPeriodInner(const struct tm * const tm, INT64 seconds, INT64 dstStart, INT64 dstEnd)
491 {
492 if (tm != NULL) {
493 if (tm->tm_isdst < 0) {
494 /* it must to be. */
495 if ((seconds >= dstStart) && (seconds < dstStart + g_dstForwardSeconds)) {
496 return FALSE;
497 }
498
499 /* determine the time period of the second pass, out of the DST period. */
500 if ((seconds > dstEnd) && (seconds <= dstEnd + g_dstForwardSeconds)) {
501 return TRUE;
502 }
503 } else if (tm->tm_isdst > 0) {
504 /* the logical judgment here is the opposite of common sense */
505 return TRUE;
506 } else {
507 /* tm->tm_isdst is zero */
508 return FALSE;
509 }
510 }
511
512 if ((seconds < dstStart) || (seconds >= dstEnd)) {
513 return FALSE; /* daylight saving time is not effect. */
514 }
515
516 return TRUE;
517 }
518
CheckWithinDstPeriod(const struct tm * const tm,INT64 seconds)519 BOOL CheckWithinDstPeriod(const struct tm * const tm, INT64 seconds)
520 {
521 INT64 dstStart, dstEnd;
522 struct tm time = {0};
523
524 if (g_isDstWork == FALSE) {
525 return FALSE;
526 }
527
528 /* represent a local time. */
529 if (tm != NULL) {
530 (void)memcpy_s(&time, sizeof(struct tm), tm, sizeof(struct tm));
531 time.tm_isdst = 0;
532 /* the input-param of seconds is unused in this case. */
533 seconds = mktime(&time);
534 if (seconds == -1) {
535 return FALSE;
536 }
537 } else {
538 /* represent a standard time, not care TZ. */
539 if (gmtime_r(&seconds, &time) == NULL) {
540 return FALSE;
541 }
542 }
543
544 dstStart = DstConfigDecode(time.tm_year, g_strDstStart);
545 dstEnd = DstConfigDecode(time.tm_year, g_strDstEnd);
546 if ((dstStart == -1) || (dstEnd == -1)) {
547 return FALSE;
548 }
549
550 return CheckDstPeriodInner(tm, seconds, dstStart, dstEnd);
551 }
552
dst_disable(VOID)553 int dst_disable(VOID)
554 {
555 if (lock()) {
556 return -1;
557 }
558
559 g_isDstWork = FALSE;
560
561 unlock();
562
563 return 0;
564 }
565
dst_enable(const char * strDstStartTime,const char * strDstEndTime,int swForwardSeconds)566 int dst_enable(const char *strDstStartTime, const char *strDstEndTime, int swForwardSeconds)
567 {
568 if (lock()) {
569 return -1;
570 }
571
572 /* Check if the format of dst config is correct. */
573 if (DstConfigCheck(strDstStartTime, strDstEndTime) != TRUE) {
574 unlock();
575 return -1;
576 }
577
578 if ((swForwardSeconds < 0) || (swForwardSeconds >= 24 * 3600)) { /* seconds per day 24 * 3600 */
579 unlock();
580 return -1;
581 }
582
583 g_isDstWork = FALSE;
584 if (strncpy_s(g_strDstStart, DST_SET_LENGTH_MAX, strDstStartTime, strlen(strDstStartTime)) != EOK) {
585 unlock();
586 return -1;
587 }
588 if (strncpy_s(g_strDstEnd, DST_SET_LENGTH_MAX, strDstEndTime, strlen(strDstEndTime)) != EOK) {
589 unlock();
590 return -1;
591 }
592
593 g_dstForwardSeconds = swForwardSeconds;
594 g_isDstWork = TRUE;
595
596 unlock();
597
598 return 0;
599 }
600
dst_inquire(int year,struct tm * pstDstStart,struct tm * pstDstEnd)601 int dst_inquire(int year, struct tm *pstDstStart, struct tm *pstDstEnd)
602 {
603 INT64 dstStart, dstEnd;
604
605 if (lock()) {
606 return -1;
607 }
608
609 if (!g_isDstWork) {
610 unlock();
611 return -1;
612 }
613
614 if ((pstDstStart == NULL) || (pstDstEnd == NULL)) {
615 unlock();
616 return -1;
617 }
618
619 dstStart = DstConfigDecode(year, g_strDstStart);
620 dstEnd = DstConfigDecode(year, g_strDstEnd);
621 if ((dstStart == -1) || (dstEnd == -1)) {
622 unlock();
623 return -1;
624 }
625
626 dstStart += timezone;
627 dstEnd += timezone;
628 if ((gmtime_r(&dstStart, pstDstStart) == NULL) || (gmtime_r(&dstEnd, pstDstEnd) == NULL)) {
629 unlock();
630 return -1;
631 }
632
633 unlock();
634 return 0;
635 }
636
637