Unity 8
relativetimeformatter.cpp
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  */
17 
18 // Local
19 #include "relativetimeformatter.h"
20 
21 // Qt
22 #include <QDateTime>
23 
24 // Other
25 #include <glib.h>
26 #include <glib/gi18n.h>
27 #include <locale.h>
28 #include <langinfo.h>
29 #include <string.h>
30 
31 RelativeTimeFormatter::RelativeTimeFormatter(QObject *parent)
32  : GDateTimeFormatter(parent)
33 {
34 }
35 
36  /* Check the system locale setting to see if the format is 24-hour
37  time or 12-hour time */
38 gboolean
39 is_locale_12h(void)
40 {
41  int i;
42  static const char *formats_24h[] = {"%H", "%R", "%T", "%OH", "%k", nullptr};
43  const char* t_fmt = nl_langinfo(T_FMT);
44 
45  for (i=0; formats_24h[i]!=nullptr; i++)
46  if (strstr(t_fmt, formats_24h[i]) != nullptr)
47  return FALSE;
48 
49  return TRUE;
50 }
51 
52 typedef enum
53 {
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;
61 
62 static date_proximity_t
63 getDateProximity(GDateTime* now, GDateTime* time)
64 {
65  date_proximity_t prox = DATE_PROXIMITY_FAR;
66  gint now_year, now_month, now_day;
67  gint time_year, time_month, time_day;
68 
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  }
75 
76  // did it happen yesterday?
77  GDateTime* yesterday = g_date_time_add_days(now, -1);
78  gint tom_year, tom_month, tom_day;
79  g_date_time_get_ymd(yesterday, &tom_year, &tom_month, &tom_day);
80  g_date_time_unref(yesterday);
81  if ((tom_year == time_year) && (tom_month == time_month) && (tom_day == time_day)) {
82  return DATE_PROXIMITY_YESTERDAY;
83  }
84 
85  // does it happen tomorrow?
86  GDateTime* tomorrow = g_date_time_add_days(now, 1);
87  g_date_time_get_ymd(tomorrow, &tom_year, &tom_month, &tom_day);
88  g_date_time_unref(tomorrow);
89  if ((tom_year == time_year) && (tom_month == time_month) && (tom_day == time_day)) {
90  return DATE_PROXIMITY_TOMORROW;
91  }
92 
93  // does it happen this week?
94  if (g_date_time_compare(time, now) < 0) {
95  GDateTime* last_week = g_date_time_add_days(now, -6);
96  GDateTime* last_week_bound = g_date_time_new_local(g_date_time_get_year(last_week),
97  g_date_time_get_month(last_week),
98  g_date_time_get_day_of_month(last_week),
99  0, 0, 0);
100  if (g_date_time_compare(time, last_week_bound) >= 0)
101  prox = DATE_PROXIMITY_LAST_WEEK;
102 
103  g_date_time_unref(last_week);
104  g_date_time_unref(last_week_bound);
105  } else {
106  GDateTime* next_week = g_date_time_add_days(now, 6);
107  GDateTime* next_week_bound = g_date_time_new_local(g_date_time_get_year(next_week),
108  g_date_time_get_month(next_week),
109  g_date_time_get_day_of_month(next_week),
110  23, 59, 59.9);
111  if (g_date_time_compare(time, next_week_bound) <= 0)
112  prox = DATE_PROXIMITY_NEXT_WEEK;
113 
114  g_date_time_unref(next_week);
115  g_date_time_unref(next_week_bound);
116  }
117 
118  return prox;
119 }
120 
121 const char*
122 dgettext_datetime(const char *text)
123 {
124  return dgettext("indicator-datetime", text);
125 }
126 
142 char* generate_full_format_string_at_time (GDateTime* now,
143  GDateTime* then)
144 {
145  GString* ret = g_string_new (nullptr);
146 
147  if (then != nullptr) {
148  const date_proximity_t prox = getDateProximity(now, then);
149 
150  if (is_locale_12h()) {
151  switch (prox) {
152  case DATE_PROXIMITY_YESTERDAY:
153  /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
154  This format string is used for showing, on a 12-hour clock, times that happen yesterday.
155  (\u2003 is a unicode em space which is slightly wider than a normal space.)
156  en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 1:00 PM" */
157  g_string_assign (ret, dgettext_datetime("Yesterday\u2003%l:%M %p"));
158  break;
159 
160  case DATE_PROXIMITY_TODAY:
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 happened today.
163  en_US example: "%l:%M %p" --> "1:00 PM" */
164  g_string_assign (ret, dgettext_datetime("%l:%M %p"));
165  break;
166 
167  case DATE_PROXIMITY_TOMORROW:
168  /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
169  This format string is used for showing, on a 12-hour clock, events/appointments that happen tomorrow.
170  (\u2003 is a unicode em space which is slightly wider than a normal space.)
171  en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 1:00 PM" */
172  g_string_assign (ret, dgettext_datetime("Tomorrow\u2003%l:%M %p"));
173  break;
174 
175  case DATE_PROXIMITY_LAST_WEEK:
176  case DATE_PROXIMITY_NEXT_WEEK:
177  /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
178  This format string is used for showing, on a 12-hour clock, times that happened in the last week.
179  (\u2003 is a unicode em space which is slightly wider than a normal space.)
180  en_US example: "%a\u2003%l:%M %p" --> "Fri 1:00 PM" */
181  g_string_assign (ret, dgettext_datetime("%a\u2003%l:%M %p"));
182  break;
183 
184  case DATE_PROXIMITY_FAR:
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 before a week from now.
187  (\u2003 is a unicode em space which is slightly wider than a normal space.)
188  en_US example: "%a %d %b\u2003%l:%M %p" --> "Fri Oct 31 1:00 PM"
189  en_GB example: "%a %b %d\u2003%l:%M %p" --> "Fri 31 Oct 1:00 PM" */
190  g_string_assign (ret, dgettext_datetime("%a %d %b\u2003%l:%M %p"));
191  break;
192  }
193  } else {
194  switch (prox) {
195 
196  case DATE_PROXIMITY_YESTERDAY:
197  /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
198  This format string is used for showing, on a 24-hour clock, times that happen yesterday.
199  (\u2003 is a unicode em space which is slightly wider than a normal space.)
200  en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 13:00" */
201  g_string_assign (ret, dgettext_datetime("Yesterday\u2003%H:%M"));
202  break;
203 
204  case DATE_PROXIMITY_TODAY:
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 happened today.
207  en_US example: "%H:%M" --> "13:00" */
208  g_string_assign (ret, dgettext_datetime("%H:%M"));
209  break;
210 
211  case DATE_PROXIMITY_TOMORROW:
212  /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
213  This format string is used for showing, on a 24-hour clock, events/appointments that happen tomorrow.
214  (\u2003 is a unicode em space which is slightly wider than a normal space.)
215  en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 13:00" */
216  g_string_assign (ret, dgettext_datetime("Tomorrow\u2003%H:%M"));
217  break;
218 
219  case DATE_PROXIMITY_LAST_WEEK:
220  case DATE_PROXIMITY_NEXT_WEEK:
221  /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
222  This format string is used for showing, on a 24-hour clock, times that happened in the last week.
223  (\u2003 is a unicode em space which is slightly wider than a normal space.)
224  en_US example: "%a\u2003%H:%M" --> "Fri 13:00" */
225  g_string_assign (ret, dgettext_datetime("%a\u2003%H:%M"));
226  break;
227 
228  case DATE_PROXIMITY_FAR:
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 before a week from now.
231  (\u2003 is a unicode em space which is slightly wider than a normal space.)
232  en_US example: "%a %d %b\u2003%H:%M" --> "Fri Oct 31 13:00"
233  en_GB example: "%a %b %d\u2003%H:%M" --> "Fri 31 Oct 13:00" */
234  g_string_assign (ret, dgettext_datetime("%a %d %b\u2003%H:%M"));
235  break;
236  }
237  }
238  }
239 
240  return g_string_free (ret, FALSE);
241 }
242 
243 QString RelativeTimeFormatter::format() const
244 {
245  GDateTime* now = g_date_time_new_now_local();
246  if (!now) { return QString(); }
247 
248  GDateTime* then = g_date_time_new_from_unix_local(time());
249  if (!then) { return QString(); }
250 
251  char* time_format = generate_full_format_string_at_time(now, then);
252 
253  QString str(QString::fromUtf8(time_format));
254  g_free(time_format);
255 
256  g_date_time_unref(now);
257  g_date_time_unref(then);
258 
259  return str;
260 }