1/* 2 * Copyright 2012-2017 elementary, Inc. (https://elementary.io) 3 * SPDX-License-Identifier: LGPL-3.0-or-later 4 */ 5 6/** 7 * The DateTime namespace contains useful functions for 8 * getting the default translated format for either date and time. 9 */ 10namespace Granite.DateTime { 11 /** 12 * Gets a default translated time format. 13 * The function constructs a new string interpreting the //is_12h// and //with_second// parameters 14 * so that it can be used with formatting functions like {@link GLib.DateTime.format}. 15 * 16 * The returned string is formatted and translated. This function is mostly used to display 17 * the time in various user interfaces like the time displayed in the top panel. 18 * 19 * @param is_12h if the returned string should be formatted in 12h format 20 * @param with_second if the returned string should include seconds 21 * 22 * @return the formatted and located time string. 23 */ 24 public static string get_default_time_format (bool is_12h = false, bool with_second = false) { 25 if (is_12h == true) { 26 if (with_second == true) { 27 /// TRANSLATORS: a GLib.DateTime format showing the hour (12h format) with seconds 28 return _("%-l:%M:%S %p"); 29 } else { 30 /// TRANSLATORS: a GLib.DateTime format showing the hour (12h format) 31 return _("%-l:%M %p"); 32 } 33 } else { 34 if (with_second == true) { 35 /// TRANSLATORS: a GLib.DateTime format showing the hour (24h format) with seconds 36 return _("%H:%M:%S"); 37 } else { 38 /// TRANSLATORS: a GLib.DateTime format showing the hour (24h format) 39 return _("%H:%M"); 40 } 41 } 42 } 43 44 /** 45 * Compares a {@link GLib.DateTime} to {@link GLib.DateTime.now_local} and returns a location, relative date and 46 * time string. Results appear as natural-language strings like "Now", "5m ago", "Yesterday" 47 * 48 * @param date_time a {@link GLib.DateTime} to compare against {@link GLib.DateTime.now_local} 49 * 50 * @return a localized, relative date and time string 51 */ 52 public static string get_relative_datetime (GLib.DateTime date_time) { 53 var now = new GLib.DateTime.now_local (); 54 var diff = now.difference (date_time); 55 56 if (is_same_day (date_time, now)) { 57 if (diff > 0) { 58 if (diff < TimeSpan.MINUTE) { 59 return _("Now"); 60 } else if (diff < TimeSpan.HOUR) { 61 var minutes = diff / TimeSpan.MINUTE; 62 return dngettext (GETTEXT_PACKAGE, "%dm ago", "%dm ago", (ulong) (minutes)).printf ((int) (minutes)); 63 } else if (diff < 12 * TimeSpan.HOUR) { 64 int rounded = (int) Math.round ((double) diff / TimeSpan.HOUR); 65 return dngettext (GETTEXT_PACKAGE, "%dh ago", "%dh ago", (ulong) rounded).printf (rounded); 66 } 67 } else { 68 diff = -1 * diff; 69 if (diff < TimeSpan.HOUR) { 70 var minutes = diff / TimeSpan.MINUTE; 71 return dngettext (GETTEXT_PACKAGE, "in %dm", "in %dm", (ulong) (minutes)).printf ((int) (minutes)); 72 } else if (diff < 12 * TimeSpan.HOUR) { 73 int rounded = (int) Math.round ((double) diff / TimeSpan.HOUR); 74 return dngettext (GETTEXT_PACKAGE, "in %dh", "in %dh", (ulong) rounded).printf (rounded); 75 } 76 } 77 78 return date_time.format (get_default_time_format (is_clock_format_12h (), false)); 79 } else if (is_same_day (date_time.add_days (1), now)) { 80 return _("Yesterday"); 81 } else if (is_same_day (date_time.add_days (-1), now)) { 82 return _("Tomorrow"); 83 } else if (diff < 6 * TimeSpan.DAY && diff > -6 * TimeSpan.DAY) { 84 return date_time.format (get_default_date_format (true, false, false)); 85 } else if (date_time.get_year () == now.get_year ()) { 86 return date_time.format (get_default_date_format (false, true, false)); 87 } else { 88 return date_time.format ("%x"); 89 } 90 } 91 92 /** 93 * Gets the //clock-format// key from //org.gnome.desktop.interface// schema 94 * and determines if the clock format is 12h based 95 * 96 * @return true if the clock format is 12h based, false otherwise. 97 */ 98 private static bool is_clock_format_12h () { 99 string format = null; 100 try { 101 var portal = Portal.Settings.get (); 102 var variant = portal.read ("org.gnome.desktop.interface", "clock-format").get_variant (); 103 format = variant.get_string (); 104 } catch (Error e) { 105 debug ("cannot use portal, using GSettings: %s", e.message); 106 } 107 108 if (format == null) { 109 var h24_settings = new GLib.Settings ("org.gnome.desktop.interface"); 110 format = h24_settings.get_string ("clock-format"); 111 } 112 113 return (format.contains ("12h")); 114 } 115 116 /** 117 * Compare two {@link GLib.DateTime} and return true if they occur on the same day of the same year 118 * 119 * @param day1 a {@link GLib.DateTime} to compare against day2 120 * @param day2 a {@link GLib.DateTime} to compare against day1 121 * 122 * @return true if day1 and day2 occur on the same day of the same year. False otherwise 123 */ 124 public static bool is_same_day (GLib.DateTime day1, GLib.DateTime day2) { 125 return day1.get_day_of_year () == day2.get_day_of_year () && day1.get_year () == day2.get_year (); 126 } 127 128 /** 129 * Gets the default translated date format. 130 * The function constructs a new string interpreting the //with_weekday//, //with_day// and //with_year// parameters 131 * so that it can be used with formatting functions like {@link GLib.DateTime.format}. 132 * 133 * As the {@link Granite.DateTime.get_default_time_format}, the returned string is formatted, translated and is also mostly used to display 134 * the date in various user interfaces like the date displayed in the top panel. 135 * 136 * @param with_weekday if the returned string should contain the abbreviated weekday name 137 * @param with_day if the returned string should contain contain the day of the month as a decimal number (range 1 to 31) 138 * @param with_year if the returned string should contain the year as a decimal number including the century 139 * 140 * @return returns the formatted and located date string. If for some reason, the function could not determine the format to use, 141 * an empty string will be returned. 142 */ 143 public static string get_default_date_format (bool with_weekday = false, bool with_day = true, bool with_year = false) { 144 if (with_weekday == true && with_day == true && with_year == true) { 145 /// TRANSLATORS: a GLib.DateTime format showing the weekday, date, and year 146 return _("%a, %b %e, %Y"); 147 } else if (with_weekday == false && with_day == true && with_year == true) { 148 /// TRANSLATORS: a GLib.DateTime format showing the date and year 149 return _("%b %e %Y"); 150 } else if (with_weekday == false && with_day == false && with_year == true) { 151 /// TRANSLATORS: a GLib.DateTime format showing the year 152 return _("%Y"); 153 } else if (with_weekday == false && with_day == true && with_year == false) { 154 /// TRANSLATORS: a GLib.DateTime format showing the date 155 return _("%b %e"); 156 } else if (with_weekday == true && with_day == false && with_year == true) { 157 /// TRANSLATORS: a GLib.DateTime format showing the weekday and year. 158 return _("%a %Y"); 159 } else if (with_weekday == true && with_day == false && with_year == false) { 160 /// TRANSLATORS: a GLib.DateTime format showing the weekday 161 return _("%a"); 162 } else if (with_weekday == true && with_day == true && with_year == false) { 163 /// TRANSLATORS: a GLib.DateTime format showing the weekday and date 164 return _("%a, %b %e"); 165 } else if (with_weekday == false && with_day == false && with_year == false) { 166 /// TRANSLATORS: a GLib.DateTime format showing the month. 167 return _("%b"); 168 } 169 170 return ""; 171 } 172 173 /** 174 * Converts seconds into the ISO 8601 standard date format for minutes (e.g. 100s to 01:40). 175 * Output of negative seconds is prepended with minus character. 176 * 177 * @param seconds the number of seconds to convert into ISO 8601 178 * 179 * @return returns an ISO 8601 formatted string 180 */ 181 public static string seconds_to_time (int seconds) { 182 int sign = 1; 183 if (seconds < 0) { 184 seconds = -seconds; 185 sign = -1; 186 } 187 188 int hours = seconds / 3600; 189 int min = (seconds % 3600) / 60; 190 int sec = (seconds % 60); 191 192 if (hours > 0) { 193 return ("%d:%02d:%02d".printf (sign * hours, min, sec)); 194 } else { 195 return ("%02d:%02d".printf (sign * min, sec)); 196 } 197 } 198} 199