lib: included tzwrapper in Barry and Barrified the namespace
[barry.git] / src / tzwrapper.h
blob8a6a5c8060549006f7b53abd219d444502dedcce
1 ///
2 /// \file tzwrapper.h
3 /// Timezone adjustment class, wrapping the TZ environment
4 /// variable to make struct tm -> time_t conversions easier.
5 ///
7 /*
8 Copyright (C) 2010, Chris Frey <cdfrey@foursquare.net>, To God be the glory
9 Released to the public domain.
10 Included in Barry and Barrified the namespace July 2010
13 #ifndef __TZWRAPPER_H__
15 #include "dll.h"
16 #include <string>
17 #include <time.h>
18 #include <stdlib.h>
20 namespace Barry { namespace Sync {
22 /// Parses ISO timestamp in the format of YYYYMMDDTHHMMSS[Z]
23 /// and places broken down time in result.
24 /// The trailing Z is optional in the format.
25 /// If the Z exists, utc will be set to true, otherwise false.
26 /// Returns NULL on error.
27 /// Thread-safe.
28 BXEXPORT struct tm* iso_to_tm(const char *timestamp,
29 struct tm *result,
30 bool &utc);
32 /// utc_mktime() converts a struct tm that contains
33 /// broken down time in utc to a time_t. This function uses
34 /// a brute-force method of conversion that does not require
35 /// the environment variable TZ to be changed at all, and is
36 /// therefore slightly more thread-safe in that regard.
37 ///
38 /// The difference between mktime() and utc_mktime() is that
39 /// standard mktime() expects the struct tm to be in localtime,
40 /// according to the current TZ and system setting, while utc_mktime()
41 /// always assumes that the struct tm is in UTC, and converts it
42 /// to time_t regardless of what TZ is currently set.
43 ///
44 /// The difference between utc_mktime() and TzWrapper::iso_mktime()
45 /// is that iso_mktime() will parse straight from an ISO string,
46 /// and if the ISO timestamp ends in a 'Z', it will behave like
47 /// utc_mktime() except it will alter the TZ environment variable
48 /// to do it. If the ISO timestamp has no 'Z', then iso_mktime()
49 /// behaves like mktime().
50 ///
51 BXEXPORT time_t utc_mktime(struct tm *utctime);
54 // class TzWrapper
56 /// Wrapper class for the TZ environment variable. This class allows
57 /// setting TZ to any number of variables, and will restore the original
58 /// setting on destruction.
59 ///
60 /// By default, TzWrapper does not change the environment at all, but
61 /// only saves it. Alternately, you can use the timezone constructor
62 /// to save and set a new timezone on the fly.
63 ///
64 /// Each Set() and Unset() function returns a reference to TzWrapper,
65 /// so that you can chain function calls like this:
66 ///
67 /// time_t utc = TzWrapper("Canada/Pacific").mktime(&pacific_tm);
68 ///
69 /// In addition, there are two static utility functions used to
70 /// convert ISO timestamps to struct tm* and time_t values.
71 ///
72 /// Note: This class is not thread-safe, since it modifies the TZ
73 /// environment variable without locking. If other threads
74 /// use time functions, this may interfere with their behaviour.
75 ///
76 class BXEXPORT TzWrapper
78 std::string m_orig_tz;
79 bool m_tz_exists;
80 bool m_dirty;
82 protected:
83 void SaveTz()
85 char *ptz = getenv("TZ");
86 if( ptz )
87 m_orig_tz = ptz;
88 m_tz_exists = ptz;
91 void RestoreTz()
93 if( m_dirty ) {
94 if( m_tz_exists )
95 Set(m_orig_tz.c_str());
96 else
97 Unset();
99 m_dirty = false;
103 public:
104 /// Does not change TZ, only saves current setting
105 TzWrapper()
106 : m_dirty(false)
108 SaveTz();
111 /// Saves current setting and sets TZ to new timezone value.
112 /// If timezone is null, it is the same as calling Unset().
113 explicit TzWrapper(const char *timezone)
114 : m_dirty(false)
116 SaveTz();
117 Set(timezone);
120 ~TzWrapper()
122 RestoreTz();
125 /// Set TZ to a new value. If timezone is null, it is the
126 /// same as calling Unset().
128 /// If timezone is an empty or invalid timezone string, it
129 /// is the same as calling SetUTC().
130 TzWrapper& Set(const char *timezone)
132 if( timezone )
133 setenv("TZ", timezone, 1);
134 else
135 unsetenv("TZ");
136 tzset();
137 m_dirty = true;
138 return *this;
141 /// Deletes TZ from the environment, which has the same effect
142 /// as calling SetSysLocal(). This is not a permanent
143 /// condition, since TZ will be restored to original state
144 /// upon destruction.
145 TzWrapper& Unset()
147 unsetenv("TZ");
148 tzset();
149 m_dirty = true;
150 return *this;
153 /// Set timezone to UTC
154 TzWrapper& SetUTC()
156 return Set("");
159 /// Use system localtime. This overrides any TZ value that the
160 /// user may have set before running your program.
161 TzWrapper& SetSysLocal()
163 return Unset();
166 /// Use the default TZ value that the user set before running
167 /// this program. In most cases, this will be the user's
168 /// preferred local timezone.
169 TzWrapper& SetDefault()
171 RestoreTz();
172 return *this;
174 /// Same as SetDefault()
175 TzWrapper& SetOrig()
177 return SetDefault();
181 // C library wrappers, for calls like:
182 // time_t t = TzWrapper("Canada/Pacific").mktime(tm);
184 char* asctime(const struct tm *t) const { return ::asctime(t); }
185 char* asctime_r(const struct tm *t, char *buf) const
186 { return ::asctime_r(t, buf); }
187 char* ctime(const time_t *t) const { return ::ctime(t); }
188 char* ctime_r(const time_t *t, char *buf) const
189 { return ::ctime_r(t, buf); }
190 struct tm* gmtime(const time_t *t) const { return ::gmtime(t); }
191 struct tm* gmtime_r(const time_t *t, struct tm *result) const
192 { return ::gmtime_r(t, result); }
193 struct tm* localtime(const time_t *t) const { return ::localtime(t); }
194 struct tm* localtime_r(const time_t *t, struct tm *result) const
195 { return ::localtime_r(t, result); }
196 time_t mktime(struct tm *t) { return ::mktime(t); }
199 // Additional utility functions
202 /// Converts an ISO timestamp (YYYYMMDDTHHMMWW[Z]) into a
203 /// unix time_t. If the 'Z' UTC flag is not specified, then
204 /// the timestamp will be assumed to be in the current
205 /// default timezone. Otherwise, SetUTC() will be used for the
206 /// conversion.
208 /// This function uses an internal TzWrapper to adjust TZ
209 /// if necessary, which is why it is a static function
210 /// of TzWrapper, instead of a standalone function.
212 static time_t iso_mktime(const char *timestamp);
215 }} // namespace Barry::Sync
217 #endif