Веб

Почему в MUI DateTimePicker появляются невидимые символы

MUI X DateTimePicker добавляет невидимые Unicode-символы для поддержки RTL, которые попадают в строку значения. Эти символы ломают парсинг dayjs, из-за чего .unix() возвращает null.

Использую @mui/x-date-pickers v8.19.0 с @mui/material v7.3.4 в приложении Next.js 15.5.6. Я обернул свое приложение в LocalizationProvider и использую DateTimePicker следующим образом:

tsx
<DateTimePicker
  label="With Time Clock"
  sx={{ direction: 'ltr' }}
  name="time"
  viewRenderers={{
    hours: renderTimeViewClock,
    minutes: renderTimeViewClock,
    seconds: renderTimeViewClock,
  }}
/>

Когда я пытаюсь преобразовать выбранное значение в Unix-временную метку с помощью dayjs(value).unix(), результат всегда равен null. В строке значения селектора присутствуют невидимые символы, например:

'PM⁩ ⁦01:22⁩ ⁦11/29/2025'

Почему эти невидимые символы появляются, хотя я явно установил направление селектора в ltr?

Содержание


Краткое объяснение

MUI X всегда вставляет невидимые Unicode-символы для поддержки RTL внутри базового <TextField>.
Эти символы “протекают” в строковое значение, которое вы получаете из пикера, поэтому строка не является чистым представлением даты.
dayjs не может разобрать строку, содержащую эти символы, поэтому dayjs(value).unix() возвращает null.


Какие символы добавляются?

Символ Код Назначение
U+2069 Pop Directional Isolate (PDI)
U+2068 Isolate Initiate (ISO)
U+200E Left‑to‑Right Mark (LRM)
U+200F Right‑to‑Left Mark (RLM)

Эти метки невидимы для глаза, но являются частью строки, которую предоставляет пикер.
Смотрите документацию MUI X: Field components add Unicode characters for RTL.


Почему они мешают dayjs

dayjs ожидает чистую строку в известном формате (например, "MM/DD/YYYY HH:mm").
Когда строка содержит любые из указанных выше меток, парсер не может сопоставить токены формата и возвращает undefined, который .unix() затем превращает в null.
Таким образом:

ts
const raw = 'PM⁩ ⁦01:22⁦ ⁦11/29/2025'; // содержит U+2069, U+2068
dayjs(raw).unix(); // → null

Как исправить

1. Удалить все невидимые символы перед парсингом

ts
function stripInvisible(str: string): string {
  // Убираем все символы вида U+2066‑U+2069, U+200E‑U+200F и т.д.
  return str.replace(/[\u200E\u200F\u202A-\u202E\u2066-\u2069]/g, '');
}

const cleaned = stripInvisible(value); // → 'PM 01:22 11/29/2025'
const timestamp = dayjs(cleaned).unix(); // теперь работает

2. Использовать value как объект даты

Если вы передаёте value в компонент как объект dayjs или Date, то не нужно парсить строку:

tsx
const [value, setValue] = useState(dayjs());

<DateTimePicker
  value={value}
  onChange={(newValue) => setValue(newValue)}
  // …
/>

const timestamp = value.unix(); // или dayjs(value).unix()

Поскольку в onChange вы сразу получаете объект, а не строку, проблем с невидимыми символами не будет.

3. Конфигурировать формат вывода

Если вы всё же хотите работать со строкой, можно задать inputFormat без символов, которые вызывают проблемы:

tsx
<DateTimePicker
  inputFormat="MM/DD/YYYY HH:mm"
  // …
/>

Но это не решит проблему с невидимыми маркерами; они всё равно останутся в value, если вы не очистите их.


Объект даты напрямую

Самый надёжный способ – не использовать строку.
Передавайте и получайте value как объект даты (dayjs, Date, Luxon, …).
MUI X возвращает объект, а не строку, если вы используете onChange:

ts
<DateTimePicker
  value={value}
  onChange={(newValue) => setValue(newValue)}
  // …
/>

const timestamp = dayjs(value).unix(); // безопасно

Итоги

  • MUI X добавляет невидимые символы для RTL‑поддержки; они остаются в строковом значении поля.
  • Эти символы ломают парсинг dayjs, поэтому unix() возвращает null.
  • Решения: очистить строку от невидимых символов, использовать объект даты напрямую, либо изменить формат вывода.

Если вам нужен только Unix‑таймстамп, лучше хранить значение как объект даты и преобразовывать его в момент, когда это действительно требуется.

Авторы
Проверено модерацией
Модерация