Last active
May 1, 2026 15:05
-
-
Save gabeweb/80e2d64aebafdc8909693e162ae11175 to your computer and use it in GitHub Desktop.
Gmail_Full_Timestamp.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name Full timestamp for Gmail | |
| // @namespace https://* | |
| // @version 0.4 | |
| // @match https://mail.google.com/mail/u/* | |
| // @grant none | |
| // @author gabeweb | |
| // @homepage https://gist.github.com/gabeweb/80e2d64aebafdc8909693e162ae11175 | |
| // @icon https://gist.github.com/fluidicon.png | |
| // @description Display full timestamp on Gmail inbox/folders. | |
| // @run-at document-end | |
| // @license MIT | |
| // @downloadURL https://gist.githubusercontent.com/gabeweb/80e2d64aebafdc8909693e162ae11175/ | |
| // @updateURL https://gist.githubusercontent.com/gabeweb/80e2d64aebafdc8909693e162ae11175/ | |
| // ==/UserScript== | |
| (function() { | |
| 'use strict'; | |
| const GmailISO = { | |
| // Diccionario bilingüe de meses para soporte ES/EN | |
| // Bilingual month dictionary for ES/EN support | |
| months: { | |
| 'ene': 0, 'feb': 1, 'mar': 2, 'abr': 3, 'may': 4, 'jun': 5, | |
| 'jul': 6, 'ago': 7, 'sep': 8, 'oct': 9, 'nov': 10, 'dic': 11, | |
| 'sept': 8, 'enero': 0, 'febrero': 1, 'marzo': 2, 'abril': 3, | |
| 'mayo': 4, 'junio': 5, 'julio': 6, 'agosto': 7, 'septiembre': 8, | |
| 'octubre': 9, 'noviembre': 10, 'diciembre': 11, | |
| 'jan': 0, 'feb': 1, 'mar': 2, 'apr': 3, 'may': 4, 'jun': 5, | |
| 'jul': 6, 'aug': 7, 'sep': 8, 'oct': 9, 'nov': 10, 'dec': 11, | |
| 'january': 0, 'february': 1, 'march': 2, 'april': 3, 'august': 7, 'september': 8 | |
| }, | |
| init: function() { | |
| this.observer = new MutationObserver(this.process.bind(this)); | |
| this.observer.observe(document.body, { childList: true, subtree: true }); | |
| this.process(); | |
| }, | |
| process: function() { | |
| const targets = document.querySelectorAll('.xW.xY span[aria-label], .apm span[aria-label], .g3'); | |
| targets.forEach(el => this.formatElement(el)); | |
| }, | |
| parseDate: function(str) { | |
| if (!str) return null; | |
| if (/(\d+[\u2013-]\d+)/.test(str)) return null; | |
| let s = str.toLowerCase() | |
| .replace(/[\u200E\u200F]/g, '') | |
| .replace(/ de /g, ' ') | |
| .replace(/[.,]/g, '') | |
| .trim(); | |
| let d = new Date(); | |
| const yearMatch = s.match(/\b(20\d{2})\b/); | |
| if (yearMatch) d.setFullYear(parseInt(yearMatch[1])); | |
| let monthSet = false; | |
| for (let m in this.months) { | |
| let regex = new RegExp('\\b' + m + '\\b', 'i'); | |
| if (regex.test(s)) { | |
| d.setMonth(this.months[m]); | |
| monthSet = true; | |
| break; | |
| } | |
| } | |
| const numericMatch = s.match(/(\d{1,2})\/(\d{1,2})/); | |
| if (!monthSet && numericMatch) { | |
| d.setDate(parseInt(numericMatch[1])); | |
| d.setMonth(parseInt(numericMatch[2]) - 1); | |
| } else { | |
| const dayMatch = s.match(/\b(\d{1,2})\b/); | |
| if (dayMatch) d.setDate(parseInt(dayMatch[1])); | |
| } | |
| const timeMatch = s.match(/(\d{1,2}):(\d{2})/); | |
| if (timeMatch) { | |
| let h = parseInt(timeMatch[1]); | |
| let m = parseInt(timeMatch[2]); | |
| const isPM = /\b(pm|p m)\b/i.test(s) || (s.includes('p') && !s.includes('sep')); | |
| if (isPM && h < 12) h += 12; | |
| if (!isPM && h === 12 && (s.includes('am') || s.includes('a m'))) h = 0; | |
| d.setHours(h, m, 0); | |
| } | |
| return d; | |
| }, | |
| formatElement: function(el) { | |
| if (el.dataset.isoFixed === "true") return; | |
| if (el.closest('.G-atb')) return; | |
| let raw = el.getAttribute('title') || el.getAttribute('aria-label') || el.innerText; | |
| if (raw.includes(' de ') && /\d+/.test(raw) && (raw.includes('\u2013') || raw.includes('-'))) return; | |
| if (raw.includes(' of ') && /\d+/.test(raw) && (raw.includes('\u2013') || raw.includes('-'))) return; | |
| const dateObj = this.parseDate(raw); | |
| if (dateObj && !isNaN(dateObj.getTime())) { | |
| const formatted = this.formatISO(dateObj); | |
| this.observer.disconnect(); | |
| el.innerText = formatted; | |
| el.style.fontFamily = '"Roboto Mono", "Cascadia Code", "Consolas", monospace'; | |
| el.style.fontSize = "1em"; | |
| el.style.whiteSpace = "nowrap"; | |
| el.dataset.isoFixed = "true"; | |
| let cell = el.closest('td'); | |
| if (cell) cell.style.width = "195px"; | |
| this.observer.observe(document.body, { childList: true, subtree: true }); | |
| } | |
| }, | |
| formatISO: function(d) { | |
| const pad = (n) => n.toString().padStart(2, '0'); | |
| return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} @ ${pad(d.getHours())}:${pad(d.getMinutes())}`; | |
| } | |
| }; | |
| GmailISO.init(); | |
| })(); |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Español
Este script permite mostrar la fecha y hora completas en Gmail. Dado que Gmail suele mostrar estos datos en valores simplificados en la vista de lista, la información resulta limitada cuando se reciben muchos mensajes en una misma fecha. El script utiliza el formato estándar yyyy-MM-dd @ HH:mm para una mayor claridad, aplicando además un estilo monoespaciado moderno que facilita la lectura.
Para aplicar este script, puedes usar:
English
This script enables the full date and timestamp display in Gmail. Because Gmail's default view uses simplified time values, tracking multiple emails received on the same day can be difficult. This script adopts the yyyy-MM-dd @ HH:mm standard for better precision and features a modern monospace aesthetic for improved legibility.
For applying this script, you can use:
List view.
Message view.
Original message view.