tzwrapper.h

Go to the documentation of this file.
00001 ///
00002 /// \file       tzwrapper.h
00003 ///             Timezone adjustment class, wrapping the TZ environment
00004 ///             variable to make struct tm -> time_t conversions easier.
00005 ///
00006 
00007 /*
00008     Copyright (C) 2010, Chris Frey <cdfrey@foursquare.net>, To God be the glory
00009     Released to the public domain.
00010     Included in Barry and Barrified the namespace July 2010
00011 */
00012 
00013 #ifndef __TZWRAPPER_H__
00014 
00015 #include "dll.h"
00016 #include <string>
00017 #include <time.h>
00018 #include <stdlib.h>
00019 
00020 namespace Barry { namespace Sync {
00021 
00022 /// Parses ISO timestamp in the format of YYYYMMDDTHHMMSS[Z]
00023 /// and places broken down time in result.
00024 /// The trailing Z is optional in the format.
00025 /// If the Z exists, utc will be set to true, otherwise false.
00026 /// Returns NULL on error.
00027 /// Thread-safe.
00028 BXEXPORT struct tm* iso_to_tm(const char *timestamp,
00029                                 struct tm *result,
00030                                 bool &utc);
00031 
00032 /// Turns the struct tm into an ISO timestamp in the format
00033 /// of YYYYMMDDTHHMMSS[Z].  The Z is appended if utc is true.
00034 /// This function assumes that t contains sane values, and will
00035 /// create the target string directly from its content.
00036 /// Returns the ISO timestamp, or empty string on error.
00037 /// If t contains sane values, this function should never fail.
00038 /// Thread-safe.
00039 BXEXPORT std::string tm_to_iso(const struct tm *t, bool utc);
00040 
00041 /// utc_mktime() converts a struct tm that contains
00042 /// broken down time in utc to a time_t.  This function uses
00043 /// a brute-force method of conversion that does not require
00044 /// the environment variable TZ to be changed at all, and is
00045 /// therefore slightly more thread-safe in that regard.
00046 ///
00047 /// The difference between mktime() and utc_mktime() is that
00048 /// standard mktime() expects the struct tm to be in localtime,
00049 /// according to the current TZ and system setting, while utc_mktime()
00050 /// always assumes that the struct tm is in UTC, and converts it
00051 /// to time_t regardless of what TZ is currently set.
00052 ///
00053 /// The difference between utc_mktime() and TzWrapper::iso_mktime()
00054 /// is that iso_mktime() will parse straight from an ISO string,
00055 /// and if the ISO timestamp ends in a 'Z', it will behave like
00056 /// utc_mktime() except it will alter the TZ environment variable
00057 /// to do it.  If the ISO timestamp has no 'Z', then iso_mktime()
00058 /// behaves like mktime().
00059 ///
00060 BXEXPORT time_t utc_mktime(struct tm *utctime);
00061 
00062 //
00063 // class TzWrapper
00064 //
00065 /// Wrapper class for the TZ environment variable.  This class allows
00066 /// setting TZ to any number of variables, and will restore the original
00067 /// setting on destruction.
00068 ///
00069 /// By default, TzWrapper does not change the environment at all, but
00070 /// only saves it.  Alternately, you can use the timezone constructor
00071 /// to save and set a new timezone on the fly.
00072 ///
00073 /// Each Set() and Unset() function returns a reference to TzWrapper,
00074 /// so that you can chain function calls like this:
00075 ///
00076 ///     time_t utc = TzWrapper("Canada/Pacific").mktime(&pacific_tm);
00077 ///
00078 /// In addition, there are two static utility functions used to
00079 /// convert ISO timestamps to struct tm* and time_t values.
00080 ///
00081 /// Note: This class is not thread-safe, since it modifies the TZ
00082 ///       environment variable without locking.  If other threads
00083 ///       use time functions, this may interfere with their behaviour.
00084 ///
00085 class BXEXPORT TzWrapper
00086 {
00087         std::string m_orig_tz;
00088         bool m_tz_exists;
00089         bool m_dirty;
00090 
00091 protected:
00092         void SaveTz()
00093         {
00094                 char *ptz = getenv("TZ");
00095                 if( ptz )
00096                         m_orig_tz = ptz;
00097                 m_tz_exists = ptz;
00098         }
00099 
00100         void RestoreTz()
00101         {
00102                 if( m_dirty ) {
00103                         if( m_tz_exists )
00104                                 Set(m_orig_tz.c_str());
00105                         else
00106                                 Unset();
00107 
00108                         m_dirty = false;
00109                 }
00110         }
00111 
00112 public:
00113         /// Does not change TZ, only saves current setting
00114         TzWrapper()
00115                 : m_dirty(false)
00116         {
00117                 SaveTz();
00118         }
00119 
00120         /// Saves current setting and sets TZ to new timezone value.
00121         /// If timezone is null, it is the same as calling Unset().
00122         explicit TzWrapper(const char *timezone)
00123                 : m_dirty(false)
00124         {
00125                 SaveTz();
00126                 Set(timezone);
00127         }
00128 
00129         ~TzWrapper()
00130         {
00131                 RestoreTz();
00132         }
00133 
00134         /// Set TZ to a new value.  If timezone is null, it is the
00135         /// same as calling Unset().
00136         ///
00137         /// If timezone is an empty or invalid timezone string, it
00138         /// is the same as calling SetUTC().
00139         TzWrapper& Set(const char *timezone)
00140         {
00141                 if( timezone )
00142                         setenv("TZ", timezone, 1);
00143                 else
00144                         unsetenv("TZ");
00145                 tzset();
00146                 m_dirty = true;
00147                 return *this;
00148         }
00149 
00150         /// Deletes TZ from the environment, which has the same effect
00151         /// as calling SetSysLocal().  This is not a permanent
00152         /// condition, since TZ will be restored to original state
00153         /// upon destruction.
00154         TzWrapper& Unset()
00155         {
00156                 unsetenv("TZ");
00157                 tzset();
00158                 m_dirty = true;
00159                 return *this;
00160         }
00161 
00162         /// Set timezone to UTC
00163         TzWrapper& SetUTC()
00164         {
00165                 return Set("");
00166         }
00167 
00168         /// Use system localtime.  This overrides any TZ value that the
00169         /// user may have set before running your program.
00170         TzWrapper& SetSysLocal()
00171         {
00172                 return Unset();
00173         }
00174 
00175         /// Use the default TZ value that the user set before running
00176         /// this program.  In most cases, this will be the user's
00177         /// preferred local timezone.
00178         TzWrapper& SetDefault()
00179         {
00180                 RestoreTz();
00181                 return *this;
00182         }
00183         /// Same as SetDefault()
00184         TzWrapper& SetOrig()
00185         {
00186                 return SetDefault();
00187         }
00188 
00189         //
00190         // C library wrappers, for calls like:
00191         //      time_t t = TzWrapper("Canada/Pacific").mktime(tm);
00192         //
00193         char* asctime(const struct tm *t) const { return ::asctime(t); }
00194         char* asctime_r(const struct tm *t, char *buf) const
00195                 { return ::asctime_r(t, buf); }
00196         char* ctime(const time_t *t) const { return ::ctime(t); }
00197         char* ctime_r(const time_t *t, char *buf) const
00198                 { return ::ctime_r(t, buf); }
00199         struct tm* gmtime(const time_t *t) const { return ::gmtime(t); }
00200         struct tm* gmtime_r(const time_t *t, struct tm *result) const
00201                 { return ::gmtime_r(t, result); }
00202         struct tm* localtime(const time_t *t) const { return ::localtime(t); }
00203         struct tm* localtime_r(const time_t *t, struct tm *result) const
00204                 { return ::localtime_r(t, result); }
00205         time_t mktime(struct tm *t) { return ::mktime(t); }
00206 
00207         //
00208         // Additional utility functions
00209         //
00210 
00211         /// Converts an ISO timestamp (YYYYMMDDTHHMMWW[Z]) into a
00212         /// unix time_t.  If the 'Z' UTC flag is not specified, then
00213         /// the timestamp will be assumed to be in the current
00214         /// default timezone.  Otherwise, SetUTC() will be used for the
00215         /// conversion.
00216         ///
00217         /// This function uses an internal TzWrapper to adjust TZ
00218         /// if necessary, which is why it is a static function
00219         /// of TzWrapper, instead of a standalone function.
00220         ///
00221         static time_t iso_mktime(const char *timestamp);
00222 };
00223 
00224 }} // namespace Barry::Sync
00225 
00226 #endif
00227 
Generated by  doxygen 1.6.2-20100208