You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 16:32:01