1 /*
2  * Copyright (c) 2021 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 
16 #include "base/utils/time_util.h"
17 
18 #include <iomanip>
19 #include <sstream>
20 #include <sys/time.h>
21 #include "base/utils/utils.h"
22 
23 namespace OHOS::Ace {
24 namespace {
25 
26 constexpr int64_t SEC_TO_MICROSEC = 1000000;
27 constexpr int64_t SEC_TO_NANOSEC = 1000000000;
28 constexpr int64_t MICROSEC_TO_NANOSEC = 1000;
29 constexpr int64_t SEC_TO_MILLISEC = 1000;
30 constexpr int64_t MILLISEC_TO_MICROSEC = 1000;
31 constexpr int32_t HOURS_WEST_GEOGRAPHICAL_LOWER_LIMIT = -12;
32 constexpr int32_t HOURS_WEST_LOWER_LIMIT = -14;
33 constexpr int32_t HOURS_WEST_UPPER_LIMIT = 12;
34 constexpr int32_t TOTAL_SECONDS_OF_DAY = 24 * 60 * 60;
35 constexpr int32_t TOTAL_SECONDS_OF_HOUR = 60 * 60;
36 constexpr int32_t TOTAL_SECONDS_OF_MINUTE = 60;
37 constexpr int32_t TOTAL_MINUTE_OF_HOUR = 60;
38 constexpr int32_t TWENTY_FOUR_HOUR_BASE = 24;
39 constexpr int32_t TWELVE_HOUR_BASE = 12;
40 constexpr int32_t DAY_TIME_LOWER_LIMIT = 6;
41 constexpr int32_t DAY_TIME_UPPER_LIMIT = 18;
42 constexpr int32_t MAX_TIME_STR_LEN = 64;
43 } // namespace
44 
GetMicroTickCount()45 int64_t GetMicroTickCount()
46 {
47     struct timespec ts;
48     clock_gettime(CLOCK_MONOTONIC, &ts);
49     return (ts.tv_sec * SEC_TO_MICROSEC + ts.tv_nsec / MICROSEC_TO_NANOSEC);
50 }
51 
GetSysTimestamp()52 int64_t GetSysTimestamp()
53 {
54     struct timespec ts;
55     clock_gettime(CLOCK_MONOTONIC, &ts);
56     return ts.tv_sec * SEC_TO_NANOSEC + ts.tv_nsec;
57 }
58 
GetCurrentTimestamp()59 int64_t GetCurrentTimestamp()
60 {
61     struct timeval currentTime;
62     gettimeofday(&currentTime, nullptr);
63     return static_cast<int64_t>(currentTime.tv_sec) * SEC_TO_MILLISEC + currentTime.tv_usec / MILLISEC_TO_MICROSEC;
64 }
65 
GetCurrentTimestampMicroSecond()66 int64_t GetCurrentTimestampMicroSecond()
67 {
68     struct timeval currentTime;
69     gettimeofday(&currentTime, nullptr);
70     return static_cast<int64_t>(currentTime.tv_sec) * SEC_TO_MILLISEC * MILLISEC_TO_MICROSEC + currentTime.tv_usec;
71 }
72 
ConvertTimestampToStr(int64_t timestamp)73 std::string ConvertTimestampToStr(int64_t timestamp)
74 {
75     char timeStr[MAX_TIME_STR_LEN];
76     // timestamp is in millisecond unit, divide 1000 to second
77     auto t = static_cast<std::time_t>(timestamp / SEC_TO_MILLISEC);
78     auto local = std::localtime(&t);
79     if (!local) {
80         return "";
81     }
82     std::strftime(timeStr, MAX_TIME_STR_LEN, "%Y-%m-%d %H:%M:%S", local);
83     std::stringstream oss;
84     // milliseconds in timestr should be 3 characters length
85     oss << timeStr << "." << std::setw(3) << std::setfill('0') << (timestamp % SEC_TO_MILLISEC);
86     return oss.str();
87 }
88 
GetTimeOfNow(int32_t hoursWest)89 TimeOfNow GetTimeOfNow(int32_t hoursWest)
90 {
91     struct timeval currentTime;
92     struct timezone timeZone;
93     gettimeofday(&currentTime, &timeZone);
94 
95     TimeOfNow timeOfNow(hoursWest);
96     int32_t minutesWest = timeZone.tz_minuteswest;
97     if (IsHoursWestValid(timeOfNow.hoursWest_)) {
98         minutesWest = Round(TOTAL_MINUTE_OF_HOUR * timeOfNow.hoursWest_);
99     } else {
100         // when [hoursWest] is invalid, set current time zone to [hoursWest].
101         // default value of hoursWest_ is INT_MAX
102         if (!NearEqual(timeOfNow.hoursWest_, INT_MAX)) {
103             LOGW("hoursWest [%{public}d] is invalid, use current time zone.", timeOfNow.hoursWest_);
104         }
105         timeOfNow.hoursWest_ = timeZone.tz_minuteswest / TOTAL_MINUTE_OF_HOUR;
106     }
107     int secondsOfToday = currentTime.tv_sec % TOTAL_SECONDS_OF_DAY - minutesWest * TOTAL_SECONDS_OF_MINUTE;
108     if (secondsOfToday < 0) {
109         secondsOfToday += TOTAL_SECONDS_OF_DAY;
110     }
111     timeOfNow.minute_ = (secondsOfToday / TOTAL_SECONDS_OF_MINUTE) % TOTAL_MINUTE_OF_HOUR +
112                         secondsOfToday % TOTAL_SECONDS_OF_MINUTE / TOTAL_SECONDS_OF_MINUTE;
113     timeOfNow.hour24_ =
114         (secondsOfToday / TOTAL_SECONDS_OF_HOUR) % TWENTY_FOUR_HOUR_BASE + timeOfNow.minute_ / TOTAL_MINUTE_OF_HOUR;
115     timeOfNow.hour12_ =
116         (timeOfNow.hour24_ < TWELVE_HOUR_BASE) ? timeOfNow.hour24_ : (timeOfNow.hour24_ - TWELVE_HOUR_BASE);
117     timeOfNow.second_ = secondsOfToday % TOTAL_SECONDS_OF_MINUTE;
118     timeOfNow.timeUsec_ = currentTime.tv_usec;
119     return timeOfNow;
120 }
121 
IsHoursWestValid(int32_t & hoursWest)122 bool IsHoursWestValid(int32_t& hoursWest)
123 {
124     // valid hoursWest is within [-14, 12]
125     bool isValid = GreatOrEqual(hoursWest, HOURS_WEST_LOWER_LIMIT) && LessOrEqual(hoursWest, HOURS_WEST_UPPER_LIMIT);
126     if (!isValid) {
127         return false;
128     }
129     // Theoretically, the time zone range should be [-12, +12], but some countries and regions that cross the
130     // International Date Line use -13(UTC+13) and -14(UTC+14) to keep the whole country or region at the same date.
131     bool isSpecialTimeZone = LessNotEqual(hoursWest, HOURS_WEST_GEOGRAPHICAL_LOWER_LIMIT);
132     if (isSpecialTimeZone) {
133         hoursWest += TWENTY_FOUR_HOUR_BASE;
134     }
135     return true;
136 }
137 
IsDayTime(const TimeOfNow & timeOfNow)138 bool IsDayTime(const TimeOfNow& timeOfNow)
139 {
140     return GreatOrEqual(timeOfNow.hour24_, DAY_TIME_LOWER_LIMIT) &&
141            LessNotEqual(timeOfNow.hour24_, DAY_TIME_UPPER_LIMIT);
142 }
143 
GetTimeOfZone(int32_t hoursWest)144 TimeOfZone GetTimeOfZone(int32_t hoursWest)
145 {
146     struct timeval currentTime;
147     struct timezone timeZone;
148     gettimeofday(&currentTime, &timeZone);
149 
150     TimeOfZone timeOfZone(hoursWest);
151     int32_t minutesWest = timeZone.tz_minuteswest;
152     if (HoursWestIsValid(timeOfZone.hoursWest_)) {
153         minutesWest = Round(TOTAL_MINUTE_OF_HOUR * timeOfZone.hoursWest_);
154     } else {
155         // when [hoursWest] is invalid, set current time zone to [hoursWest].
156         // default value of hoursWest_ is DEFAULT_HOURS_WEST
157         if (!NearEqual(timeOfZone.hoursWest_, DEFAULT_HOURS_WEST)) {
158             LOGW("hoursWest [%{public}d] is invalid, use current time zone.", timeOfZone.hoursWest_);
159         }
160         timeOfZone.hoursWest_ = minutesWest / TOTAL_MINUTE_OF_HOUR;
161     }
162     int secondsOfToday = currentTime.tv_sec % TOTAL_SECONDS_OF_DAY - minutesWest * TOTAL_SECONDS_OF_MINUTE;
163     if (secondsOfToday < 0) {
164         secondsOfToday += TOTAL_SECONDS_OF_DAY;
165     }
166     timeOfZone.minute_ = (secondsOfToday / TOTAL_SECONDS_OF_MINUTE) % TOTAL_MINUTE_OF_HOUR +
167                         secondsOfToday % TOTAL_SECONDS_OF_MINUTE / TOTAL_SECONDS_OF_MINUTE;
168     timeOfZone.hour24_ =
169         (secondsOfToday / TOTAL_SECONDS_OF_HOUR) % TWENTY_FOUR_HOUR_BASE + timeOfZone.minute_ / TOTAL_MINUTE_OF_HOUR;
170     timeOfZone.hour12_ =
171         (timeOfZone.hour24_ < TWELVE_HOUR_BASE) ? timeOfZone.hour24_ : (timeOfZone.hour24_ - TWELVE_HOUR_BASE);
172     timeOfZone.second_ = secondsOfToday % TOTAL_SECONDS_OF_MINUTE;
173     timeOfZone.timeUsec_ = currentTime.tv_usec;
174     return timeOfZone;
175 }
176 
HoursWestIsValid(int32_t & hoursWest)177 bool HoursWestIsValid(int32_t& hoursWest)
178 {
179     // valid hoursWest is within [-14, 12]
180     bool isValid = GreatOrEqual(hoursWest, HOURS_WEST_LOWER_LIMIT) && LessOrEqual(hoursWest, HOURS_WEST_UPPER_LIMIT);
181     if (!isValid) {
182         return false;
183     }
184     // Theoretically, the time zone range should be [-12, +12], but some countries and regions that cross the
185     // International Date Line use -13(UTC+13) and -14(UTC+14) to keep the whole country or region at the same date.
186     bool isSpecialTimeZone = LessNotEqual(hoursWest, HOURS_WEST_GEOGRAPHICAL_LOWER_LIMIT);
187     if (isSpecialTimeZone) {
188         hoursWest += TWENTY_FOUR_HOUR_BASE;
189     }
190     return true;
191 }
192 
IsDayTime(const TimeOfZone & timeOfZone)193 bool IsDayTime(const TimeOfZone& timeOfZone)
194 {
195     return GreatOrEqual(timeOfZone.hour24_, DAY_TIME_LOWER_LIMIT) &&
196            LessNotEqual(timeOfZone.hour24_, DAY_TIME_UPPER_LIMIT);
197 }
198 
199 } // namespace OHOS::Ace
200