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