ppp: minor cleanups to match other chatscripts order and documentation
[barry.git] / src / tzwrapper.h
blob24acd81e37058e687d4e5d4db5b58df891e2501d
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__
14 #define __TZWRAPPER_H__
16 #include "dll.h"
17 #include <string>
18 #include <time.h>
19 #include <stdlib.h>
21 namespace Barry { namespace Sync {
23 /// Parses ISO timestamp in the format of YYYYMMDDTHHMMSS[Z]
24 /// or YYYY-MM-DDTHH:MM:SS.uuu-HH:MM
25 /// and places broken down time in result.
26 /// The trailing Z is optional in the format.
27 /// If the Z exists, utc will be set to true, otherwise false.
28 /// If zoneminutes is not null, and if a timezone offset is
29 /// specified, it will be filled in and *zone set to true.
30 /// Otherwise, *zone will be set to false.
31 /// Returns NULL on error.
32 /// Thread-safe.
33 BXEXPORT struct tm* iso_to_tm(const char *timestamp,
34 struct tm *result,
35 bool &utc,
36 bool *zone = 0,
37 int *zoneminutes = 0);
39 /// Turns the struct tm into an ISO timestamp in the format
40 /// of YYYYMMDDTHHMMSS[Z]. The Z is appended if utc is true.
41 /// This function assumes that t contains sane values, and will
42 /// create the target string directly from its content.
43 /// Returns the ISO timestamp, or empty string on error.
44 /// If t contains sane values, this function should never fail.
45 /// Thread-safe.
46 BXEXPORT std::string tm_to_iso(const struct tm *t, bool utc);
48 /// utc_mktime() converts a struct tm that contains
49 /// broken down time in utc to a time_t. This function uses
50 /// a brute-force method of conversion that does not require
51 /// the environment variable TZ to be changed at all, and is
52 /// therefore slightly more thread-safe in that regard.
53 ///
54 /// The difference between mktime() and utc_mktime() is that
55 /// standard mktime() expects the struct tm to be in localtime,
56 /// according to the current TZ and system setting, while utc_mktime()
57 /// always assumes that the struct tm is in UTC, and converts it
58 /// to time_t regardless of what TZ is currently set.
59 ///
60 /// The difference between utc_mktime() and TzWrapper::iso_mktime()
61 /// is that iso_mktime() will parse straight from an ISO string,
62 /// and if the ISO timestamp ends in a 'Z', it will behave like
63 /// utc_mktime() except it will alter the TZ environment variable
64 /// to do it. If the ISO timestamp has no 'Z', then iso_mktime()
65 /// behaves like mktime().
66 ///
67 BXEXPORT time_t utc_mktime(struct tm *utctime);
70 // class TzWrapper
72 /// Wrapper class for the TZ environment variable. This class allows
73 /// setting TZ to any number of variables, and will restore the original
74 /// setting on destruction.
75 ///
76 /// By default, TzWrapper does not change the environment at all, but
77 /// only saves it. Alternately, you can use the timezone constructor
78 /// to save and set a new timezone on the fly.
79 ///
80 /// Each Set() and Unset() function returns a reference to TzWrapper,
81 /// so that you can chain function calls like this:
82 ///
83 /// time_t utc = TzWrapper("Canada/Pacific").mktime(&pacific_tm);
84 ///
85 /// In addition, there are two static utility functions used to
86 /// convert ISO timestamps to struct tm* and time_t values.
87 ///
88 /// Note: This class is not thread-safe, since it modifies the TZ
89 /// environment variable without locking. If other threads
90 /// use time functions, this may interfere with their behaviour.
91 ///
92 class BXEXPORT TzWrapper
94 std::string m_orig_tz;
95 bool m_tz_exists;
96 bool m_dirty;
98 protected:
99 void SaveTz()
101 char *ptz = getenv("TZ");
102 if( ptz )
103 m_orig_tz = ptz;
104 m_tz_exists = ptz;
107 void RestoreTz()
109 if( m_dirty ) {
110 if( m_tz_exists )
111 Set(m_orig_tz.c_str());
112 else
113 Unset();
115 m_dirty = false;
119 public:
120 /// Does not change TZ, only saves current setting
121 TzWrapper()
122 : m_dirty(false)
124 SaveTz();
127 /// Saves current setting and sets TZ to new timezone value.
128 /// If timezone is null, it is the same as calling Unset().
129 explicit TzWrapper(const char *timezone)
130 : m_dirty(false)
132 SaveTz();
133 Set(timezone);
136 ~TzWrapper()
138 RestoreTz();
141 /// Set TZ to a new value. If timezone is null, it is the
142 /// same as calling Unset().
144 /// If timezone is an empty or invalid timezone string, it
145 /// is the same as calling SetUTC().
146 TzWrapper& Set(const char *timezone)
148 if( timezone )
149 setenv("TZ", timezone, 1);
150 else
151 unsetenv("TZ");
152 tzset();
153 m_dirty = true;
154 return *this;
157 /// Deletes TZ from the environment, which has the same effect
158 /// as calling SetSysLocal(). This is not a permanent
159 /// condition, since TZ will be restored to original state
160 /// upon destruction.
161 TzWrapper& Unset()
163 unsetenv("TZ");
164 tzset();
165 m_dirty = true;
166 return *this;
169 /// Set timezone to UTC
170 TzWrapper& SetUTC()
172 return Set("");
175 /// Set timezone via offset in minutes
176 /// Negative minutes goes west, positive goes east
177 /// i.e. -05:00 is EST
178 TzWrapper& SetOffset(int zoneminutes);
180 /// Use system localtime. This overrides any TZ value that the
181 /// user may have set before running your program.
182 TzWrapper& SetSysLocal()
184 return Unset();
187 /// Use the default TZ value that the user set before running
188 /// this program. In most cases, this will be the user's
189 /// preferred local timezone.
190 TzWrapper& SetDefault()
192 RestoreTz();
193 return *this;
195 /// Same as SetDefault()
196 TzWrapper& SetOrig()
198 return SetDefault();
202 // C library wrappers, for calls like:
203 // time_t t = TzWrapper("Canada/Pacific").mktime(tm);
205 char* asctime(const struct tm *t) const { return ::asctime(t); }
206 char* asctime_r(const struct tm *t, char *buf) const
207 { return ::asctime_r(t, buf); }
208 char* ctime(const time_t *t) const { return ::ctime(t); }
209 char* ctime_r(const time_t *t, char *buf) const
210 { return ::ctime_r(t, buf); }
211 struct tm* gmtime(const time_t *t) const { return ::gmtime(t); }
212 struct tm* gmtime_r(const time_t *t, struct tm *result) const
213 { return ::gmtime_r(t, result); }
214 struct tm* localtime(const time_t *t) const { return ::localtime(t); }
215 struct tm* localtime_r(const time_t *t, struct tm *result) const
216 { return ::localtime_r(t, result); }
217 time_t mktime(struct tm *t) { return ::mktime(t); }
220 // Additional utility functions
223 /// Converts an ISO timestamp (YYYYMMDDTHHMMWW[Z]) into a
224 /// unix time_t. If the 'Z' UTC flag is not specified, then
225 /// the timestamp will be assumed to be in the current
226 /// default timezone. Otherwise, SetUTC() will be used for the
227 /// conversion.
229 /// This function uses an internal TzWrapper to adjust TZ
230 /// if necessary, which is why it is a static function
231 /// of TzWrapper, instead of a standalone function.
233 static time_t iso_mktime(const char *timestamp);
236 }} // namespace Barry::Sync
238 #endif