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

如何在Cloud Firestore中将日期转换为Timestamp存储

解决React中Cloud Firestore存储生日为Timestamp类型的问题

问题描述

在React项目中使用Cloud Firestore时,希望将用户通过type="date"输入框提交的生日日期以Timestamp类型存储到数据库,但目前传入的是字符串格式,无法直接存储为Timestamp。

问题根源

你的代码中,birthDate初始值是Timestamp,但在日期输入框的onChange事件中,直接将event.target.value(字符串格式的日期,如"2024-05-20")赋值给了birthDate,导致最终存入Firestore的是字符串而非Timestamp类型。

解决方案

只需在将日期存入Firestore时,把字符串格式的日期转换为Firestore的Timestamp即可,有两种实现方式:

方式1:提交数据时转换(推荐)

保持state中存储用户输入的字符串日期,在调用addDoc时转换为Timestamp,这样既方便后续展示原始输入,又能正确存储类型:

  1. 调整birthDate的初始状态:
const [birthDate, setBirthDate] = useState(""); // 初始为空字符串,符合用户未输入的状态
  1. 修改日期输入框的onChange(无需额外转换,直接存字符串):
<input 
    type="date" 
    name="data_nascimento" 
    id="data_nascimento" 
    required
    onChange={(event) => {
        setBirthDate(event.target.value);
    }}
/>
  1. 在handleRegister的addDoc中转换为Timestamp:
await addDoc(userCollectionRef, {
    tipoUsuario: 'aluno',
    idUsuario: auth.currentUser.uid,
    nome,
    email,
    curso,
    dataNascimento: Timestamp.fromDate(new Date(birthDate)), // 核心转换代码
});

方式2:输入时直接转换为Timestamp

在用户选择日期时,直接将字符串转换为Timestamp并存入state:

<input 
    type="date" 
    name="data_nascimento" 
    id="data_nascimento" 
    required
    onChange={(event) => {
        const selectedDate = new Date(event.target.value);
        setBirthDate(Timestamp.fromDate(selectedDate));
    }}
/>

这种方式下,state中直接存储Timestamp,后续提交时可直接传入addDoc。

额外优化:修复用户创建与数据存储的顺序问题

你的原代码中,createUserWithEmailAndPassword同时使用了await和.then(),可能导致在用户数据存入Firestore前就跳转到首页,引发数据存储失败。建议调整为顺序执行:

const handleRegister = async () => {
    try {
        // 先等待用户账号创建完成
        const userCredential = await createUserWithEmailAndPassword(
            auth,
            registerEmail,
            registerPassword
        );
        // 设置登录状态
        localStorage.setItem("isAuth", true);
        setIsAuth(true);
        // 存入用户详细信息到Firestore
        await addDoc(userCollectionRef, {
            tipoUsuario: 'aluno',
            idUsuario: userCredential.user.uid, // 直接从userCredential获取uid更可靠
            nome,
            email,
            curso,
            dataNascimento: Timestamp.fromDate(new Date(birthDate)),
        });
        // 最后跳转首页
        navigate("/home");
        console.log(userCredential.user);
    } catch (error) {
        console.log(error.message);
    }
};

完整修改后的代码

import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
import { createUserWithEmailAndPassword } from "firebase/auth";
import {
  collection,
  addDoc,
  Timestamp,
} from "firebase/firestore";
import { auth, db } from "../firebase-config";

function Register({ setIsAuth }) {

  let navigate = useNavigate();
  const VoltarLogin = () => {
      navigate("/login");
  };

  const [registerEmail, setRegisterEmail] = useState("");
  const [registerPassword, setRegisterPassword] = useState("");

  const [nome, setNome] = useState("");
  const [email, setEmail] = useState("");
  const [curso, setCurso] = useState("");
  const [birthDate, setBirthDate] = useState(""); // 修改初始值

  const userCollectionRef = collection(db, "usuarios");

  const handleRegister = async () => {
      try {
          const userCredential = await createUserWithEmailAndPassword(
              auth,
              registerEmail,
              registerPassword
          );
          localStorage.setItem("isAuth", true);
          setIsAuth(true);
          
          await addDoc(userCollectionRef, {
              tipoUsuario: 'aluno',
              idUsuario: userCredential.user.uid,
              nome,
              email,
              curso,
              dataNascimento: Timestamp.fromDate(new Date(birthDate)),
          });
          
          navigate("/home");
          console.log(userCredential.user);
      } catch (error) {
          console.log(error.message);
      }
    };

  return (
    <div className="box">
      <div className="center-box-register">
          <div className="card-register">
              <h1>Cadastro</h1>
          <div className="linha">
          </div>

                  <div className="textfield">
                      <label htmlFor="name">Nome:</label>
                      <input 
                      type="text"
                      name="nome"
                      id="nome"
                      placeholder="Digite seu nome"
                      required
                      onChange={(event) => {
                          setNome(event.target.value);
                          }}>
                      </input>
                  </div>

                  <div className="textfield">
                      <label htmlFor="email">E-mail:</label>
                      <input 
                      type="email" 
                      className="email" 
                      id="email" 
                      placeholder="Digite seu e-mail" 
                      required
                      onChange={(event) => {
                          setRegisterEmail(event.target.value);
                          setEmail(event.target.value);
                      }}>
                      </input>
                  </div>

                  <div className="textfield">
                      <label htmlFor="senha">Senha:</label>
                      <input 
                      type="password" 
                      name="senha" 
                      id="senha" 
                      placeholder="Digite sua senha" 
                      required
                      onChange={(event) => {
                          setRegisterPassword(event.target.value);
                      }}>
                      </input>
                  </div>

                  <div className="cursos">
                      <label htmlFor="user">Selecione seu curso: </label>
                      <select 
                      name="user" 
                      id="user" 
                      required
                      onChange={(event) => {
                          setCurso(event.target.value);
                      }}>
                          <option disabled selected> Curso... </option>
                          <option value="mtecaai">M-TEC PI | Administração</option>
                          <option value="mtecds">M-TEC PI | Desenvolvimento de Sistemas</option>
                          <option value="mtecaqi">M-TEC PI | Química</option>
                          <option value="etimaai">ETIM Administração</option>
                          <option value="etimds">ETIM Desenvolvimento de Sistemas</option>
                          <option value="erimaqi">ETIM Química</option>
                          <option value="eadaai">Administração - EAD</option>
                          <option value="rh">Recursos Humanos</option>
                          <option value="sec">Secretariado</option>
                          <option value="log">Logística</option>
                      </select>
                  </div>

                  <div className="textfield">
                      <label htmlFor="data_nascimento">Data de nascimento:</label>
                      <input 
                      type="date" 
                      name="data_nascimento" 
                      id="data_nascimento" 
                      required
                      onChange={(event) => {
                          setBirthDate(event.target.value);
                      }}>
                      </input>
                  </div>

                  <button name="submit" id="submit" className="btn-cadastro" onClick={handleRegister}>Cadastrar-se</button>

                  <div className="lin2">
                  </div>

                  <div className="login">
                      <button onClick={VoltarLogin} className="btn-voltar">Já tem uma conta?</button>
                  </div>
          </div>
    </div>
    </div>
     )
   }

export default Register;

内容的提问来源于stack exchange,提问作者Carlos03

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 00:01:14