Почему в 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 следующим образом:
<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?
Содержание
- Краткое объяснение
- Какие символы добавляются?
- Почему они мешают
dayjs - Как исправить
- Вариант: использовать объект даты напрямую
Краткое объяснение
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.
Таким образом:
const raw = 'PM 01:22 11/29/2025'; // содержит U+2069, U+2068
dayjs(raw).unix(); // → null
Как исправить
1. Удалить все невидимые символы перед парсингом
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, то не нужно парсить строку:
const [value, setValue] = useState(dayjs());
<DateTimePicker
value={value}
onChange={(newValue) => setValue(newValue)}
// …
/>
const timestamp = value.unix(); // или dayjs(value).unix()
Поскольку в onChange вы сразу получаете объект, а не строку, проблем с невидимыми символами не будет.
3. Конфигурировать формат вывода
Если вы всё же хотите работать со строкой, можно задать inputFormat без символов, которые вызывают проблемы:
<DateTimePicker
inputFormat="MM/DD/YYYY HH:mm"
// …
/>
Но это не решит проблему с невидимыми маркерами; они всё равно останутся в value, если вы не очистите их.
Объект даты напрямую
Самый надёжный способ – не использовать строку.
Передавайте и получайте value как объект даты (dayjs, Date, Luxon, …).
MUI X возвращает объект, а не строку, если вы используете onChange:
<DateTimePicker
value={value}
onChange={(newValue) => setValue(newValue)}
// …
/>
const timestamp = dayjs(value).unix(); // безопасно
Итоги
- MUI X добавляет невидимые символы для RTL‑поддержки; они остаются в строковом значении поля.
- Эти символы ломают парсинг
dayjs, поэтомуunix()возвращаетnull. - Решения: очистить строку от невидимых символов, использовать объект даты напрямую, либо изменить формат вывода.
Если вам нужен только Unix‑таймстамп, лучше хранить значение как объект даты и преобразовывать его в момент, когда это действительно требуется.