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