/* * Copyright 2014 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ // Local #include "relativetimeformatter.h" // Qt #include // Other #include #include #include #include #include RelativeTimeFormatter::RelativeTimeFormatter(QObject *parent) : GDateTimeFormatter(parent) { } /* Check the system locale setting to see if the format is 24-hour time or 12-hour time */ gboolean is_locale_12h(void) { int i; static const char *formats_24h[] = {"%H", "%R", "%T", "%OH", "%k", nullptr}; const char* t_fmt = nl_langinfo(T_FMT); for (i=0; formats_24h[i]!=nullptr; i++) if (strstr(t_fmt, formats_24h[i]) != nullptr) return FALSE; return TRUE; } typedef enum { DATE_PROXIMITY_YESTERDAY, DATE_PROXIMITY_TODAY, DATE_PROXIMITY_TOMORROW, DATE_PROXIMITY_LAST_WEEK, DATE_PROXIMITY_NEXT_WEEK, DATE_PROXIMITY_FAR } date_proximity_t; static date_proximity_t getDateProximity(GDateTime* now, GDateTime* time) { date_proximity_t prox = DATE_PROXIMITY_FAR; gint now_year, now_month, now_day; gint time_year, time_month, time_day; // does it happen today? g_date_time_get_ymd(now, &now_year, &now_month, &now_day); g_date_time_get_ymd(time, &time_year, &time_month, &time_day); if ((now_year == time_year) && (now_month == time_month) && (now_day == time_day)) { return DATE_PROXIMITY_TODAY; } // did it happen yesterday? GDateTime* yesterday = g_date_time_add_days(now, -1); gint tom_year, tom_month, tom_day; g_date_time_get_ymd(yesterday, &tom_year, &tom_month, &tom_day); g_date_time_unref(yesterday); if ((tom_year == time_year) && (tom_month == time_month) && (tom_day == time_day)) { return DATE_PROXIMITY_YESTERDAY; } // does it happen tomorrow? GDateTime* tomorrow = g_date_time_add_days(now, 1); g_date_time_get_ymd(tomorrow, &tom_year, &tom_month, &tom_day); g_date_time_unref(tomorrow); if ((tom_year == time_year) && (tom_month == time_month) && (tom_day == time_day)) { return DATE_PROXIMITY_TOMORROW; } // does it happen this week? if (g_date_time_compare(time, now) < 0) { GDateTime* last_week = g_date_time_add_days(now, -6); GDateTime* last_week_bound = g_date_time_new_local(g_date_time_get_year(last_week), g_date_time_get_month(last_week), g_date_time_get_day_of_month(last_week), 0, 0, 0); if (g_date_time_compare(time, last_week_bound) >= 0) prox = DATE_PROXIMITY_LAST_WEEK; g_date_time_unref(last_week); g_date_time_unref(last_week_bound); } else { GDateTime* next_week = g_date_time_add_days(now, 6); GDateTime* next_week_bound = g_date_time_new_local(g_date_time_get_year(next_week), g_date_time_get_month(next_week), g_date_time_get_day_of_month(next_week), 23, 59, 59.9); if (g_date_time_compare(time, next_week_bound) <= 0) prox = DATE_PROXIMITY_NEXT_WEEK; g_date_time_unref(next_week); g_date_time_unref(next_week_bound); } return prox; } const char* dgettext_datetime(const char *text) { return dgettext("indicator-datetime", text); } /** * _ a time yesterday should be shown as (e.g. “Yesterday 3:55 PM”) * _ a time today should be shown as just the time (e.g. “3:55 PM”) * _ a time tomorrow should be shown as(e.g. “Tomorrow 3:55 PM”) * _ a time any other day this week should be shown as the short version of the * day and time (e.g. “Wed 3:55 PM”) * weekday (e.g. “Friday”) * _ a time after this week should be shown as the short version of the day, * date, and time (e.g. “Wed 21 Apr 3:55 PM”) * _ in addition, when presenting the times of upcoming events, the time should * be followed by the timezone if it is different from the one the computer * is currently set to. For example, “Wed 3:55 PM UTC−5”. * * TODO - keep inline with indicator-datetime */ char* generate_full_format_string_at_time (GDateTime* now, GDateTime* then) { GString* ret = g_string_new (nullptr); if (then != nullptr) { const date_proximity_t prox = getDateProximity(now, then); if (is_locale_12h()) { switch (prox) { case DATE_PROXIMITY_YESTERDAY: /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! This format string is used for showing, on a 12-hour clock, times that happen yesterday. (\u2003 is a unicode em space which is slightly wider than a normal space.) en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 1:00 PM" */ g_string_assign (ret, dgettext_datetime("Yesterday\u2003%l:%M %p")); break; case DATE_PROXIMITY_TODAY: /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! This format string is used for showing, on a 12-hour clock, times that happened today. en_US example: "%l:%M %p" --> "1:00 PM" */ g_string_assign (ret, dgettext_datetime("%l:%M %p")); break; case DATE_PROXIMITY_TOMORROW: /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! This format string is used for showing, on a 12-hour clock, events/appointments that happen tomorrow. (\u2003 is a unicode em space which is slightly wider than a normal space.) en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 1:00 PM" */ g_string_assign (ret, dgettext_datetime("Tomorrow\u2003%l:%M %p")); break; case DATE_PROXIMITY_LAST_WEEK: case DATE_PROXIMITY_NEXT_WEEK: /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! This format string is used for showing, on a 12-hour clock, times that happened in the last week. (\u2003 is a unicode em space which is slightly wider than a normal space.) en_US example: "%a\u2003%l:%M %p" --> "Fri 1:00 PM" */ g_string_assign (ret, dgettext_datetime("%a\u2003%l:%M %p")); break; case DATE_PROXIMITY_FAR: /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! This format string is used for showing, on a 12-hour clock, times that happened before a week from now. (\u2003 is a unicode em space which is slightly wider than a normal space.) en_US example: "%a %d %b\u2003%l:%M %p" --> "Fri Oct 31 1:00 PM" en_GB example: "%a %b %d\u2003%l:%M %p" --> "Fri 31 Oct 1:00 PM" */ g_string_assign (ret, dgettext_datetime("%a %d %b\u2003%l:%M %p")); break; } } else { switch (prox) { case DATE_PROXIMITY_YESTERDAY: /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! This format string is used for showing, on a 24-hour clock, times that happen yesterday. (\u2003 is a unicode em space which is slightly wider than a normal space.) en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 13:00" */ g_string_assign (ret, dgettext_datetime("Yesterday\u2003%H:%M")); break; case DATE_PROXIMITY_TODAY: /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! This format string is used for showing, on a 24-hour clock, times that happened today. en_US example: "%H:%M" --> "13:00" */ g_string_assign (ret, dgettext_datetime("%H:%M")); break; case DATE_PROXIMITY_TOMORROW: /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! This format string is used for showing, on a 24-hour clock, events/appointments that happen tomorrow. (\u2003 is a unicode em space which is slightly wider than a normal space.) en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 13:00" */ g_string_assign (ret, dgettext_datetime("Tomorrow\u2003%H:%M")); break; case DATE_PROXIMITY_LAST_WEEK: case DATE_PROXIMITY_NEXT_WEEK: /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! This format string is used for showing, on a 24-hour clock, times that happened in the last week. (\u2003 is a unicode em space which is slightly wider than a normal space.) en_US example: "%a\u2003%H:%M" --> "Fri 13:00" */ g_string_assign (ret, dgettext_datetime("%a\u2003%H:%M")); break; case DATE_PROXIMITY_FAR: /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! This format string is used for showing, on a 24-hour clock, times that happened before a week from now. (\u2003 is a unicode em space which is slightly wider than a normal space.) en_US example: "%a %d %b\u2003%H:%M" --> "Fri Oct 31 13:00" en_GB example: "%a %b %d\u2003%H:%M" --> "Fri 31 Oct 13:00" */ g_string_assign (ret, dgettext_datetime("%a %d %b\u2003%H:%M")); break; } } } return g_string_free (ret, FALSE); } QString RelativeTimeFormatter::format() const { GDateTime* now = g_date_time_new_now_local(); if (!now) { return QString(); } GDateTime* then = g_date_time_new_from_unix_local(time()); if (!then) { return QString(); } char* time_format = generate_full_format_string_at_time(now, then); QString str(QString::fromUtf8(time_format)); g_free(time_format); g_date_time_unref(now); g_date_time_unref(then); return str; }