React项目中如何将ISO 8601格式日期转换为dd/mm/yy格式?
解决MaterialReactTable中ISO 8601日期转dd/mm/yy格式的问题
我在React项目中使用MaterialReactTable展示数据,JSON里的createdAt和updatedAt字段是ISO 8601格式(示例值:"2016-03-24T05:28:03.099+05:30"),想要转换成dd/mm/yy格式显示。自己写了DateTimeFormatter组件结合dayjs处理,但没达到预期效果,求解决。
相关代码
DataTable组件
import React, { useState } from "react"; import { MaterialReactTable } from "material-react-table"; import Fuse from "fuse.js"; import { Slider, TextField, IconButton, Drawer } from "@mui/material"; import { DatePicker } from "@mui/x-date-pickers"; import GroupingDropdown from "./GroupingDropDown"; import DateTimeFormatter from "./DateTimeFormatter"; import CategorySubcategoryFilter from "./CategorySubcategoryFilter"; import FilterListIcon from "@mui/icons-material/FilterList"; import SortIcon from "@mui/icons-material/Sort"; import GroupIcon from "@mui/icons-material/Group"; import SortingFilter from "./SortingFilter"; const DataTable = ({ data, columns }) => { const [columnVisibility, setColumnVisibility] = useState({}); const [globalFilter, setGlobalFilter] = useState(""); const [nameFilter, setNameFilter] = useState(""); const [categoryFilter, setCategoryFilter] = useState([]); const [subcategoryFilter, setSubcategoryFilter] = useState([]); const [priceRange, setPriceRange] = useState([0, 1000]); const [createdAtRange, setCreatedAtRange] = useState([null, null]); const [grouping, setGrouping] = useState([]); const [showFilterDrawer, setShowFilterDrawer] = useState(false); const [showSortingDrawer, setShowSortingDrawer] = useState(false); const [showGroupingDrawer, setShowGroupingDrawer] = useState(false); const [sortedData, setSortedData] = useState(data); const fuse = new Fuse(sortedData, { keys: ["name"], includeMatches: true, }); const handleSorting = (columnKey) => { const sorted = [...sortedData].sort((a, b) => { if (a[columnKey] < b[columnKey]) return -1; if (a[columnKey] > b[columnKey]) return 1; return 0; }); setSortedData(sorted); }; const filteredData = data.filter((item) => { return ( (fuse.search(globalFilter).map((result) => result.item.name).includes(item.name) || globalFilter === "") && (fuse.search(nameFilter).map((result) => result.item.name).includes(item.name) || nameFilter === "") && (categoryFilter.length === 0 || categoryFilter.includes(item.category)) && (subcategoryFilter.length === 0 || subcategoryFilter.includes(item.subcategory)) && item.price >= priceRange[0] && item.price <= priceRange[1] && (createdAtRange[0] === null || createdAtRange[1] === null || (new Date(item.createdAt) >= createdAtRange[0] && new Date(item.createdAt) <= createdAtRange[1])) ); }); const handleGroupingChange = (columnIds) => { setGrouping(columnIds); setShowGroupingDrawer(false); }; return ( <> <div style={{ display: "flex", alignItems: "flex-start", flexDirection: "row-reverse", padding: "10px" }}> <input value={globalFilter || ""} onChange={(e) => setGlobalFilter(e.target.value)} placeholder="Search..." style={{ marginRight: "10px", padding: "8px", border: "1px solid #ccc", borderRadius: "5px", fontSize: "14px", outline: "none" }} /> <input value={nameFilter || ""} onChange={(e) => setNameFilter(e.target.value)} placeholder="Filter by name..." style={{ marginRight: "10px", padding: "8px", border: "1px solid #ccc", borderRadius: "5px", fontSize: "14px", outline: "none" }} /> <IconButton onClick={() => setShowFilterDrawer(true)}> <FilterListIcon /> </IconButton> <IconButton onClick={() => setShowSortingDrawer(true)}> <SortIcon /> </IconButton> <IconButton onClick={() => setShowGroupingDrawer(true)}> <GroupIcon /> </IconButton> </div> <MaterialReactTable columns={columns} data={filteredData} columnVisibility={columnVisibility} onColumnVisibilityChange={setColumnVisibility} enableSorting globalFilter={globalFilter} enableGrouping grouping={grouping} renderCell={({ cell }) => { if (cell.column.accessorKey === "createdAt" || cell.column.accessorKey === "updatedAt") { return <DateTimeFormatter value={cell.value} />; } return cell.renderedCellValue; }} /> </> ); }; export default DataTable;
DateTimeFormatter.jsx
import React from "react"; import dayjs from "dayjs"; const DateTimeFormatter = ({ value }) => { console.log("Original value:", value); // Debugging statement const dateTime = dayjs(value); console.log("Formatted date:", dateTime.format("DD/MM/YY")); // Debugging statement const formattedDateTime = dateTime.format("DD/MM/YY"); return <span>{formattedDateTime}</span>; }; export default DateTimeFormatter;
示例JSON数据
{ "id": 1, "name": "Nutrition Attachment", "category": "Health", "subcategory": "Nutrition", "createdAt": "2016-03-24T05:28:03.099+05:30", "updatedAt": "2016-03-24T05:28:03.099+05:30", "price": 24.99, "sale_price": 21.95 }
修复方案
1. 修复dayjs的日期解析逻辑
带时区偏移的ISO字符串可能导致dayjs解析异常,需要导入自定义解析插件并显式指定格式:
import React from "react"; import dayjs from "dayjs"; import "dayjs/plugin/customParseFormat"; // 扩展dayjs的自定义解析能力 dayjs.extend(require("dayjs/plugin/customParseFormat")); const DateTimeFormatter = ({ value }) => { // 显式匹配带时区的ISO格式 const dateTime = dayjs(value, "YYYY-MM-DDTHH:mm:ss.SSSZ"); // 解析失败时显示默认文本 return <span>{dateTime.isValid() ? dateTime.format("DD/MM/YY") : "无效日期"}</span>; }; export default DateTimeFormatter;
2. 确保获取原始日期值
MaterialReactTable的cell.value可能经过默认格式化,直接从原始数据中取值更可靠:
// 修改DataTable中MaterialReactTable的renderCell属性 renderCell={({ cell }) => { const accessorKey = cell.column.accessorKey; if (accessorKey === "createdAt" || accessorKey === "updatedAt") { // 直接获取原始JSON中的日期字符串 return <DateTimeFormatter value={cell.row.original[accessorKey]} />; } return cell.renderedCellValue; }}
3. 提前格式化数据(替代方案)
如果上述方法仍不生效,可以在传入表格前直接格式化所有日期字段:
// 在DataTable组件中处理传入的data import dayjs from "dayjs"; const DataTable = ({ data, columns }) => { // 预处理数据,格式化日期字段 const processedData = data.map(item => ({ ...item, createdAt: dayjs(item.createdAt).format("DD/MM/YY"), updatedAt: dayjs(item.updatedAt).format("DD/MM/YY") })); // 后续使用processedData替代data传入表格 // ...其他代码不变 };
内容的提问来源于stack exchange,提问作者vikas rathore
相关产品推荐
相关产品推荐

