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.
Dependents: WebTimer DISCO-F746NG_light_control_system_tth
Timezone.cpp
00001 /*----------------------------------------------------------------------* 00002 * Arduino Timezone Library * 00003 * Jack Christensen Mar 2012 * 00004 * * 00005 * Arduino Timezone Library Copyright (C) 2018 by Jack Christensen and * 00006 * licensed under GNU GPL v3.0, https://www.gnu.org/licenses/gpl.html * 00007 *----------------------------------------------------------------------*/ 00008 #include "Timezone.h" 00009 #include "mbed_mktime.h" 00010 00011 /*----------------------------------------------------------------------* 00012 * Create a Timezone object from the given time change rules. * 00013 *----------------------------------------------------------------------*/ 00014 Timezone::Timezone(TimeChangeRule dstStart, TimeChangeRule stdStart) : 00015 m_dst(dstStart), 00016 m_std(stdStart) 00017 { 00018 initTimeChanges(); 00019 } 00020 00021 /*----------------------------------------------------------------------* 00022 * Create a Timezone object for a zone that does not observe * 00023 * daylight time. * 00024 *----------------------------------------------------------------------*/ 00025 Timezone::Timezone(TimeChangeRule stdTime) : 00026 m_dst(stdTime), 00027 m_std(stdTime) 00028 { 00029 initTimeChanges(); 00030 } 00031 00032 /*----------------------------------------------------------------------* 00033 * Convert the given UTC time to local time, standard or * 00034 * daylight time, as appropriate. * 00035 *----------------------------------------------------------------------*/ 00036 time_t Timezone::toLocal(time_t utc) 00037 { 00038 // recalculate the time change points if needed 00039 00040 if (year(utc) != year(m_dstUTC)) 00041 calcTimeChanges(year(utc)); 00042 00043 if (utcIsDST(utc)) 00044 return utc + m_dst.offset * SECS_PER_MIN; 00045 else 00046 return utc + m_std.offset * SECS_PER_MIN; 00047 } 00048 00049 /*----------------------------------------------------------------------* 00050 * Convert the given UTC time to local time, standard or * 00051 * daylight time, as appropriate, and return a pointer to the time * 00052 * change rule used to do the conversion. The caller must take care * 00053 * not to alter this rule. * 00054 *----------------------------------------------------------------------*/ 00055 time_t Timezone::toLocal(time_t utc, TimeChangeRule ** tcr) 00056 { 00057 // recalculate the time change points if needed 00058 00059 if (year(utc) != year(m_dstUTC)) 00060 calcTimeChanges(year(utc)); 00061 00062 if (utcIsDST(utc)) { 00063 *tcr = &m_dst; 00064 return utc + m_dst.offset * SECS_PER_MIN; 00065 } 00066 else { 00067 *tcr = &m_std; 00068 return utc + m_std.offset * SECS_PER_MIN; 00069 } 00070 } 00071 00072 /*----------------------------------------------------------------------* 00073 * Convert the given local time to UTC time. * 00074 * * 00075 * WARNING: * 00076 * This function is provided for completeness, but should seldom be * 00077 * needed and should be used sparingly and carefully. * 00078 * * 00079 * Ambiguous situations occur after the Standard-to-DST and the * 00080 * DST-to-Standard time transitions. When changing to DST, there is * 00081 * one hour of local time that does not exist, since the clock moves * 00082 * forward one hour. Similarly, when changing to standard time, there * 00083 * is one hour of local times that occur twice since the clock moves * 00084 * back one hour. * 00085 * * 00086 * This function does not test whether it is passed an erroneous time * 00087 * value during the Local -> DST transition that does not exist. * 00088 * If passed such a time, an incorrect UTC time value will be returned. * 00089 * * 00090 * If passed a local time value during the DST -> Local transition * 00091 * that occurs twice, it will be treated as the earlier time, i.e. * 00092 * the time that occurs before the transistion. * 00093 * * 00094 * Calling this function with local times during a transition interval * 00095 * should be avoided! * 00096 *----------------------------------------------------------------------*/ 00097 time_t Timezone::toUTC(time_t local) 00098 { 00099 // recalculate the time change points if needed 00100 00101 if (year(local) != year(m_dstLoc)) 00102 calcTimeChanges(year(local)); 00103 00104 if (locIsDST(local)) 00105 return local - m_dst.offset * SECS_PER_MIN; 00106 else 00107 return local - m_std.offset * SECS_PER_MIN; 00108 } 00109 00110 /*----------------------------------------------------------------------* 00111 * Determine whether the given UTC time_t is within the DST interval * 00112 * or the Standard time interval. * 00113 *----------------------------------------------------------------------*/ 00114 bool Timezone::utcIsDST(time_t utc) 00115 { 00116 // recalculate the time change points if needed 00117 00118 if (year(utc) != year(m_dstUTC)) 00119 calcTimeChanges(year(utc)); 00120 00121 if (m_stdUTC == m_dstUTC) // daylight time not observed in this tz 00122 return false; 00123 else 00124 if (m_stdUTC > m_dstUTC) // northern hemisphere 00125 return(utc >= m_dstUTC && utc < m_stdUTC); 00126 else 00127 // southern hemisphere 00128 return !(utc >= m_stdUTC && utc < m_dstUTC); 00129 } 00130 00131 /*----------------------------------------------------------------------* 00132 * Determine whether the given Local time_t is within the DST interval * 00133 * or the Standard time interval. * 00134 *----------------------------------------------------------------------*/ 00135 bool Timezone::locIsDST(time_t local) 00136 { 00137 // recalculate the time change points if needed 00138 00139 if (year(local) != year(m_dstLoc)) 00140 calcTimeChanges(year(local)); 00141 00142 if (m_stdUTC == m_dstUTC) // daylight time not observed in this tz 00143 return false; 00144 else 00145 if (m_stdLoc > m_dstLoc) // northern hemisphere 00146 return(local >= m_dstLoc && local < m_stdLoc); 00147 else 00148 // southern hemisphere 00149 return !(local >= m_stdLoc && local < m_dstLoc); 00150 } 00151 00152 /*----------------------------------------------------------------------* 00153 * Calculate the DST and standard time change points for the given * 00154 * given year as local and UTC time_t values. * 00155 *----------------------------------------------------------------------*/ 00156 void Timezone::calcTimeChanges(int yr) 00157 { 00158 m_dstLoc = toTime_t(m_dst, yr); 00159 m_stdLoc = toTime_t(m_std, yr); 00160 m_dstUTC = m_dstLoc - m_std.offset * SECS_PER_MIN; 00161 m_stdUTC = m_stdLoc - m_dst.offset * SECS_PER_MIN; 00162 } 00163 00164 /*----------------------------------------------------------------------* 00165 * Initialize the DST and standard time change points. * 00166 *----------------------------------------------------------------------*/ 00167 void Timezone::initTimeChanges() 00168 { 00169 m_dstLoc = 0; 00170 m_stdLoc = 0; 00171 m_dstUTC = 0; 00172 m_stdUTC = 0; 00173 } 00174 00175 /*----------------------------------------------------------------------* 00176 * Convert the given time change rule to a time_t value * 00177 * for the given year. * 00178 *----------------------------------------------------------------------*/ 00179 time_t Timezone::toTime_t(TimeChangeRule r, int yr) 00180 { 00181 uint8_t m = r.month; // temp copies of r.month and r.week 00182 uint8_t w = r.week; 00183 if (w == 0) { 00184 00185 // is this a "Last week" rule? 00186 if (++m > 12) { 00187 00188 // yes, for "Last", go to the next month 00189 m = 1; 00190 ++yr; 00191 } 00192 00193 w = 1; // and treat as first week of next month, subtract 7 days later 00194 } 00195 00196 // calculate first day of the month, or for "Last" rules, first day of the next month 00197 tm tmTime; 00198 tmTime.tm_hour = r.hour; 00199 tmTime.tm_min = 0; 00200 tmTime.tm_sec = 0; 00201 tmTime.tm_mday = 1; 00202 tmTime.tm_mon = m; 00203 tmTime.tm_year = yr - 1970; 00204 00205 time_t t; 00206 _rtc_maketime(&tmTime, &t, RTC_FULL_LEAP_YEAR_SUPPORT); 00207 00208 // add offset from the first of the month to r.dow, and offset for the given week 00209 tm tmNow; 00210 00211 _rtc_localtime(t, &tmNow, RTC_FULL_LEAP_YEAR_SUPPORT); 00212 00213 t += ((r.dow - tmNow.tm_wday + 7) % 7 + (w - 1) * 7) * SECS_PER_DAY; 00214 00215 // back up a week if this is a "Last" rule 00216 if (r.week == 0) 00217 t -= 7 * SECS_PER_DAY; 00218 return t; 00219 } 00220 00221 /*----------------------------------------------------------------------* 00222 * Read or update the daylight and standard time rules from RAM. * 00223 *----------------------------------------------------------------------*/ 00224 void Timezone::setRules(TimeChangeRule dstStart, TimeChangeRule stdStart) 00225 { 00226 m_dst = dstStart; 00227 m_std = stdStart; 00228 initTimeChanges(); // force calcTimeChanges() at next conversion call 00229 } 00230 00231 /** 00232 * @brief 00233 * @note 00234 * @param 00235 * @retval 00236 */ 00237 int Timezone::year(time_t seconds) 00238 { 00239 tm tmNow; 00240 00241 _rtc_localtime(seconds, &tmNow, RTC_FULL_LEAP_YEAR_SUPPORT); 00242 return tmNow.tm_year; 00243 } 00244
Generated on Fri Jul 22 2022 10:00:39 by
1.7.2