• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <sstream>
16 #include <iomanip>
17 #include "calendar_log.h"
18 #include "native_util.h"
19 #include <ctime>
20 #include <numeric>
21 
22 namespace OHOS::CalendarApi::Native {
23 const int MIN_DAY_OF_WEEK = 1;
24 const int MAX_DAY_OF_WEEK = 7;
25 const int MIN_MONTH_OF_YEAR = -12;
26 const int MAX_MONTH_OF_YEAR = 12;
27 const int MIN_DAY_OF_MONTH = -31;
28 const int MAX_DAY_OF_MONTH = 31;
29 const int MIN_DAY_OF_YEAR = -366;
30 const int MAX_DAY_OF_YEAR = 366;
31 const int MIN_WEEK_OF_YEAR = -53;
32 const int MAX_WEEK_OF_YEAR = 53;
33 const int MIN_WEEK_OF_MONTH = -5;
34 const int MAX_WEEK_OF_MONTH = 5;
DumpCalendarAccount(const CalendarAccount & account)35 void DumpCalendarAccount(const CalendarAccount &account)
36 {
37     LOG_DEBUG("account.name:%{private}s", account.name.c_str());
38     LOG_DEBUG("account.type:%{private}s", account.type.c_str());
39     LOG_DEBUG("account.displayName:%{private}s", account.displayName.value_or("").c_str());
40 }
41 
DumpEvent(const Event & event)42 void DumpEvent(const Event &event)
43 {
44     LOG_DEBUG("id       :%{private}d", event.id.value_or(-1));
45     LOG_DEBUG("type     :%{private}d", event.type);
46     LOG_DEBUG("title    :%{private}s", event.title.value_or("[null]").c_str());
47     if (event.location) {
48         auto location = event.location.value();
49         LOG_DEBUG("location.location  :%{private}s", location.location.value_or("[null]").c_str());
50         LOG_DEBUG("location.longitude :%{private}lf", location.longitude.value_or(-1));
51         LOG_DEBUG("location.latitude  :%{private}lf", location.latitude.value_or(-1));
52     } else {
53         LOG_DEBUG("location [null]");
54     }
55     if (event.service) {
56         auto service = event.service.value();
57         LOG_DEBUG("service.type  :%{private}s", service.type.c_str());
58         LOG_DEBUG("service.description :%{private}s", service.description.value_or("[null]").c_str());
59         LOG_DEBUG("service.uri  :%{private}s", service.uri.c_str());
60     } else {
61         LOG_DEBUG("service [null]");
62     }
63     if (event.recurrenceRule.has_value()) {
64         LOG_DEBUG("recurrenceRule.recurrenceFrequency: %{private}d", event.recurrenceRule.value().recurrenceFrequency);
65     }
66     LOG_DEBUG("startTime    :%{private}s", std::to_string(event.startTime).c_str());
67     LOG_DEBUG("endTime      :%{private}s", std::to_string(event.endTime).c_str());
68     LOG_DEBUG("isAllDay :%{private}d", event.isAllDay.value_or(0));
69 
70     for (const auto &attendee : event.attendees) {
71         LOG_DEBUG("attendee.name   :%{private}s", attendee.name.c_str());
72         LOG_DEBUG("attendee.email  :%{private}s", attendee.email.c_str());
73     }
74 
75     LOG_DEBUG("timeZone     :%{private}s", event.timeZone.value_or("[null]").c_str());
76     LOG_DEBUG("description  :%{private}s", event.description.value_or("[null]").c_str());
77 }
78 
BuildEventLocation(DataShare::DataShareValuesBucket & valuesBucket,const Event & event)79 void BuildEventLocation(DataShare::DataShareValuesBucket &valuesBucket, const Event &event)
80 {
81     if (!event.location) {
82         return;
83     }
84     auto location = event.location.value();
85     if (location.location) {
86         valuesBucket.Put("eventLocation", location.location.value());
87     }
88     if (location.longitude) {
89         // longitude is string in db
90         valuesBucket.Put("location_longitude", std::to_string(location.longitude.value()));
91     }
92     if (location.latitude) {
93         // latitude is string in db
94         valuesBucket.Put("location_latitude", std::to_string(location.latitude.value()));
95     }
96 }
97 
BuildEventService(DataShare::DataShareValuesBucket & valuesBucket,const Event & event)98 void BuildEventService(DataShare::DataShareValuesBucket &valuesBucket, const Event &event)
99 {
100     if (!event.service) {
101         return;
102     }
103     const auto service = event.service.value();
104     if (service.description) {
105         valuesBucket.Put("service_description", service.description.value());
106     }
107     valuesBucket.Put("service_type", service.type);
108     valuesBucket.Put("service_cp_bz_uri", service.uri);
109 }
110 
GetUTCTime(const int64_t & timeValue)111 std::string GetUTCTime(const int64_t &timeValue)
112 {
113     const int monOffset = 1;
114     const int strLen = 2;
115     const int baseYear = 1900;
116     time_t expire = timeValue / 1000;
117     std::tm expireTime = {0};
118 #ifdef WINDOWS_PLATFORM
119     if (gmtime_s(&expireTime, &expire)) {
120 #else
121     if (gmtime_r(&expire, &expireTime) == nullptr) {
122 #endif
123         return {};
124     }
125     std::stringstream out;
126     out << (expireTime.tm_year + baseYear);
127     out << std::setfill('0') << std::setw(strLen) << expireTime.tm_mon + monOffset;
128     out << std::setfill('0') << std::setw(strLen) << expireTime.tm_mday;
129     out << "T";
130     out << std::setfill('0') << std::setw(strLen) << expireTime.tm_hour;
131     out << std::setfill('0') << std::setw(strLen) << expireTime.tm_min;
132     out << std::setfill('0') << std::setw(strLen) << expireTime.tm_sec;
133     out << "Z";
134 
135     return out.str();
136 }
137 
138 std::string GetUTCTimes(const std::vector<int64_t> &timeValues)
139 {
140     std::stringstream out;
141     if (timeValues.size() == 0) {
142         return out.str();
143     }
144 
145     const auto timeLen = timeValues.size() - 1;
146     if (timeLen == 0) {
147         out << GetUTCTime(timeValues[0]);
148         return out.str();
149     }
150 
151     for (unsigned int i = 0; i <= timeLen; i++) {
152         out << GetUTCTime(timeValues[i]);
153         if (i != timeLen) {
154             out << ",";
155         }
156     }
157 
158     return out.str();
159 }
160 
161 std::string GetRule(const Event &event)
162 {
163     const time_t now = event.startTime / 1000;
164     const std::tm *time = std::localtime(&now);
165     std::string rrule;
166     RecurrenceType recurrenceFrequency = event.recurrenceRule.value().recurrenceFrequency;
167     if (recurrenceFrequency == DAILY) {
168         rrule = "FREQ=DAILY" + GetEventRRule(event) + ";WKST=SU";
169     } else if (recurrenceFrequency == WEEKLY) {
170         rrule = "FREQ=WEEKLY" + GetEventRRule(event) + ";WKST=SU;BYDAY=";
171         if (time != nullptr) {
172             rrule += GetWeeklyRule(event, *time);
173         }
174     } else if (recurrenceFrequency == MONTHLY) {
175         rrule = "FREQ=MONTHLY" + GetEventRRule(event) + ";WKST=SU";
176         if (time != nullptr) {
177             rrule += GetMonthlyRule(event, *time);
178         }
179     } else if (recurrenceFrequency == YEARLY) {
180         rrule = "FREQ=YEARLY" + GetEventRRule(event) + ";WKST=SU";
181         if (time != nullptr) {
182             rrule += GetYearlyRule(event, *time);
183         }
184     }
185 
186     return rrule;
187 }
188 
189 std::string GetEventRRule(const Event &event)
190 {
191     auto recurrenceRule = event.recurrenceRule.value();
192     std::string rrule;
193     if (recurrenceRule.expire.has_value() && recurrenceRule.expire.value() > 0) {
194         rrule += ";UNTIL=" + GetUTCTime(event.recurrenceRule.value().expire.value());
195     }
196     if (recurrenceRule.count.has_value() && recurrenceRule.count.value() > 0) {
197         rrule += ";COUNT=" + std::to_string(recurrenceRule.count.value());
198     }
199     if (recurrenceRule.interval.has_value() && recurrenceRule.interval.value() > 0) {
200         rrule += ";INTERVAL=" + std::to_string(recurrenceRule.interval.value());
201     }
202     return rrule;
203 }
204 
205 std::string GetWeeklyRule(const Event &event, const std::tm &time)
206 {
207     std::string rrule;
208     bool isHasSetData = false;
209     auto rRuleValue = event.recurrenceRule.value();
210     const std::vector<string> weekList = {"SU", "MO", "TU", "WE", "TH", "FR", "SA"};
211     if (rRuleValue.daysOfWeek.has_value()) {
212         isHasSetData = true;
213         auto daysOfWeekList = rRuleValue.daysOfWeek.value();
214         rrule = GetDaysOfWeekRule(MIN_DAY_OF_WEEK, MAX_DAY_OF_WEEK, daysOfWeekList);
215     }
216     if (isHasSetData == false) {
217         if (time.tm_wday < MAX_DAY_OF_WEEK) {
218             rrule = weekList[time.tm_wday];
219         }
220     }
221     return rrule;
222 }
223 
224 std::string GetMonthlyRule(const Event &event, const std::tm &time)
225 {
226     bool isHasSetData = false;
227     std::string rrule;
228     auto rruleValue = event.recurrenceRule.value();
229     if (rruleValue.daysOfWeek.has_value() && rruleValue.weeksOfMonth.has_value()) {
230         isHasSetData = true;
231         rrule += ";BYDAY=";
232         rrule += GetDaysOfWeekMonthRule(rruleValue.daysOfWeek.value(), rruleValue.weeksOfMonth.value());
233     }
234 
235     if (rruleValue.daysOfMonth.has_value()) {
236         isHasSetData = true;
237         rrule += ";BYMONTHDAY=";
238         auto daysOfMonthList = rruleValue.daysOfMonth.value();
239         rrule += GetRRuleSerial(MIN_DAY_OF_MONTH, MAX_DAY_OF_MONTH, daysOfMonthList);
240     }
241     if (isHasSetData == false) {
242         rrule += ";BYMONTHDAY=";
243         rrule += std::to_string(time.tm_mday);
244     }
245     return rrule;
246 }
247 
248 std::string GetYearlyRule(const Event &event, const std::tm &time)
249 {
250     const int monOffset = 1;
251     bool isHasSetData = false;
252     std::string rrule;
253     auto rruleValue = event.recurrenceRule.value();
254     if (rruleValue.daysOfYear.has_value()) {
255         isHasSetData = true;
256         std::string days = GetRRuleSerial(MIN_DAY_OF_YEAR, MAX_DAY_OF_YEAR, rruleValue.daysOfYear.value());
257         rrule = ";BYYEARDAY=" + days;
258     }
259     if (rruleValue.weeksOfYear.has_value() && rruleValue.daysOfWeek.has_value()) {
260         isHasSetData = true;
261         auto weekOfYearList = rruleValue.weeksOfYear.value();
262         std::string weeks = GetRRuleSerial(MIN_WEEK_OF_YEAR, MAX_WEEK_OF_YEAR, weekOfYearList);
263         auto daysOfWeekList = rruleValue.daysOfWeek.value();
264         std::string weekdays = GetDaysOfWeekRule(MIN_DAY_OF_WEEK, MAX_DAY_OF_WEEK, daysOfWeekList);
265         rrule = ";BYWEEKNO=" + weeks + ";BYDAY=" + weekdays;
266     }
267     if (rruleValue.monthsOfYear.has_value() && rruleValue.daysOfMonth.has_value()) {
268         isHasSetData = true;
269         auto daysOfMonthList = rruleValue.daysOfMonth.value();
270         auto monthsOfYearList = rruleValue.monthsOfYear.value();
271         std::string days = GetRRuleSerial(MIN_DAY_OF_MONTH, MAX_DAY_OF_MONTH, daysOfMonthList);
272         std::string months = GetRRuleSerial(MIN_MONTH_OF_YEAR, MAX_MONTH_OF_YEAR, monthsOfYearList);
273         rrule = ";BYMONTHDAY=" + days + ";BYMONTH=" + months;
274     }
275     if (rruleValue.monthsOfYear.has_value() && rruleValue.weeksOfMonth.has_value() &&
276         rruleValue.daysOfWeek.has_value()) {
277         isHasSetData = true;
278         auto monthsOfYearList = rruleValue.monthsOfYear.value();
279         auto weeksOfMonthList = rruleValue.weeksOfMonth.value();
280         auto daysOfWeekList = rruleValue.daysOfWeek.value();
281         std::string months = GetRRuleSerial(MIN_MONTH_OF_YEAR, MAX_MONTH_OF_YEAR, monthsOfYearList);
282         std::string daysOfWeekMonth = GetDaysOfWeekMonthRule(daysOfWeekList, weeksOfMonthList);
283         rrule = ";BYDAY=" + daysOfWeekMonth + ";BYMONTH=" + months;
284     }
285     if (isHasSetData == false) {
286         rrule += ";BYMONTHDAY=";
287         rrule += std::to_string(time.tm_mday);
288         rrule += ";BYMONTH=";
289         rrule += std::to_string(time.tm_mon + monOffset);
290     }
291     return rrule;
292 }
293 
294 std::string GetDaysOfWeekRule(int minValue, int maxValue, const std::vector<int64_t> &daysOfWeekList)
295 {
296     std::string rrule;
297     const std::vector<string> weekDayList = {"MO", "TU", "WE", "TH", "FR", "SA", "SU"};
298     for (const auto &dayOfWeek : daysOfWeekList) {
299         if (dayOfWeek <= maxValue && dayOfWeek >= minValue) {
300             if (&dayOfWeek == &daysOfWeekList.back()) {
301                 rrule = rrule + weekDayList[dayOfWeek - 1];
302                 break;
303             }
304             rrule = rrule + weekDayList[dayOfWeek - 1] + ",";
305         }
306     }
307     return rrule;
308 }
309 
310 std::string GetDaysOfWeekMonthRule(
311     const std::vector<int64_t> &daysOfWeekList, const std::vector<int64_t> &weeksOfMonthList)
312 {
313     std::string rrule;
314     const std::vector<string> weekDayList = {"MO", "TU", "WE", "TH", "FR", "SA", "SU"};
315     auto daysLen = daysOfWeekList.size();
316     for (size_t i = 0; i < daysLen; i++) {
317         if (daysOfWeekList[i] >= MIN_DAY_OF_WEEK && daysOfWeekList[i] <= MAX_DAY_OF_WEEK &&
318             weeksOfMonthList[i] >= MIN_WEEK_OF_MONTH && weeksOfMonthList[i] <= MAX_WEEK_OF_MONTH) {
319             if (i == daysLen - 1) {
320                 rrule = rrule + std::to_string(weeksOfMonthList[i]) + weekDayList[daysOfWeekList[i] - 1];
321                 break;
322             } else {
323                 rrule = rrule + std::to_string(weeksOfMonthList[i]) + weekDayList[daysOfWeekList[i] - 1] + ",";
324             }
325         }
326     }
327     return rrule;
328 }
329 
330 std::string GetRRuleSerial(int minValue, int maxValue, const std::vector<int64_t> &serialList)
331 {
332     std::string rrule;
333     for (const auto &serial : serialList) {
334         if (serial >= minValue && serial <= maxValue) {
335             if (&serial == &serialList.back()) {
336                 rrule = rrule + std::to_string(serial);
337                 break;
338             }
339             rrule = rrule + std::to_string(serial) + ",";
340         }
341     }
342     return rrule;
343 }
344 
345 void BuildEventRecurrenceRule(DataShare::DataShareValuesBucket &valuesBucket, const Event &event)
346 {
347     if (!event.recurrenceRule.has_value()) {
348         return;
349     }
350 
351     std::string rrule = GetRule(event);
352     if (!rrule.empty()) {
353         valuesBucket.Put("rrule", rrule);
354     }
355 
356     if (event.recurrenceRule.value().excludedDates.has_value()) {
357         const auto excludedDateStr = GetUTCTimes(event.recurrenceRule.value().excludedDates.value());
358         valuesBucket.Put("exdate", excludedDateStr);
359     }
360 }
361 
362 DataShare::DataShareValuesBucket BuildValueEvent(const Event &event, int calendarId, int channelId)
363 {
364     DataShare::DataShareValuesBucket valuesBucket;
365     valuesBucket.Put("calendar_id", calendarId);
366 
367     LOG_DEBUG("title %{private}s", event.title.value_or("").c_str());
368     valuesBucket.Put("title", event.title.value_or(""));
369     valuesBucket.Put("important_event_type", event.type);
370     valuesBucket.Put("dtstart", event.startTime);
371     valuesBucket.Put("dtend", event.endTime);
372     valuesBucket.Put("channel_id", channelId);
373 
374     BuildEventLocation(valuesBucket, event);
375     BuildEventService(valuesBucket, event);
376     BuildEventRecurrenceRule(valuesBucket, event);
377 
378     LOG_DEBUG("description %{private}s", event.description.value_or("").c_str());
379 
380     if (event.description.has_value()) {
381         valuesBucket.Put("description", event.description.value());
382     }
383     if (event.timeZone.has_value()) {
384         valuesBucket.Put("eventTimezone", event.timeZone.value());
385     }
386     if (event.isAllDay.has_value()) {
387         valuesBucket.Put("allDay", event.isAllDay.value());
388     }
389     if (event.identifier.has_value()) {
390         valuesBucket.Put("identifier", event.identifier.value());
391     }
392     if (event.isLunar.has_value()) {
393         valuesBucket.Put("event_calendar_type", event.isLunar.value());
394     }
395     return valuesBucket;
396 }
397 
398 DataShare::DataShareValuesBucket BuildAttendeeValue(const Attendee &attendee, int eventId)
399 {
400     DataShare::DataShareValuesBucket valuesBucket;
401     valuesBucket.Put("event_id", eventId);
402     valuesBucket.Put("attendeeName", attendee.name);
403     LOG_DEBUG("attendeeName %{private}s", attendee.name.c_str());
404     valuesBucket.Put("attendeeEmail", attendee.email);
405     LOG_DEBUG("attendeeEmail %{private}s", attendee.email.c_str());
406     if (attendee.role.has_value()) {
407         valuesBucket.Put("attendeeRelationship", attendee.role.value());
408     }
409     if (attendee.status.has_value()) {
410         valuesBucket.Put("attendeeStatus", attendee.status.value());
411     }
412     if (attendee.type.has_value()) {
413         valuesBucket.Put("attendeeType", attendee.type.value());
414     }
415 
416     return valuesBucket;
417 }
418 
419 int GetValue(DataShareResultSetPtr &resultSet, string_view fieldName, int& out)
420 {
421     int index = 0;
422     auto ret = resultSet->GetColumnIndex(string(fieldName), index);
423     if (ret != DataShare::E_OK) {
424         return ret;
425     }
426     return resultSet->GetInt(index, out);
427 }
428 
429 int GetIndexValue(const DataShareResultSetPtr &resultSet, int index, std::string& out)
430 {
431     return resultSet->GetString(index, out);
432 }
433 
434 int GetIndexValue(const DataShareResultSetPtr &resultSet, int index, int& out)
435 {
436     return resultSet->GetInt(index, out);
437 }
438 
439 int GetIndexValue(const DataShareResultSetPtr &resultSet, int index, int64_t& out)
440 {
441     return resultSet->GetLong(index, out);
442 }
443 
444 int GetValue(DataShareResultSetPtr &resultSet, string_view fieldName, std::string& out)
445 {
446     int index = 0;
447     auto fieldNameStr = string(fieldName);
448     auto ret = resultSet->GetColumnIndex(fieldNameStr, index);
449     if (ret != DataShare::E_OK) {
450         LOG_WARN("GetValue [%{private}s] failed [%{private}d]", fieldNameStr.c_str(), ret);
451         return ret;
452     }
453     return resultSet->GetString(index, out);
454 }
455 
456 std::vector<std::shared_ptr<Calendar>> ResultSetToCalendars(DataShareResultSetPtr &resultSet)
457 {
458     std::vector<std::shared_ptr<Calendar>> result;
459     int rowCount = 0;
460     resultSet->GetRowCount(rowCount);
461     LOG_INFO("GetRowCount is %{public}d", rowCount);
462     if (rowCount == 0) {
463         return result;
464     }
465     auto err = resultSet->GoToFirstRow();
466     if (err != DataShare::E_OK) {
467         LOG_INFO("Failed GoToFirstRow %{public}d", err);
468         return result;
469     }
470     do {
471         int idValue = -1;
472         if (GetValue(resultSet, "_id", idValue) != DataShare::E_OK) {
473             break;
474         }
475         LOG_DEBUG("id: %{private}d", idValue);
476         std::string nameValue;
477         if (GetValue(resultSet, "account_name", nameValue) != DataShare::E_OK) {
478             break;
479         }
480         LOG_DEBUG("account_name: %{private}s", nameValue.c_str());
481         std::string typeValue;
482         if (GetValue(resultSet, "account_type", typeValue) != DataShare::E_OK) {
483             break;
484         }
485         LOG_DEBUG("account_type: %{private}s", typeValue.c_str());
486 
487         std::string displayNameValue;
488         GetValue(resultSet, "calendar_displayName", displayNameValue);
489         LOG_DEBUG("calendar_displayName: %{private}s", displayNameValue.c_str());
490 
491         int canReminder = -1;
492         GetValue(resultSet, "canReminder", canReminder);
493         LOG_DEBUG("canReminder: %{private}d", canReminder);
494 
495         int colorValue = 0;
496         GetValue(resultSet, "calendar_color", colorValue);
497         CalendarAccount curAccount {nameValue, typeValue, displayNameValue};
498         result.emplace_back(std::make_shared<Calendar>(curAccount, idValue));
499     } while (resultSet->GoToNextRow() == DataShare::E_OK);
500     return result;
501 }
502 
503 std::optional<Location> ResultSetToLocation(DataShareResultSetPtr &resultSet)
504 {
505     Location out;
506     string value;
507     auto ret = GetValue(resultSet, "eventLocation", value);
508     out.location = std::make_optional<string>(value);
509     ret = GetValue(resultSet, "location_longitude", value);
510     double longitudeValue = -1;
511     std::stringstream str2digit;
512     str2digit << value;
513     str2digit >> longitudeValue;
514     if (longitudeValue != -1) {
515         out.longitude = std::make_optional<double>(longitudeValue);
516     }
517     ret = GetValue(resultSet, "location_latitude", value);
518     double latitudeValue = -1;
519     str2digit.clear();
520     str2digit << value;
521     str2digit >> latitudeValue;
522     if (latitudeValue != -1) {
523         out.latitude = std::make_optional<double>(latitudeValue);
524     }
525 
526     if (ret != DataShare::E_OK) {
527         return std::nullopt;
528     }
529     return std::make_optional<Location>(out);
530 }
531 
532 std::optional<EventService> ResultSetToEventService(DataShareResultSetPtr &resultSet)
533 {
534     EventService out;
535     string value;
536     auto ret = GetValue(resultSet, "service_type", value);
537     if (ret != DataShare::E_OK) {
538         return std::nullopt;
539     }
540     const std::set<std::string> serviceType = {"Meeting", "Watching", "Repayment", "Live", "Shopping",
541                                                "Trip", "Class", "SportsEvents", "SportsExercise"};
542     if (serviceType.count(value)) {
543         out.type = value;
544     } else {
545         return std::nullopt;
546     }
547     ret = GetValue(resultSet, "service_cp_bz_uri", value);
548     if (ret != DataShare::E_OK) {
549         return std::nullopt;
550     }
551     out.uri = value;
552     ret = GetValue(resultSet, "service_description", value);
553     if (ret == DataShare::E_OK) {
554         out.description = std::make_optional<string>(value);
555     }
556     return std::make_optional<EventService>(out);
557 }
558 
559 int StringToInt(const std::string &str)
560 {
561     try {
562         return std::stoi(str);
563     } catch (std::exception &ex) {
564         LOG_ERROR("StringToInt conversion fail, str: %{public}s", str.c_str());
565         return 0;
566     }
567 }
568 
569 std::time_t TimeToUTC(const std::string &strTime)
570 {
571     const int baseYear = 1900;
572     const int offset = 2;
573     const int yearOffset = 4;
574     const int monBase = 4;
575     const int dayBase = 6;
576     const int hourBase = 9;
577     const int minBase = 11;
578     const int secBase = 13;
579     const int monCount = 12;
580     const int monRectify = 11;
581     const int micSecond = 1000;
582     const int timeStrLenMin = 8;
583     const int timeStrLen = 15;
584 
585     std::tm expireTime = {0};
586     if (strTime.size() < timeStrLenMin) {
587         LOG_DEBUG("strTime length error");
588         return 0;
589     }
590     expireTime.tm_year = StringToInt(strTime.substr(0, yearOffset)) - baseYear;
591     expireTime.tm_mon = (StringToInt(strTime.substr(monBase, offset)) + monRectify) % monCount;
592     expireTime.tm_mday = StringToInt(strTime.substr(dayBase, offset));
593     if (strTime.find("T") != std::string::npos && strTime.length() >= timeStrLen) {
594         expireTime.tm_hour = StringToInt(strTime.substr(hourBase, offset));
595         expireTime.tm_min = StringToInt(strTime.substr(minBase, offset));
596         expireTime.tm_sec = StringToInt(strTime.substr(secBase,  offset));
597     } else {
598         expireTime.tm_hour = 0;
599         expireTime.tm_min = 0;
600         expireTime.tm_sec = 0;
601     }
602 
603     std::time_t utcTime = mktime(&expireTime) * micSecond; //精确到微秒
604 
605     return utcTime;
606 }
607 
608 std::vector<std::string> SplitString(const std::string &str, const std::string &flag)
609 {
610     std::vector<std::string> result;
611     std::string::size_type pos1 = 0;
612     std::string::size_type pos2 = str.find(flag);
613     while (pos2 != std::string::npos) {
614         result.push_back(str.substr(pos1, pos2 - pos1));
615         pos1 = pos2 + flag.size();
616         pos2 = str.find(flag, pos1);
617     }
618     if (pos1 != str.length()) {
619         result.push_back(str.substr(pos1));
620     }
621 
622     return result;
623 }
624 
625 std::optional<vector<int64_t>> ResultSetToExcludedDates(DataShareResultSetPtr &resultSet)
626 {
627     std::string value;
628     auto ret = GetValue(resultSet, "exdate", value);
629     if (ret != DataShare::E_OK) {
630         return std::nullopt;
631     }
632     std::vector<string> strListExDate = SplitString(value, ",");
633 
634     std::vector<int64_t> excludedDates;
635     for (const auto &str : strListExDate) {
636         auto exDate = TimeToUTC(str);
637         excludedDates.emplace_back(exDate);
638     }
639 
640     return std::make_optional<vector<int64_t>>(excludedDates);
641 }
642 
643 void ConvertRecurrenceFrequency(const std::string &frequency, RecurrenceRule &rule)
644 {
645     if (frequency == "YEARLY") {
646         rule.recurrenceFrequency = YEARLY;
647         return;
648     }
649     if (frequency == "MONTHLY") {
650         rule.recurrenceFrequency = MONTHLY;
651         return;
652     }
653     if (frequency == "WEEKLY") {
654         rule.recurrenceFrequency = WEEKLY;
655         return;
656     }
657     if (frequency == "DAILY") {
658         rule.recurrenceFrequency = DAILY;
659     }
660 }
661 
662 std::optional<RecurrenceRule> ResultSetToRecurrenceRule(DataShareResultSetPtr &resultSet)
663 {
664     const int strListSize = 2;
665     RecurrenceRule out;
666     out.recurrenceFrequency = NORULE;
667     std::string value;
668     auto ret = GetValue(resultSet, "rrule", value);
669     if (ret != DataShare::E_OK) {
670         return std::nullopt;
671     }
672     std::map<std::string, std::string> ruleMap;
673     std::vector<std::string> strListRule = SplitString(value, ";");
674     for (const auto &str : strListRule) {
675         std::vector<std::string> keyAndValue = SplitString(str, "=");
676         if (keyAndValue.size() == strListSize) {
677             ruleMap.insert(std::pair<std::string, std::string>(keyAndValue[0], keyAndValue[1]));
678         }
679     }
680     SetRRuleValue(ruleMap, out);
681     out.excludedDates = ResultSetToExcludedDates(resultSet);
682 
683     return std::make_optional<RecurrenceRule>(out);
684 }
685 
686 void SetVecNum(std::optional<std::vector<int64_t>> &ruleVec, const std::string &ruleStr)
687 {
688     std::vector<std::string> weekNumList = SplitString(ruleStr, ",");
689     for (const auto &weekNum : weekNumList) {
690         ruleVec->push_back(StringToInt(weekNum));
691     }
692 }
693 
694 void SetRRuleValue(const std::map<std::string, std::string> &ruleMap, RecurrenceRule &out)
695 {
696     std::map<std::string, std::string>::const_iterator iter;
697     for (iter = ruleMap.begin(); iter != ruleMap.end(); iter++) {
698         if (iter->first == "FREQ") {
699             ConvertRecurrenceFrequency(iter->second, out);
700             continue;
701         }
702         if (iter->first == "COUNT") {
703             out.count = std::make_optional<int64_t>(StringToInt(iter->second));
704             continue;
705         }
706         if (iter->first == "INTERVAL") {
707             out.interval = std::make_optional<int64_t>(StringToInt(iter->second));
708             continue;
709         }
710         if (iter->first == "UNTIL") {
711             out.expire = std::make_optional<int64_t>(TimeToUTC(iter->second));
712         }
713         if (iter->first == "BYDAY") {
714             std::vector<std::string> weekDayList = SplitString(iter->second, ",");
715             SetByDayOfRRule(weekDayList, out);
716         }
717         if (iter->first == "BYWEEKNO") {
718             out.weeksOfYear = std::make_optional<std::vector<int64_t>>();
719             SetVecNum(out.weeksOfYear, iter->second);
720         }
721         if (iter->first == "BYMONTHDAY") {
722             out.daysOfMonth = std::make_optional<std::vector<int64_t>>();
723             SetVecNum(out.daysOfMonth, iter->second);
724         }
725         if (iter->first == "BYYEARDAY") {
726             out.daysOfYear = std::make_optional<std::vector<int64_t>>();
727             SetVecNum(out.daysOfYear, iter->second);
728         }
729         if (iter->first == "BYMONTH") {
730             out.monthsOfYear = std::make_optional<std::vector<int64_t>>();
731             SetVecNum(out.monthsOfYear, iter->second);
732         }
733     }
734 }
735 
736 void SetByDayOfRRule(const std::vector<std::string> &weekDayList, RecurrenceRule &out)
737 {
738     const int weekStrLen = 2;
739     const std::vector<string> dayOfWeekList = {"MO", "TU", "WE", "TH", "FR", "SA", "SU"};
740     out.daysOfWeek = std::make_optional<vector<int64_t>>();
741     out.weeksOfMonth = std::make_optional<vector<int64_t>>();
742     for (const auto &weekday : weekDayList) {
743         if (weekday.length() > weekStrLen) {
744             std::string weekDayStr = weekday.substr(weekday.length() - weekStrLen, weekStrLen);
745             std::string WeekNumStr = weekday.substr(0, weekday.length() - weekStrLen);
746             auto it = std::find(dayOfWeekList.begin(), dayOfWeekList.end(), weekDayStr);
747             if (it != dayOfWeekList.end()) {
748                 int dayNum = it - dayOfWeekList.begin();
749                 out.daysOfWeek->push_back(dayNum + 1);
750                 out.weeksOfMonth->push_back(StringToInt(WeekNumStr));
751             }
752         } else if (weekday.length() == weekStrLen) {
753             auto it = std::find(dayOfWeekList.begin(), dayOfWeekList.end(), weekday);
754             if (it != dayOfWeekList.end()) {
755                 int dayNum = it - dayOfWeekList.begin();
756                 out.daysOfWeek->push_back(dayNum + 1);
757             }
758         }
759     }
760 }
761 
762 void ResultSetToInstanceTime(Event &event, DataShareResultSetPtr &resultSet, const std::set<std::string>& columns)
763 {
764     if (columns.count("instanceStartTime")) {
765         GetValueOptional(resultSet, "begin", event.instanceStartTime);
766     }
767 
768     if (columns.count("instanceEndTime")) {
769         GetValueOptional(resultSet, "end", event.instanceEndTime);
770     }
771 }
772 
773 void ResultSetToEvent(Event &event, DataShareResultSetPtr &resultSet, const std::set<std::string>& columns)
774 {
775     GetValueOptional(resultSet, "_id", event.id);
776     if (columns.count("type")) {
777         int type = 0;
778         GetValue(resultSet, "important_event_type", type);
779         event.type = static_cast<EventType>(type);
780     }
781     if (columns.count("title")) {
782         GetValueOptional(resultSet, "title", event.title);
783     }
784     if (columns.count("startTime")) {
785         LOG_DEBUG("TLQ get startTime");
786         GetValue(resultSet, "dtstart", event.startTime);
787     }
788     if (columns.count("endTime")) {
789         LOG_DEBUG("TLQ get endTime");
790         GetValue(resultSet, "dtend", event.endTime);
791     }
792     if (columns.count("isAllDay")) {
793         int isAllDay = 0;
794         GetValue(resultSet, "allDay", isAllDay);
795         event.isAllDay = static_cast<bool>(isAllDay);
796     }
797     if (columns.count("description")) {
798         GetValueOptional(resultSet, "description", event.description);
799     }
800     if (columns.count("timeZone")) {
801         GetValueOptional(resultSet, "eventTimezone", event.timeZone);
802     }
803     if (columns.count("location")) {
804         event.location = ResultSetToLocation(resultSet);
805     }
806     if (columns.count("service")) {
807         event.service = ResultSetToEventService(resultSet);
808     }
809     if (columns.count("recurrenceRule")) {
810         event.recurrenceRule = ResultSetToRecurrenceRule(resultSet);
811     }
812 
813     if (columns.count("identifier")) {
814         GetValueOptional(resultSet, "identifier", event.identifier);
815     }
816     if (columns.count("isLunar")) {
817         int isLunar = 0;
818         GetValue(resultSet, "event_calendar_type", isLunar);
819         event.isLunar = static_cast<bool>(isLunar);
820     }
821     ResultSetToInstanceTime(event, resultSet, columns);
822 }
823 
824 int ResultSetToEvents(std::vector<Event> &events, DataShareResultSetPtr &resultSet,
825     const std::set<std::string>& columns)
826 {
827     int rowCount = 0;
828     resultSet->GetRowCount(rowCount);
829     LOG_INFO("GetRowCount is %{public}d", rowCount);
830     if (rowCount <= 0) {
831         return -1;
832     }
833     auto err = resultSet->GoToFirstRow();
834     if (err != DataShare::E_OK) {
835         LOG_ERROR("Failed GoToFirstRow %{public}d", err);
836         return -1;
837     }
838     do {
839         Event event;
840         ResultSetToEvent(event, resultSet, columns);
841         events.emplace_back(event);
842     } while (resultSet->GoToNextRow() == DataShare::E_OK);
843     return 0;
844 }
845 
846 void ResultSetToAttendeeStatus(Attendee &attendee, DataShareResultSetPtr &resultSet)
847 {
848     int statusValue = 0;
849     GetValue(resultSet, "attendeeStatus", statusValue);
850     if (statusValue == UNKNOWN) {
851         attendee.status = std::make_optional<AttendeeStatus>(UNKNOWN);
852     } else if (statusValue == TENTATIVE) {
853         attendee.status = std::make_optional<AttendeeStatus>(TENTATIVE);
854     } else if (statusValue == ACCEPTED) {
855         attendee.status = std::make_optional<AttendeeStatus>(ACCEPTED);
856     } else if (statusValue == DECLINED) {
857         attendee.status = std::make_optional<AttendeeStatus>(DECLINED);
858     } else {
859         attendee.status = std::make_optional<AttendeeStatus>(UNRESPONSIVE);
860     }
861 }
862 
863 void ResultSetToAttendeeType(Attendee &attendee, DataShareResultSetPtr &resultSet)
864 {
865     int typeValue = 0;
866     GetValue(resultSet, "attendeeType", typeValue);
867     if (typeValue == REQUIRED) {
868         attendee.type = std::make_optional<AttendeeType>(REQUIRED);
869     } else if (typeValue == OPTIONAL) {
870         attendee.type = std::make_optional<AttendeeType>(OPTIONAL);
871     } else {
872         attendee.type = std::make_optional<AttendeeType>(RESOURCE);
873     }
874 }
875 
876 int ResultSetToAttendees(std::vector<Attendee> &attendees, DataShareResultSetPtr &resultSet)
877 {
878     int rowCount = 0;
879     resultSet->GetRowCount(rowCount);
880     LOG_INFO("GetRowCount is %{public}d", rowCount);
881     if (rowCount <= 0) {
882         return -1;
883     }
884     auto err = resultSet->GoToFirstRow();
885     if (err != DataShare::E_OK) {
886         LOG_ERROR("Failed GoToFirstRow %{public}d", err);
887         return -1;
888     }
889     int roleValue = 0;
890     do {
891         Attendee attendee;
892         GetValue(resultSet, "attendeeName", attendee.name);
893         GetValue(resultSet, "attendeeEmail", attendee.email);
894         GetValue(resultSet, "attendeeRelationship",  roleValue);
895         if (roleValue == PARTICIPANT) {
896             attendee.role = std::make_optional<RoleType>(PARTICIPANT);
897         } else if (roleValue == ORGANIZER) {
898             attendee.role = std::make_optional<RoleType>(ORGANIZER);
899         }
900 
901         ResultSetToAttendeeStatus(attendee, resultSet);
902         ResultSetToAttendeeType(attendee, resultSet);
903         attendees.emplace_back(attendee);
904     } while (resultSet->GoToNextRow() == DataShare::E_OK);
905     return 0;
906 }
907 
908 std::string EventIdsToString(const std::vector<int> &ids) {
909     if (ids.empty()) {
910         return "";
911     }
912     return std::accumulate(std::next(ids.begin()), ids.end(), std::to_string(ids[0]),
913         [](const std::string& a, int b) {
914             std::stringstream ss;
915             ss << a << ", " << b;
916             return ss.str();
917         }
918     );
919 }
920 
921 int ResultSetToReminders(std::vector<int> &reminders, DataShareResultSetPtr &resultSet)
922 {
923     int rowCount = 0;
924     resultSet->GetRowCount(rowCount);
925     LOG_INFO("GetRowCount is %{public}d", rowCount);
926     if (rowCount <= 0) {
927         return -1;
928     }
929     auto err = resultSet->GoToFirstRow();
930     if (err != DataShare::E_OK) {
931         LOG_ERROR("Failed GoToFirstRow %{public}d", err);
932         return -1;
933     }
934     do {
935         int minutes = 0;
936         GetValue(resultSet, "minutes", minutes);
937         reminders.emplace_back(minutes);
938     } while (resultSet->GoToNextRow() == DataShare::E_OK);
939     return 0;
940 }
941 
942 void ResultSetToConfig(CalendarConfig &config, DataShareResultSetPtr &resultSet)
943 {
944     int rowCount = 0;
945     resultSet->GetRowCount(rowCount);
946     LOG_INFO("GetRowCount is %{public}d", rowCount);
947     auto err = resultSet->GoToFirstRow();
948     if (err != DataShare::E_OK) {
949         LOG_ERROR("Failed GoToFirstRow %{public}d", err);
950     }
951     do {
952         int enableReminder = 0;
953         std::int64_t color = 0;
954         GetValue(resultSet, "canReminder", enableReminder);
955         GetValue(resultSet, "calendar_color", color);
956         config.enableReminder = static_cast<bool>(enableReminder);
957         LOG_INFO("enableReminder is %{public}d", enableReminder);
958         config.color = color;
959     } while (resultSet->GoToNextRow() == DataShare::E_OK);
960 }
961 
962 bool IsValidHexString(const std::string& colorStr)
963 {
964     if (colorStr.empty()) {
965         return false;
966     }
967     for (char ch : colorStr) {
968         if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
969             continue;
970         }
971         return false;
972     }
973     return true;
974 }
975 
976 bool ColorParse(const std::string& colorStr, variant<string, int64_t>& colorValue)
977 {
978     if (colorStr.empty()) {
979         LOG_ERROR("color string is empty");
980         return false;
981     }
982 
983     if (colorStr[0] != '#') { // start with '#'
984         LOG_ERROR("color string not start with #");
985         return false;
986     }
987 
988     const int rgbLen = 7;
989     const int argbLen = 9;
990     if (colorStr.size() != rgbLen && colorStr.size() != argbLen) {
991         LOG_ERROR("color string length is not 7 or 9");
992         return false;
993     }
994 
995     std::string colorStrSub = colorStr.substr(1);
996     if (!IsValidHexString(colorStrSub)) {
997         LOG_DEBUG("color string is not valid hex string");
998         return false;
999     }
1000 
1001     LOG_DEBUG("color string size is 7 or 9");
1002     try {
1003         colorValue.emplace<1>(std::stoll(colorStrSub, NULL, 16));  // 16 is convert hex string to number
1004     } catch (std::exception &ex) {
1005         LOG_ERROR("stoll fail %{public}s", ex.what());
1006         return false;
1007     }
1008     if (std::get_if<1>(&colorValue)) {
1009         LOG_DEBUG("colorStrSub -> colorValue colorValue:%{public}s", std::to_string(std::get<1>(colorValue)).c_str());
1010         return true;
1011     }
1012     LOG_DEBUG("color is null");
1013     return false;
1014 }
1015 
1016 void SetLocationFieldInfo(std::vector<string>& queryField)
1017 {
1018     queryField.emplace_back("eventLocation");
1019     queryField.emplace_back("location_longitude");
1020     queryField.emplace_back("location_latitude");
1021 }
1022 
1023 void SetServiceFieldInfo(std::vector<string>& queryField)
1024 {
1025     queryField.emplace_back("service_type");
1026     queryField.emplace_back("service_cp_bz_uri");
1027     queryField.emplace_back("service_description");
1028 }
1029 
1030 void FillFieldInfo(const std::string field, std::vector<string>& queryField, std::set<string>& resultSetField,
1031     const std::map<string, string> eventField)
1032 {
1033     if (field == "location") {
1034             SetLocationFieldInfo(queryField);
1035             resultSetField.insert(field);
1036             return;
1037         }
1038         if (field == "service") {
1039             SetServiceFieldInfo(queryField);
1040             resultSetField.insert(field);
1041             return;
1042         }
1043         if (field == "attendee") {
1044             resultSetField.insert(field);
1045             return;
1046         }
1047         if (field == "reminderTime") {
1048             resultSetField.insert(field);
1049             return;
1050         }
1051         if (field == "identifier") {
1052             queryField.emplace_back("identifier");
1053             resultSetField.insert(field);
1054             return;
1055         }
1056         if (field == "recurrenceRule") {
1057             queryField.emplace_back("rrule");
1058             queryField.emplace_back("exdate");
1059             resultSetField.insert(field);
1060             return;
1061         }
1062         if (field == "isLunar") {
1063             queryField.emplace_back("event_calendar_type");
1064             resultSetField.insert(field);
1065             return;
1066         }
1067         if (field == "instanceStartTime") {
1068             queryField.emplace_back("begin");
1069             resultSetField.insert(field);
1070             return;
1071         }
1072         if (field == "instanceEndTime") {
1073             queryField.emplace_back("end");
1074             resultSetField.insert(field);
1075             return;
1076         }
1077         queryField.emplace_back(eventField.at(field));
1078         resultSetField.insert(field);
1079 }
1080 
1081 void SetFieldInfo(const std::vector<string>& eventKey, std::vector<string>& queryField,
1082     std::set<string>& resultSetField, const std::map<string, string> eventField)
1083 {
1084     for (const auto& field : eventKey) {
1085         if (field == "id") {
1086             continue;
1087         }
1088         FillFieldInfo(field, queryField, resultSetField, eventField);
1089     }
1090 }
1091 
1092 void SetField(const std::vector<string>& eventKey, std::vector<string>& queryField, std::set<string>& resultSetField)
1093 {
1094     const std::map<string, string> eventField = { { "id", "_id" },
1095                                                   { "type", "important_event_type" },
1096                                                   { "title", "title" },
1097                                                   { "startTime", "dtstart" },
1098                                                   { "endTime", "dtend" },
1099                                                   { "isAllDay", "allDay" },
1100                                                   { "timeZone", "eventTimezone" },
1101                                                   { "description", "description" }};
1102     SetFieldInfo(eventKey, queryField, resultSetField, eventField);
1103 }
1104 }