Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-dev by
mbed_mktime.c
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2017-2017 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include "mbed_mktime.h" 00018 00019 /* Time constants. */ 00020 #define SECONDS_BY_MINUTES 60 00021 #define MINUTES_BY_HOUR 60 00022 #define SECONDS_BY_HOUR (SECONDS_BY_MINUTES * MINUTES_BY_HOUR) 00023 #define HOURS_BY_DAY 24 00024 #define SECONDS_BY_DAY (SECONDS_BY_HOUR * HOURS_BY_DAY) 00025 #define LAST_VALID_YEAR 206 00026 00027 /* Macros which will be used to determine if we are within valid range. */ 00028 #define EDGE_TIMESTAMP_FULL_LEAP_YEAR_SUPPORT 3220095 // 7th of February 1970 at 06:28:15 00029 #define EDGE_TIMESTAMP_4_YEAR_LEAP_YEAR_SUPPORT 3133695 // 6th of February 1970 at 06:28:15 00030 00031 /* 00032 * 2 dimensional array containing the number of seconds elapsed before a given 00033 * month. 00034 * The second index map to the month while the first map to the type of year: 00035 * - 0: non leap year 00036 * - 1: leap year 00037 */ 00038 static const uint32_t seconds_before_month[2][12] = { 00039 { 00040 0, 00041 31 * SECONDS_BY_DAY, 00042 (31 + 28) * SECONDS_BY_DAY, 00043 (31 + 28 + 31) * SECONDS_BY_DAY, 00044 (31 + 28 + 31 + 30) * SECONDS_BY_DAY, 00045 (31 + 28 + 31 + 30 + 31) * SECONDS_BY_DAY, 00046 (31 + 28 + 31 + 30 + 31 + 30) * SECONDS_BY_DAY, 00047 (31 + 28 + 31 + 30 + 31 + 30 + 31) * SECONDS_BY_DAY, 00048 (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31) * SECONDS_BY_DAY, 00049 (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30) * SECONDS_BY_DAY, 00050 (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31) * SECONDS_BY_DAY, 00051 (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30) * SECONDS_BY_DAY, 00052 }, 00053 { 00054 0, 00055 31 * SECONDS_BY_DAY, 00056 (31 + 29) * SECONDS_BY_DAY, 00057 (31 + 29 + 31) * SECONDS_BY_DAY, 00058 (31 + 29 + 31 + 30) * SECONDS_BY_DAY, 00059 (31 + 29 + 31 + 30 + 31) * SECONDS_BY_DAY, 00060 (31 + 29 + 31 + 30 + 31 + 30) * SECONDS_BY_DAY, 00061 (31 + 29 + 31 + 30 + 31 + 30 + 31) * SECONDS_BY_DAY, 00062 (31 + 29 + 31 + 30 + 31 + 30 + 31 + 31) * SECONDS_BY_DAY, 00063 (31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30) * SECONDS_BY_DAY, 00064 (31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31) * SECONDS_BY_DAY, 00065 (31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30) * SECONDS_BY_DAY, 00066 } 00067 }; 00068 00069 bool _rtc_is_leap_year(int year, rtc_leap_year_support_t leap_year_support) { 00070 /* 00071 * since in practice, the value manipulated by this algorithm lie in the 00072 * range: [70 : 206] the algorithm can be reduced to: year % 4 with exception for 200 (year 2100 is not leap year). 00073 * The algorithm valid over the full range of value is: 00074 00075 year = 1900 + year; 00076 if (year % 4) { 00077 return false; 00078 } else if (year % 100) { 00079 return true; 00080 } else if (year % 400) { 00081 return false; 00082 } 00083 return true; 00084 00085 */ 00086 if (leap_year_support == RTC_FULL_LEAP_YEAR_SUPPORT && year == 200) { 00087 return false; // 2100 is not a leap year 00088 } 00089 00090 return (year) % 4 ? false : true; 00091 } 00092 00093 bool _rtc_maketime(const struct tm* time, time_t * seconds, rtc_leap_year_support_t leap_year_support) { 00094 if (seconds == NULL || time == NULL) { 00095 return false; 00096 } 00097 00098 /* Partial check for the upper bound of the range - check years only. Full check will be performed after the 00099 * elapsed time since the beginning of the year is calculated. 00100 */ 00101 if ((time->tm_year < 70) || (time->tm_year > LAST_VALID_YEAR)) { 00102 return false; 00103 } 00104 00105 uint32_t result = time->tm_sec; 00106 result += time->tm_min * SECONDS_BY_MINUTES; 00107 result += time->tm_hour * SECONDS_BY_HOUR; 00108 result += (time->tm_mday - 1) * SECONDS_BY_DAY; 00109 result += seconds_before_month[_rtc_is_leap_year(time->tm_year, leap_year_support)][time->tm_mon]; 00110 00111 /* Check if we are within valid range. */ 00112 if (time->tm_year == LAST_VALID_YEAR) { 00113 if ((leap_year_support == RTC_FULL_LEAP_YEAR_SUPPORT && result > EDGE_TIMESTAMP_FULL_LEAP_YEAR_SUPPORT) || 00114 (leap_year_support == RTC_4_YEAR_LEAP_YEAR_SUPPORT && result > EDGE_TIMESTAMP_4_YEAR_LEAP_YEAR_SUPPORT)) { 00115 return false; 00116 } 00117 } 00118 00119 if (time->tm_year > 70) { 00120 /* Valid in the range [70:206]. */ 00121 uint32_t count_of_leap_days = ((time->tm_year - 1) / 4) - (70 / 4); 00122 if (leap_year_support == RTC_FULL_LEAP_YEAR_SUPPORT) { 00123 if (time->tm_year > 200) { 00124 count_of_leap_days--; // 2100 is not a leap year 00125 } 00126 } 00127 00128 result += (((time->tm_year - 70) * 365) + count_of_leap_days) * SECONDS_BY_DAY; 00129 } 00130 00131 *seconds = result; 00132 00133 return true; 00134 } 00135 00136 bool _rtc_localtime(time_t timestamp, struct tm* time_info, rtc_leap_year_support_t leap_year_support) { 00137 if (time_info == NULL) { 00138 return false; 00139 } 00140 00141 uint32_t seconds = (uint32_t)timestamp; 00142 00143 time_info->tm_sec = seconds % 60; 00144 seconds = seconds / 60; // timestamp in minutes 00145 time_info->tm_min = seconds % 60; 00146 seconds = seconds / 60; // timestamp in hours 00147 time_info->tm_hour = seconds % 24; 00148 seconds = seconds / 24; // timestamp in days; 00149 00150 /* Compute the weekday. 00151 * The 1st of January 1970 was a Thursday which is equal to 4 in the weekday representation ranging from [0:6]. 00152 */ 00153 time_info->tm_wday = (seconds + 4) % 7; 00154 00155 /* Years start at 70. */ 00156 time_info->tm_year = 70; 00157 while (true) { 00158 if (_rtc_is_leap_year(time_info->tm_year, leap_year_support) && seconds >= 366) { 00159 ++time_info->tm_year; 00160 seconds -= 366; 00161 } else if (!_rtc_is_leap_year(time_info->tm_year, leap_year_support) && seconds >= 365) { 00162 ++time_info->tm_year; 00163 seconds -= 365; 00164 } else { 00165 /* The remaining days are less than a years. */ 00166 break; 00167 } 00168 } 00169 00170 time_info->tm_yday = seconds; 00171 00172 /* Convert days into seconds and find the current month. */ 00173 seconds *= SECONDS_BY_DAY; 00174 time_info->tm_mon = 11; 00175 bool leap = _rtc_is_leap_year(time_info->tm_year, leap_year_support); 00176 for (uint32_t i = 0; i < 12; ++i) { 00177 if ((uint32_t) seconds < seconds_before_month[leap][i]) { 00178 time_info->tm_mon = i - 1; 00179 break; 00180 } 00181 } 00182 00183 /* Remove month from timestamp and compute the number of days. 00184 * Note: unlike other fields, days are not 0 indexed. 00185 */ 00186 seconds -= seconds_before_month[leap][time_info->tm_mon]; 00187 time_info->tm_mday = (seconds / SECONDS_BY_DAY) + 1; 00188 00189 return true; 00190 }
Generated on Tue Jul 12 2022 20:37:46 by
