惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Project Zero
Project Zero
Security Archives - TechRepublic
Security Archives - TechRepublic
C
Cyber Attacks, Cyber Crime and Cyber Security
Security Latest
Security Latest
Scott Helme
Scott Helme
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
V
Vulnerabilities – Threatpost
C
CERT Recently Published Vulnerability Notes
S
Schneier on Security
G
GRAHAM CLULEY
L
Lohrmann on Cybersecurity
D
Darknet – Hacking Tools, Hacker News & Cyber Security
I
Intezer
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
F
Full Disclosure
T
The Exploit Database - CXSecurity.com
P
Proofpoint News Feed
WordPress大学
WordPress大学
Microsoft Azure Blog
Microsoft Azure Blog
H
Help Net Security
大猫的无限游戏
大猫的无限游戏
MyScale Blog
MyScale Blog
Hacker News: Ask HN
Hacker News: Ask HN
G
Google Developers Blog
H
Heimdal Security Blog
O
OpenAI News
Hugging Face - Blog
Hugging Face - Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
L
LangChain Blog
C
Cisco Blogs
云风的 BLOG
云风的 BLOG
IT之家
IT之家
Cyberwarzone
Cyberwarzone
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Know Your Adversary
Know Your Adversary
博客园 - 聂微东
The Cloudflare Blog
C
Check Point Blog
K
Kaspersky official blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
月光博客
月光博客
T
Tor Project blog
T
Threat Research - Cisco Blogs
T
Tailwind CSS Blog
P
Proofpoint News Feed
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
A
About on SuperTechFans
小众软件
小众软件
Cloudbric
Cloudbric
A
Arctic Wolf

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Новый Intl.DurationFormat привел к неожиданной ошибке приложения
VolhaIvanova · 2026-06-01 · via Все публикации подряд на Хабре

Если вы уже используете новый Intl.DurationFormat в совсем проекте, то вам будет полезен мой кейс и поможет вам сэкономить пару часов на дебагинг.

Продукт над которым я работаю - это платежная форма. Это стабильное давно работающее приложение и вдруг пользователи стали сообщать об «Unknown error» при попытке провести транзакцию. При этом проблема была только для одного вида транзакций — «Счет».

Сначала проверили бэкенд, там все запросы проходят корректно, я стала проверять фронт и к моему удивлению никаких особенностей для этого типа транзакций добавлено не было и в кодовой базе она ничем не отличалась от обработки других транзакций.

Если коротко, платежная форма состоит из инпутов, таймера обратного отсчета и кнопок. Соответственно, подозрения пали на работу таймера в первую очередь. После сравнения данных транзакции для успешных и выдающих ошибку, паттерн обнаружился в данных бэкенда:

  {
    "transaction": {
      "id": 111111111,
      "status": "Pending",
      "createdAt": "2026-05-11T08:39:15+00:00",
      "expiresAt": "2026-07-01T08:39:15+00:00"
    }
  }

expiresAt — июль, а сейчас май. Так, срок жизни транзакции типа «Счет» ~55 дней, в то время как все другие транзакции живут не больше 15 минут. Дело в том, что банковские переводы ждут подтверждения от банка и могут висеть несколько дней. Именно поэтому баг проявлялся только для этого типа — остальные работали корректно.

У нас в проекте для таймера обратного отсчёта используется компонент TextTimer с полифиллом formatjs/intl-durationformat@ 0.7.4. Полифилл подключён в корне приложения глобально, поэтому нативная реализация браузера не задействована.

Код до фикса:

 const formatter = new Intl.DurationFormat(i18n.locale, {
   hoursDisplay: "auto",
   secondsDisplay: "always",
   style: formatStyle,
 });
 
 function getDiff(unit: dayjs.OpUnitType) {
   let diff = expiresAtDayjs.diff(now, unit);

   if (unit === "m" || unit === "s") {
     diff %= 60;
   }
 
   return Math.max(0, diff);
 }

 formatter.format({
   hours: getDiff("h"),    // = 1320
   minutes: getDiff("m"),
   seconds: getDiff("s"),
 }); // 💥 RangeError

Так в чем же проблема?

Дело в том, что если в таймер приходит длительность больше суток, а в моем случае это было 55 дней, getDiff(“h”) возвращает 1320 — потому что для часов не было % 24, и days не передавался в .format().

Полифилл видел 1320 часов, Intl.DurationFormat не понимал как обработать такой период и выбрасывал RangeError. Ошибка всплывала наверх без ErrorBoundary на компоненте, отсюда «Unknown error» вместо формы оплаты.

Решение

Два изменения:

  1. Добавить % 24 для часов в getDiff

  2. Передать days в .format()

const formatter = new Intl.DurationFormat(i18n.locale, {
  hoursDisplay: "auto",
  secondsDisplay: "always",
  style: formatStyle,
});

function getDiff(unit: dayjs.OpUnitType) {
  let diff = expiresAtDayjs.diff(now, unit);

  if (unit === "h") {
    diff %= 24;          // ← добавили
  } else if (unit === "m" || unit === "s") {
    diff %= 60;
  }

  return Math.max(0, diff);
}

formatter.format({
  days: getDiff("d"),    // ← добавили
  hours: getDiff("h"),   // теперь 1320 % 24 = 8 ✓
  minutes: getDiff("m"),
  seconds: getDiff("s"),
});

Теперь пользователь видит 55 дн. 10:05:00 (RU) или 55d 10:05:00 (EN) вместо ошибки.

А что если бы был ErrorBoundary?

Поскольку таймер — вспомогательный элемент, он показывает сколько транзакция будет открыта, но не блокирует оплату. Если обернуть его в предохранитель, падение таймера не будет блокировать работу платежной формы.

 class TimerErrorBoundary extends React.Component {
   componentDidCatch(error: Error) {
     logger.error('TextTimer crashed', { error }); // обязательно!
   }

   render() {
     if (this.state.hasError) return null;
     return this.props.children;
   }
 }

Главное — внутри ErrorBoundary всегда нужно логировать ошибку, иначе баг останется невидимым на проде. Для логирования подойдёт любой мониторинг ошибок, например, Sentry, Datadog, или собственный logger если он есть в проекте.

Также стоит понимать, что обернуть в ErrorBoundary для того, чтобы ошибка не блокировала весь компонент можно только второстепенные компоненты. То, что отвечает за вывод суммы, реквизиты и кнопка оплаты должны падать громко. ErrorBoundary подходит только для элементов, без которых оплата всё равно возможна.

Выводы

  1. Полифилл formatjs/intl-durationformat@0.7.4 отдает RangeError, если передать в негоhours ≥ 24 без days. Нет предупреждений — сразу исключение.

  2. ErrorBoundary на уровне компонента, не страницы. Оборачивайте некритичные элементы - и всегда с логированием в мониторинг.