on 76cbe21 help sign in
unity8/plugins/Utils/relativetimeformatter.cpp
268 lines 12 kB history raw
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
18// Local
19#include "relativetimeformatter.h"
21// Qt
22#include <QDateTime>
24// Other
25#include <glib.h>
26#include <glib/gi18n.h>
27#include <locale.h>
28#include <langinfo.h>
29#include <string.h>
31RelativeTimeFormatter::RelativeTimeFormatter(QObject *parent)
32 : GDateTimeFormatter(parent)
36 /* Check the system locale setting to see if the format is 24-hour
37 time or 12-hour time */
38gboolean
39is_locale_12h(void)
41 int i;
42 static const char *formats_24h[] = {"%H", "%R", "%T", "%OH", "%k", nullptr};
43 const char* t_fmt = nl_langinfo(T_FMT);
45 for (i=0; formats_24h[i]!=nullptr; i++)
46 if (strstr(t_fmt, formats_24h[i]) != nullptr)
47 return FALSE;
49 return TRUE;
52typedef enum
54 DATE_PROXIMITY_YESTERDAY,
55 DATE_PROXIMITY_TODAY,
56 DATE_PROXIMITY_TOMORROW,
57 DATE_PROXIMITY_LAST_WEEK,
58 DATE_PROXIMITY_NEXT_WEEK,
59 DATE_PROXIMITY_FAR
60} date_proximity_t;
62static date_proximity_t
63getDateProximity(GDateTime* now, GDateTime* time)
65 date_proximity_t prox = DATE_PROXIMITY_FAR;
66 gint now_year, now_month, now_day;
67 gint time_year, time_month, time_day;
69 // does it happen today?
70 g_date_time_get_ymd(now, &now_year, &now_month, &now_day);
71 g_date_time_get_ymd(time, &time_year, &time_month, &time_day);
72 if ((now_year == time_year) && (now_month == time_month) && (now_day == time_day)) {
73 return DATE_PROXIMITY_TODAY;
74 }
76 // did it happen yesterday?
77 GDateTime* tomorrow = g_date_time_add_days(now, -1);
78 gint tom_year, tom_month, tom_day;
79 g_date_time_get_ymd(tomorrow, &tom_year, &tom_month, &tom_day);
80 g_date_time_unref(tomorrow);
81 if ((tom_year == time_year) && (tom_month == time_month) && (tom_day == time_day)) {
82 return DATE_PROXIMITY_YESTERDAY;
83 }
85 // does it happen tomorrow?
86 if (prox == DATE_PROXIMITY_FAR)
87 {
88 GDateTime* tomorrow = g_date_time_add_days(now, 1);
90 gint tom_year, tom_month, tom_day;
91 g_date_time_get_ymd(tomorrow, &tom_year, &tom_month, &tom_day);
92 g_date_time_unref(tomorrow);
93 if ((tom_year == time_year) && (tom_month == time_month) && (tom_day == time_day)) {
94 return DATE_PROXIMITY_TOMORROW;
95 }
96 }
98 // does it happen this week?
99 if (prox == DATE_PROXIMITY_FAR) {
100 if (g_date_time_compare(time, now) < 0) {
101 GDateTime* last_week = g_date_time_add_days(now, -6);
102 GDateTime* last_week_bound = g_date_time_new_local(g_date_time_get_year(last_week),
103 g_date_time_get_month(last_week),
104 g_date_time_get_day_of_month(last_week),
105 0, 0, 0);
106 if (g_date_time_compare(time, last_week_bound) >= 0)
107 prox = DATE_PROXIMITY_LAST_WEEK;
109 g_date_time_unref(last_week);
110 g_date_time_unref(last_week_bound);
111 } else {
112 GDateTime* next_week = g_date_time_add_days(now, 6);
113 GDateTime* next_week_bound = g_date_time_new_local(g_date_time_get_year(next_week),
114 g_date_time_get_month(next_week),
115 g_date_time_get_day_of_month(next_week),
116 23, 59, 59.9);
117 if (g_date_time_compare(time, next_week_bound) <= 0)
118 prox = DATE_PROXIMITY_NEXT_WEEK;
120 g_date_time_unref(next_week);
121 g_date_time_unref(next_week_bound);
122 }
124 }
126 return prox;
129const char*
130dgettext_datetime(const char *text)
132 return dgettext("indicator-datetime", text);
135/**
136 * _ a time yesterday should be shown as (e.g. “Yesterday 3:55 PM”)
137 * _ a time today should be shown as just the time (e.g. “3:55 PM”)
138 * _ a time tomorrow should be shown as(e.g. “Tomorrow 3:55 PM”)
139 * _ a time any other day this week should be shown as the short version of the
140 * day and time (e.g. “Wed 3:55 PM”)
141 * weekday (e.g. “Friday”)
142 * _ a time after this week should be shown as the short version of the day,
143 * date, and time (e.g. “Wed 21 Apr 3:55 PM”)
144 * _ in addition, when presenting the times of upcoming events, the time should
145 * be followed by the timezone if it is different from the one the computer
146 * is currently set to. For example, “Wed 3:55 PM UTC−5”.
147 *
148 * TODO - keep inline with indicator-datetime
149 */
150char* generate_full_format_string_at_time (GDateTime* now,
151 GDateTime* then)
153 GString* ret = g_string_new (nullptr);
155 if (then != nullptr) {
156 const date_proximity_t prox = getDateProximity(now, then);
158 if (is_locale_12h()) {
159 switch (prox) {
160 case DATE_PROXIMITY_YESTERDAY:
161 /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
162 This format string is used for showing, on a 12-hour clock, times that happen yesterday.
163 (\u2003 is a unicode em space which is slightly wider than a normal space.)
164 en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 1:00 PM" */
165 g_string_assign (ret, dgettext_datetime("Yesterday\u2003%l:%M %p"));
166 break;
168 case DATE_PROXIMITY_TODAY:
169 /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
170 This format string is used for showing, on a 12-hour clock, times that happened today.
171 en_US example: "%l:%M %p" --> "1:00 PM" */
172 g_string_assign (ret, dgettext_datetime("%l:%M %p"));
173 break;
175 case DATE_PROXIMITY_TOMORROW:
176 /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
177 This format string is used for showing, on a 12-hour clock, events/appointments that happen tomorrow.
178 (\u2003 is a unicode em space which is slightly wider than a normal space.)
179 en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 1:00 PM" */
180 g_string_assign (ret, dgettext_datetime("Tomorrow\u2003%l:%M %p"));
181 break;
183 case DATE_PROXIMITY_LAST_WEEK:
184 case DATE_PROXIMITY_NEXT_WEEK:
185 /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
186 This format string is used for showing, on a 12-hour clock, times that happened in the last week.
187 (\u2003 is a unicode em space which is slightly wider than a normal space.)
188 en_US example: "%a\u2003%l:%M %p" --> "Fri 1:00 PM" */
189 g_string_assign (ret, dgettext_datetime("%a\u2003%l:%M %p"));
190 break;
192 case DATE_PROXIMITY_FAR:
193 /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
194 This format string is used for showing, on a 12-hour clock, times that happened before a week from now.
195 (\u2003 is a unicode em space which is slightly wider than a normal space.)
196 en_US example: "%a %d %b\u2003%l:%M %p" --> "Fri Oct 31 1:00 PM"
197 en_GB example: "%a %b %d\u2003%l:%M %p" --> "Fri 31 Oct 1:00 PM" */
198 g_string_assign (ret, dgettext_datetime("%a %d %b\u2003%l:%M %p"));
199 break;
200 }
201 } else {
202 switch (prox) {
204 case DATE_PROXIMITY_YESTERDAY:
205 /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
206 This format string is used for showing, on a 24-hour clock, times that happen yesterday.
207 (\u2003 is a unicode em space which is slightly wider than a normal space.)
208 en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 13:00" */
209 g_string_assign (ret, dgettext_datetime("Yesterday\u2003%H:%M"));
210 break;
212 case DATE_PROXIMITY_TODAY:
213 /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
214 This format string is used for showing, on a 24-hour clock, times that happened today.
215 en_US example: "%H:%M" --> "13:00" */
216 g_string_assign (ret, dgettext_datetime("%H:%M"));
217 break;
219 case DATE_PROXIMITY_TOMORROW:
220 /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
221 This format string is used for showing, on a 24-hour clock, events/appointments that happen tomorrow.
222 (\u2003 is a unicode em space which is slightly wider than a normal space.)
223 en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 13:00" */
224 g_string_assign (ret, dgettext_datetime("Tomorrow\u2003%H:%M"));
225 break;
227 case DATE_PROXIMITY_LAST_WEEK:
228 case DATE_PROXIMITY_NEXT_WEEK:
229 /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
230 This format string is used for showing, on a 24-hour clock, times that happened in the last week.
231 (\u2003 is a unicode em space which is slightly wider than a normal space.)
232 en_US example: "%a\u2003%H:%M" --> "Fri 13:00" */
233 g_string_assign (ret, dgettext_datetime("%a\u2003%H:%M"));
234 break;
236 case DATE_PROXIMITY_FAR:
237 /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
238 This format string is used for showing, on a 24-hour clock, times that happened before a week from now.
239 (\u2003 is a unicode em space which is slightly wider than a normal space.)
240 en_US example: "%a %d %b\u2003%H:%M" --> "Fri Oct 31 13:00"
241 en_GB example: "%a %b %d\u2003%H:%M" --> "Fri 31 Oct 13:00" */
242 g_string_assign (ret, dgettext_datetime("%a %d %b\u2003%H:%M"));
243 break;
244 }
245 }
246 }
248 return g_string_free (ret, FALSE);
251QString RelativeTimeFormatter::format() const
253 GDateTime* now = g_date_time_new_from_unix_utc(QDateTime::currentMSecsSinceEpoch() / 1000);
254 if (!now) { return QString(); }
256 GDateTime* then = g_date_time_new_from_unix_local(time());
257 if (!then) { return QString(); }
259 char* time_format = generate_full_format_string_at_time(now, then);
261 QString str(QString::fromUtf8(time_format));
262 g_free(time_format);
264 g_date_time_unref(now);
265 g_date_time_unref(then);
267 return str;