i3 - improved tiling WM


Add tztime module to support multiple different timezones.

Patch status: merged

Patch by Emil Mikulic

To apply this patch, use:
curl http://cr.i3wm.org/patch/42/raw.patch | git am

b/i3status.c

18
@@ -239,7 +239,13 @@ int main(int argc, char *argv[]) {
19
         };
20
 
21
         cfg_opt_t time_opts[] = {
22
-                CFG_STR("format", "%d.%m.%Y %H:%M:%S", CFGF_NONE),
23
+                CFG_STR("format", "%Y-%m-%d %H:%M:%S", CFGF_NONE),
24
+                CFG_END()
25
+        };
26
+
27
+        cfg_opt_t tztime_opts[] = {
28
+                CFG_STR("format", "%Y-%m-%d %H:%M:%S %Z", CFGF_NONE),
29
+                CFG_STR("timezone", "", CFGF_NONE),
30
                 CFG_END()
31
         };
32
 
33
@@ -292,6 +298,7 @@ int main(int argc, char *argv[]) {
34
                 CFG_SEC("volume", volume_opts, CFGF_TITLE | CFGF_MULTI),
35
                 CFG_SEC("ipv6", ipv6_opts, CFGF_NONE),
36
                 CFG_SEC("time", time_opts, CFGF_NONE),
37
+                CFG_SEC("tztime", tztime_opts, CFGF_TITLE | CFGF_MULTI),
38
                 CFG_SEC("ddate", ddate_opts, CFGF_NONE),
39
                 CFG_SEC("load", load_opts, CFGF_NONE),
40
                 CFG_SEC("cpu_usage", usage_opts, CFGF_NONE),
41
@@ -403,16 +410,9 @@ int main(int argc, char *argv[]) {
42
          * (!), not individual plugins, seem very unlikely. */
43
         char buffer[4096];
44
 
45
-        struct tm tm;
46
         while (1) {
47
                 struct timeval tv;
48
                 gettimeofday(&tv, NULL);
49
-                time_t current_time = tv.tv_sec;
50
-                struct tm *current_tm = NULL;
51
-                if (current_time != (time_t) -1) {
52
-                        localtime_r(&current_time, &tm);
53
-                        current_tm = &tm;
54
-                }
55
                 if (output_format == O_I3BAR)
56
                         yajl_gen_array_open(json_gen);
57
                 for (j = 0; j < cfg_size(cfg, "order"); j++) {
58
@@ -465,13 +465,19 @@ int main(int argc, char *argv[]) {
59
 
60
                         CASE_SEC("time") {
61
                                 SEC_OPEN_MAP("time");
62
-                                print_time(json_gen, buffer, cfg_getstr(sec, "format"), current_tm);
63
+                                print_time(json_gen, buffer, cfg_getstr(sec, "format"), NULL, tv.tv_sec);
64
+                                SEC_CLOSE_MAP;
65
+                        }
66
+
67
+                        CASE_SEC_TITLE("tztime") {
68
+                                SEC_OPEN_MAP("tztime");
69
+                                print_time(json_gen, buffer, cfg_getstr(sec, "format"), cfg_getstr(sec, "timezone"), tv.tv_sec);
70
                                 SEC_CLOSE_MAP;
71
                         }
72
 
73
                         CASE_SEC("ddate") {
74
                                 SEC_OPEN_MAP("ddate");
75
-                                print_ddate(json_gen, buffer, cfg_getstr(sec, "format"), current_tm);
76
+                                print_ddate(json_gen, buffer, cfg_getstr(sec, "format"), tv.tv_sec);
77
                                 SEC_CLOSE_MAP;
78
                         }
79
 

b/i3status.conf

84
@@ -19,7 +19,7 @@ order += "wireless wlan0"
85
 order += "ethernet eth0"
86
 order += "battery 0"
87
 order += "load"
88
-order += "time"
89
+order += "tztime local"
90
 
91
 wireless wlan0 {
92
         format_up = "W: (%quality at %essid) %ip"
93
@@ -44,7 +44,7 @@ run_watch VPN {
94
         pidfile = "/var/run/vpnc/pid"
95
 }
96
 
97
-time {
98
+tztime local {
99
         format = "%Y-%m-%d %H:%M:%S"
100
 }
101
 

b/include/i3status.h

106
@@ -137,11 +137,14 @@ char *endcolor() __attribute__ ((pure));
107
 /* src/auto_detect_format.c */
108
 char *auto_detect_format();
109
 
110
+/* src/print_time.c */
111
+void set_timezone(const char *timezone);
112
+
113
 void print_ipv6_info(yajl_gen json_gen, char *buffer, const char *format_up, const char *format_down);
114
 void print_disk_info(yajl_gen json_gen, char *buffer, const char *path, const char *format);
115
 void print_battery_info(yajl_gen json_gen, char *buffer, int number, const char *path, const char *format, int low_threshold, char *threshold_type, bool last_full_capacity);
116
-void print_time(yajl_gen json_gen, char *buffer, const char *format, struct tm *current_tm);
117
-void print_ddate(yajl_gen json_gen, char *buffer, const char *format, struct tm *current_tm);
118
+void print_time(yajl_gen json_gen, char *buffer, const char *format, const char *timezone, time_t t);
119
+void print_ddate(yajl_gen json_gen, char *buffer, const char *format, time_t t);
120
 const char *get_ip_addr();
121
 void print_wireless_info(yajl_gen json_gen, char *buffer, const char *interface, const char *format_up, const char *format_down);
122
 void print_run_watch(yajl_gen json_gen, char *buffer, const char *title, const char *pidfile, const char *format);

b/man/i3status.man

127
@@ -56,7 +56,8 @@ order += "ethernet eth0"
128
 order += "battery 0"
129
 order += "cpu_temperature 0"
130
 order += "load"
131
-order += "time"
132
+order += "tztime local"
133
+order += "tztime berlin"
134
 
135
 wireless wlan0 {
136
         format_up = "W: (%quality at %essid, %bitrate) %ip"
137
@@ -83,8 +84,13 @@ run_watch VPN {
138
         pidfile = "/var/run/vpnc/pid"
139
 }
140
 
141
-time {
142
-	format = "%Y-%m-%d %H:%M:%S"
143
+tztime local {
144
+        format = "%Y-%m-%d %H:%M:%S"
145
+}
146
+
147
+tztime berlin {
148
+        format = "%Y-%m-%d %H:%M:%S %Z"
149
+        timezone = "Europe/Berlin"
150
 }
151
 
152
 load {
153
@@ -258,12 +264,31 @@ Gets the system load (number of processes waiting for CPU time in the last
154
 
155
 === Time
156
 
157
-Formats the current system time. See +strftime(3)+ for the format.
158
+Outputs the current time in the local timezone.
159
+To use a different timezone, you can set the TZ environment variable,
160
+or use the +tztime+ module.
161
+See +strftime(3)+ for details on the format string.
162
 
163
 *Example order*: +time+
164
 
165
 *Example format*: +%Y-%m-%d %H:%M:%S+
166
 
167
+=== TzTime
168
+
169
+Outputs the current time in the given timezone.
170
+If no timezone is given, local time will be used.
171
+See +strftime(3)+ for details on the format string.
172
+The system's timezone database is usually installed in +/usr/share/zoneinfo+.
173
+Files below that path make for valid timezone strings, e.g. for
174
++/usr/share/zoneinfo/Europe/Berlin+ you can set timezone to +Europe/Berlin+
175
+in the +tztime+ module.
176
+
177
+*Example order*: +tztime berlin+
178
+
179
+*Example format*: +%Y-%m-%d %H:%M:%S %Z+
180
+
181
+*Example timezone*: +Europe/Berlin+
182
+
183
 === DDate
184
 
185
 Outputs the current discordian date in user-specified format. See +ddate(1)+ for

b/src/print_ddate.c

190
@@ -204,11 +204,14 @@ struct disc_time *get_ddate(struct tm *current_tm) {
191
         return &dt;
192
 }
193
 
194
-void print_ddate(yajl_gen json_gen, char *buffer, const char *format, struct tm *current_tm) {
195
+void print_ddate(yajl_gen json_gen, char *buffer, const char *format, time_t t) {
196
         char *outwalk = buffer;
197
         static char *form = NULL;
198
+        struct tm current_tm;
199
         struct disc_time *dt;
200
-        if ((dt = get_ddate(current_tm)) == NULL)
201
+        set_timezone(NULL);  /* Use local time. */
202
+        localtime_r(&t, &current_tm);
203
+        if ((dt = get_ddate(&current_tm)) == NULL)
204
                 return;
205
         if (form == NULL)
206
                 if ((form = malloc(strlen(format) + 1)) == NULL)

b/src/print_time.c

211
@@ -7,12 +7,39 @@
212
 
213
 #include "i3status.h"
214
 
215
-void print_time(yajl_gen json_gen, char *buffer, const char *format, struct tm *current_tm) {
216
+static int local_timezone_init = 0;
217
+static const char *local_timezone = NULL;
218
+static const char *current_timezone = NULL;
219
+
220
+void set_timezone(const char *timezone) {
221
+        if (!local_timezone_init) {
222
+                /* First call, initialize. */
223
+                local_timezone = getenv("TZ");
224
+                local_timezone_init = 1;
225
+        }
226
+        if (timezone == NULL || timezone[0] == '\0') {
227
+                /* User wants localtime. */
228
+                timezone = local_timezone;
229
+        }
230
+        if (timezone != current_timezone) {
231
+                if (timezone) {
232
+                        setenv("TZ", timezone, 1);
233
+                } else {
234
+                        unsetenv("TZ");
235
+                }
236
+                tzset();
237
+                current_timezone = timezone;
238
+        }
239
+}
240
+
241
+void print_time(yajl_gen json_gen, char *buffer, const char *format, const char *timezone, time_t t) {
242
         char *outwalk = buffer;
243
-        if (current_tm == NULL)
244
-                return;
245
-        /* Get date & time */
246
-        outwalk += strftime(outwalk, 4095, format, current_tm);
247
+        struct tm tm;
248
+
249
+        /* Convert time and format output. */
250
+        set_timezone(timezone);
251
+        localtime_r(&t, &tm);
252
+        outwalk += strftime(outwalk, 4095, format, &tm);
253
         *outwalk = '\0';
254
         OUTPUT_FULL_TEXT(buffer);
255
 }