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

如何使用Flutter Freezed包在模型中生成DateTime类型字段

正确生成含DateTime字段的Freezed模型类(适配Firestore Timestamp)

问题场景

编写的Freezed模型代码如下:

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'user_model.freezed.dart';
part 'user_model.g.dart';

@freezed
class UserModel with _$UserModel {
  factory UserModel({
    required String id,
    @Default('') String uniqueId,
    @Default(DateTime.now()) DateTime dob,

  }) = _UserModel;

  factory UserModel.fromJson(Map<String, dynamic> json) =>
      _$UserModelFromJson(json);
}

使用DateTime.now()作为dob字段默认值时,无法生成所需的.g.dart文件。将代码修改为把dob设为必填字段后,虽然能正常生成文件,但生成的fromJson代码会将dob按字符串解析,需要手动修改为适配Firestore Timestamp的逻辑:

// 生成的原始代码
dob: DateTime.parse(json['dob'] as String),
// 需要手动改成
dob: (json['dob'] as Timestamp?)?.toDate() ?? DateTime.now()

不想每次生成代码后手动修改,需要找到正确的配置方式。


解决方案

核心思路是通过自定义Json转换器让Freezed自动处理Firestore Timestamp与Dart DateTime的转换,同时通过合理的方式设置运行时默认值。

步骤1:实现Timestamp与DateTime的转换器

创建两个转换器(分别处理非空和可空的DateTime字段):

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

// 处理非空DateTime与Timestamp的转换
class TimestampConverter implements JsonConverter<DateTime, Timestamp> {
  const TimestampConverter();

  @override
  DateTime fromJson(Timestamp timestamp) => timestamp.toDate();

  @override
  Timestamp toJson(DateTime date) => Timestamp.fromDate(date);
}

// 处理可空DateTime与Timestamp的转换
class NullableTimestampConverter implements JsonConverter<DateTime?, Timestamp?> {
  const NullableTimestampConverter();

  @override
  DateTime? fromJson(Timestamp? timestamp) => timestamp?.toDate();

  @override
  Timestamp? toJson(DateTime? date) => date != null ? Timestamp.fromDate(date) : null;
}

步骤2:在模型中应用转换器并处理默认值

由于DateTime.now()是运行时计算的值,不能直接作为@Default的参数(Freezed要求默认值为编译时常量),可以选择以下两种写法:

写法一:非空字段+常量默认值+工厂函数替换
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'user_model.freezed.dart';
part 'user_model.g.dart';

class TimestampConverter implements JsonConverter<DateTime, Timestamp> {
  const TimestampConverter();

  @override
  DateTime fromJson(Timestamp timestamp) => timestamp.toDate();

  @override
  Timestamp toJson(DateTime date) => Timestamp.fromDate(date);
}

@freezed
class UserModel with _$UserModel {
  factory UserModel({
    required String id,
    @Default('') String uniqueId,
    // 用编译时常量作为默认值,同时应用转换器
    @TimestampConverter() @Default(DateTime(0)) DateTime dob,
  }) = _UserModel;

  // 自定义fromJson,将默认的DateTime(0)替换为当前时间
  factory UserModel.fromJson(Map<String, dynamic> json) {
    final rawModel = _$UserModelFromJson(json);
    return rawModel.copyWith(
      dob: rawModel.dob == DateTime(0) ? DateTime.now() : rawModel.dob,
    );
  }
}
写法二:可空字段+工厂函数补全默认值
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'user_model.freezed.dart';
part 'user_model.g.dart';

class NullableTimestampConverter implements JsonConverter<DateTime?, Timestamp?> {
  const NullableTimestampConverter();

  @override
  DateTime? fromJson(Timestamp? timestamp) => timestamp?.toDate();

  @override
  Timestamp? toJson(DateTime? date) => date != null ? Timestamp.fromDate(date) : null;
}

@freezed
class UserModel with _$UserModel {
  factory UserModel({
    required String id,
    @Default('') String uniqueId,
    // 可空字段+转换器
    @NullableTimestampConverter() DateTime? dob,
  }) = _UserModel;

  // 自定义fromJson,为空时补充当前时间
  factory UserModel.fromJson(Map<String, dynamic> json) {
    final rawModel = _$UserModelFromJson(json);
    return rawModel.copyWith(
      dob: rawModel.dob ?? DateTime.now(),
    );
  }
}

原理说明

  1. 转换器作用:通过JsonConverter注解,告诉Freezed在序列化/反序列化时,自动将Firestore的Timestamp类型与Dart的DateTime类型互相转换,无需手动修改生成代码。
  2. 默认值处理:由于DateTime.now()不是编译时常量,无法直接用在@Default中,因此通过自定义fromJson工厂函数,在反序列化时补充运行时的默认值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 03:15:40