8

I wanted to format the clock without the use of extensions...

muru
  • 207,970
Steve
  • 706
  • 5
  • 15

2 Answers2

5

BLUF: This is a permanent and clean way to alter formatting of the Gnome top bar clock to your liking without the use of extensions.

My goal was to simply do this without any extension so the custom time format would be seen consistently at the initial gdm login screen upon boot, while in active logged-in sessions, and on the session unlock screen. It took some digging but the key lies in how Gnome handles localization/internationalization and how the Gnome wall clock, as it's called, obtains the string to actually display in the top bar.

First, a bit of background on the use of .po and .mo files in Gnome localization/internationalization can be found here:

https://wiki.gnome.org/TranslationProject/LocalisationGuide

Basically, at runtime, Gnome wall clock takes the current time and applies localization/internationalization string formatting. It uses a string key to look up a formatting string to use for a given locale to determine what to actually display -- it does not rely on the locale file formatting strings. If you modify the value returned for a given key in the localization/internationalization file, the clock display will reflect the change. Localization/internationalization uses two files. The first is the human-readable .po file that translators populate for each locale and this is where the mapping from lookup keys to formatting strings can be found. The second is the .mo file that is generated from the .po file... more on this and how it relates in just a bit...

Below is a link to the source for the Gnome wall clock version used in Ubuntu 20.04:

https://github.com/GNOME/gnome-desktop/blob/gnome-3-36/libgnome-desktop/gnome-wall-clock.c

If you examine the function 'gnome_wall_clock_string_for_datetime' beginning at line 310, you'll see the localization/internationalization lookup keys in use. There are several. Ubuntu has various display settings for the wall clock depending on whether you want to display just the time, time with day, time with day and date, etc. Each of these corresponds to a given localization/internationalization lookup key that wall clock uses. What you see in quotations below is not the formatting string itself but rather the key to look up the actual formatting string. The N_( that surrounds each key performs the lookup:

char *
gnome_wall_clock_string_for_datetime (GnomeWallClock      *self,
                      GDateTime           *now,
                      GDesktopClockFormat  clock_format,
                      gboolean             show_weekday,
                      gboolean             show_full_date,
                      gboolean             show_seconds)
{
    const char *format_string;

g_debug ("clock_format: %s", clock_format == G_DESKTOP_CLOCK_FORMAT_24H ? "24h" : "12h");
g_debug ("show_weekday: %s", show_weekday ? "TRUE" : "FALSE");
g_debug ("show_full_date: %s", show_full_date ? "TRUE" : "FALSE");
g_debug ("show_seconds: %s", show_seconds ? "TRUE" : "FALSE");

if (clock_format == G_DESKTOP_CLOCK_FORMAT_24H) {
    if (show_full_date) {
        if (show_weekday)
            /* Translators: This is the time format with full date
               plus day used in 24-hour mode. Please keep the under-
               score to separate the date from the time. */
            format_string = show_seconds ? T_(N_("%a %b %-e_%R:%S"))
                : T_(N_("%a %b %-e_%R"));
        else
            /* Translators: This is the time format with full date
               used in 24-hour mode. Please keep the underscore to
               separate the date from the time. */
            format_string = show_seconds ? T_(N_("%b %-e_%R:%S"))
                : T_(N_("%b %-e_%R"));
    } else if (show_weekday) {
        /* Translators: This is the time format with day used
           in 24-hour mode. */
        format_string = show_seconds ? T_(N_("%a %R:%S"))
            : T_(N_("%a %R"));
    } else {
        /* Translators: This is the time format without date used
           in 24-hour mode. */
        format_string = show_seconds ? T_(N_("%R:%S"))
                            : T_(N_("%R"));
    }
} else {
    if (show_full_date) {
        if (show_weekday)
            /* Translators: This is a time format with full date
               plus day used for AM/PM. Please keep the under-
               score to separate the date from the time. */
            format_string = show_seconds ? T_(N_("%a %b %-e_%l:%M:%S %p"))
                : T_(N_("%a %b %-e_%l:%M %p"));
        else
            /* Translators: This is a time format with full date
               used for AM/PM. Please keep the underscore to
               separate the date from the time. */
            format_string = show_seconds ? T_(N_("%b %-e_%l:%M:%S %p"))
                : T_(N_("%b %-e_%l:%M %p"));
    } else if (show_weekday) {
        /* Translators: This is a time format with day used
           for AM/PM. */
        format_string = show_seconds ? T_(N_("%a %l:%M:%S %p"))
            : T_(N_("%a %l:%M %p"));
    } else {
        /* Translators: This is a time format without date used
           for AM/PM. */
        format_string = show_seconds ? T_(N_("%l:%M:%S %p"))
            : T_(N_("%l:%M %p"));
    }
}

g_debug ("format_string: %s", format_string);

return date_time_format (now, format_string);

}

For instance, I wanted a custom format string for displaying day, date, and time in 12 hour(AM/PM) format. That is in Ubuntu, I had set the clock to display the day, date, and time in 12 hour format which corresponds to the 'full date' in the above code. Examining the function, I was able to determine that this 'full date' lookup key occurred at line 361:

/* Translators: This is a time format with full date
                   used for AM/PM. Please keep the underscore to
                   separate the date from the time. */
                format_string = show_seconds ? T_(N_("%b %-e_%l:%M:%S %p"))
                    : T_(N_("%b %-e_%l:%M %p"));

I wasn't interested in seconds so the key I needed to find in the localization/internationalization .po file was:

'%b %-e_%l:%M %p'

Unfortunately, I couldn't locate this particular key in the en.po for my locale. Since the 18.04 LTS release it appears that the Gnome folks have replaced the commas with underscores in the formatting string but the locale file -- at least for en -- has not been updated to reflect this change.

https://github.com/GNOME/gnome-desktop/blob/gnome-3-36/po/en.po

So, I needed to add it as well as the mapping to the formatting I wanted.

msgid "%a %b %-e_%l:%M %p"
msgstr "%A %b %-d, %l:%M %p"

The localization/internationalization .mo files are binary in format but easily generated from a human-readable plain-text mapping .po files that maps a given lookup key to formatting string. Gnome wall clock uses a file with the specific name of gnome-desktop-3.0.mo for localization/internationalization. It was not present on my system under the prescribed location for any locale:

/usr/share/locale/XX/LC_MESSAGES

So, I didn't need to worry about replacing it but rather creating it anew. Regardless, you need to first obtain the .po file for your locale:

https://github.com/GNOME/gnome-desktop/tree/gnome-3-36/po

Again, many of the clock formatting strings are not present for the 'en' locale and I needed to add the one I was interested in.

Prior to the change reflected in the above 'msgstr' the clock would have displayed:

Mon Feb 4  12:22 PM

But after the above change the day is no longer abbreviated and the space separating the date and time has been replaced with a comma(see the end of this answer for the formatting specifiers):

Monday Feb 4, 12:22 PM

Next, take this .po file and run it through the following on the command line to obtain the messages.mo file where XX is your locale. The binary msgfmt can be installed via 'sudo apt install gettext' in 20.04:

msgfmt -cv XX.po

Next, rename the resulting messages.mo file to gnome-desktop-3.0.mo and copy it to your specific locale LC_MESSAGE directory:

/usr/share/locale/XX/LC_MESSAGES/gnome-desktop-3.0.mo

Then, to effect the change, log out and log back in. If you find that the formatting did not change then double check that your current clock settings truly correspond to the key for which you changed the formatting string.

Finally, here are some formatting string specifiers to help you along. I borrowed these from another site so no guarantees that these all work in Gnome:

The % sign indicating a directive may be immediately followed by a padding modifier, e.g. %-d:

0 - zero-padding _ - space-padding

    • disable padding

%a - abbreviated weekday name.* %A - full weekday name.* %b - abbreviated month name.* %B - full month name.* %d - zero-padded day of the month as a decimal number [01,31]. %e - space-padded day of the month as a decimal number [ 1,31]; equivalent to %_d. %f - microseconds as a decimal number [000000, 999999]. %H - hour (24-hour clock) as a decimal number [00,23]. %I - hour (12-hour clock) as a decimal number [01,12]. %j - day of the year as a decimal number [001,366]. %m - month as a decimal number [01,12]. %M - minute as a decimal number [00,59]. %L - milliseconds as a decimal number [000, 999]. %p - either AM or PM.* %Q - milliseconds since UNIX epoch. %s - seconds since UNIX epoch. %S - second as a decimal number [00,61]. %u - Monday-based (ISO 8601) weekday as a decimal number [1,7]. %U - Sunday-based week of the year as a decimal number [00,53]. %V - ISO 8601 week of the year as a decimal number [01, 53]. %w - Sunday-based weekday as a decimal number [0,6]. %W - Monday-based week of the year as a decimal number [00,53]. %x - the locale’s date, such as %-m/%-d/%Y.* %X - the locale’s time, such as %-I:%M:%S %p.* %y - year without century as a decimal number [00,99]. %Y - year with century as a decimal number. %Z - time zone offset, such as -0700, -07:00, -07, or Z. %% - a literal percent sign (%).

Steve
  • 706
  • 5
  • 15
  • Awesome answer! I have my Ubuntu set to English (United States) language but with Sweden Formats. Thus I was expecting my Ubuntu to look for the gnome-desktop-3.0.mo in /usr/share/locale/sv/LC_MESSAGES, but apparently it is the /usr/share/locale/en/LC_MESSAGES it uses. Then what effects do the Formats setting even have? – Skillzore Jun 04 '21 at 09:24
  • This does not affect the date on the lock screen, do you have a solution for that as well? I have just posted a question about it here: https://askubuntu.com/questions/1343639/how-can-i-custom-format-the-lock-screen-date-in-ubuntu-20-04-without-extensions – Skillzore Jun 04 '21 at 10:11
  • 1
    @Skillzone So noted. I haven't explored this yet but you are correct. I'm happy to have the gdm and desktop looking consistent at least. I'm running vanilla gnome and have a bit of customizing to do to the Adwaita theme gresource file(including the font boldness of the clock on the lock screen aka screen shield) so I'll have a look in there while I'm at it... I might know of a few other locations that could influence the clock on the lock screen as well... I'll report back if I find anything – Steve Jun 04 '21 at 16:20
  • I finally moved to 24.04 LTS and can assert that these same instructions still apply. The only small change I had to make was that even in 12 hour clock format with the %l formatting string, I had to change it to %-l to disable a leading pad space. It was most noticeable on the clock on the lock screen being off center to the right when the time was only a single digit, i.e. 1 - 9. – Steve Dec 30 '24 at 04:08
2

As the source code in Steve's well-researched answer shows, there are four settings that are supported by the clock, which can be changed without having to make changes to l10n/i18n files:

  • use 12/24h format
  • show the weekday
  • show the full date
  • show the seconds

They can be done through gsettings, e.g.

gsettings set  org.gnome.desktop.interface clock-show-seconds false
gsettings set  org.gnome.desktop.interface clock-show-date    true
gsettings set  org.gnome.desktop.interface clock-show-weekday true
gsettings set  org.gnome.desktop.interface clock-format       '24h'

(You can use gsettings get to check the values, or gsettings reset to put them back to the default setting.)

mwfearnley
  • 3,527
  • 2
  • 24
  • 31
  • these four properties can also be changed through Gnome Tweaks – törzsmókus Jun 13 '23 at 14:53
  • The above customization simply allows you to further tailor the formatting beyond just enabling/disabling various components of the date/time display. – Steve Dec 30 '24 at 04:03