Поведение timeago.js может различаться в зависимости от браузера из-за различий в движках JavaScript, реализации таймеров и поддержке стандартов. Знание типичных браузерных отличий сокращает время отладки.
Наиболее удобная среда для отладки timeago.js. Chrome DevTools предоставляет:
HTMLTimeElement.Особенности:
// Chrome корректно парсит ISO 8601 строки
new Date('2025-06-01T12:00:00').getTime(); // Парсится как локальное время
new Date('2025-06-01T12:00:00Z').getTime(); // UTC — корректно
Chrome более строго следует стандарту ECMA-262 при парсинге дат.
Firefox обрабатывает некоторые форматы дат иначе:
// Firefox корректен со стандартными форматами
new Date('2025-06-01'); // OK
new Date('June 1, 2025'); // OK в FF
new Date('01.06.2025'); // NaN в Firefox!
Особенность таймеров: Firefox может быть точнее при
соблюдении интервалов setInterval, что влияет на частоту
обновлений.
Отладка в Firefox:
Safari имеет наиболее строгий парсер дат:
// Safari
new Date('2025-06-01T12:00:00'); // Может вернуть Invalid Date!
new Date('2025-06-01T12:00:00Z'); // OK
new Date('2025-06-01'); // Invalid Date в старых версиях Safari
Основная проблема Safari: строки дат без явного
часового пояса и с дефисами в формате YYYY-MM-DD
воспринимаются некорректно в Safari < 14.
Нормализация для Safari:
function safariSafeDate(str) {
// Safari не принимает строки без Z
if (typeof str === 'string' && str.includes('T') && !str.includes('Z') && !str.includes('+')) {
return new Date(str + 'Z');
}
// Safari не принимает YYYY-MM-DD без времени
if (typeof str === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(str)) {
return new Date(str + 'T00:00:00Z');
}
return new Date(str);
}
Edge на основе Chromium ведёт себя аналогично Chrome. Специфических проблем с timeago.js нет.
Самая проблемная среда:
// iOS Safari 14 и ниже
new Date('2025-6-1'); // Invalid Date — однозначные месяц/день без ведущего нуля
new Date('2025-06-01T12:00:00'); // Invalid Date без Z!
Обязательная нормализация для iOS:
function parseForIOS(dateStr) {
if (typeof dateStr !== 'string') return new Date(dateStr);
// Заменить пробелы на T, добавить Z если нет timezone
let normalized = dateStr.trim().replace(' ', 'T');
if (!normalized.includes('Z') && !normalized.includes('+') && normalized.includes('T')) {
normalized += 'Z';
}
return new Date(normalized);
}
| Инструмент | Назначение |
|---|---|
| BrowserStack | Реальные браузеры, включая iOS Safari |
| Playwright | Chrome, Firefox, WebKit (Safari engine) через Node.js |
| Cypress | Electron (Chromium) — не Safari |
| kangax/compat | Таблица поддержки стандартов |
// tests/cross-browser.spec.ts
import { test, expect, Browser } from '@playwright/test';
const BROWSERS = ['chromium', 'firefox', 'webkit'];
for (const browserName of BROWSERS) {
test(`[${browserName}] timeago отображает корректное время`, async ({ playwright }) => {
const browser = await playwright[browserName].launch();
const page = await browser.newPage();
await page.goto('http://localhost:3000');
const timeEl = page.locator('time').first();
await expect(timeEl).not.toBeEmpty();
const text = await timeEl.textContent();
expect(text).toMatch(/назад|только что/);
await browser.close();
});
}
// Тестировать нормализатор дат, имитируя поведение Safari
describe('safariSafeDate', () => {
it('обрабатывает строку без Z (Safari bug)', () => {
const result = safariSafeDate('2025-06-01T12:00:00');
expect(isNaN(result.getTime())).toBe(false);
});
it('обрабатывает строку без времени (Safari bug)', () => {
const result = safariSafeDate('2025-06-01');
expect(isNaN(result.getTime())).toBe(false);
});
});
Chrome/Edge:
F12 → Application → Local Storage — проверить кешированные значения
F12 → Console → new Date('ваша строка') — проверить парсинг
Firefox:
F12 → Performance → Profiler → Start Recording
Safari:
Develop → Web Inspector → Timelines → JavaScript & Events
// Запустить в консоли любого браузера
function browserCompat() {
const tests = [
['ISO with Z', new Date('2025-06-01T12:00:00Z')],
['ISO without Z', new Date('2025-06-01T12:00:00')],
['Date only', new Date('2025-06-01')],
['Timestamp', new Date(1748779200000)],
];
tests.forEach(([label, d]) => {
console.log(label + ':', isNaN(d.getTime()) ? 'INVALID' : 'OK → ' + d.toISOString());
});
}
browserCompat();