为了账号安全,请及时绑定邮箱和手机立即绑定

Flutter 使用来自 Golang RFC3339 的 DateTime 解析 json:

Flutter 使用来自 Golang RFC3339 的 DateTime 解析 json:

Go
缥缈止盈 2023-04-24 15:57:26
当尝试读取在 Dart / Flutter 中使用 golangs json 包生成的 json 文件时,我注意到解析日期会产生错误:FormatException: Invalid date format一个示例是在 Go 服务器上生成的以下 json:{    ...    "dateCreated": "2018-09-29T19:51:57.4139787-07:00",    ...}我正在使用代码生成方法进行 json(反)序列化,以避免编写所有样板代码。json_serializable 包是可用于此目的的标准包。所以我的代码如下所示:@JsonSerializable()class MyObj {  DateTime dateCreated;  MyObj( this.dateCreated);  factory MyObj.fromJson(Map<String, dynamic> json) => _$MyObjFromJson(json);    Map<String, dynamic> toJson() => _$MyObjToJson(this); }
查看完整描述

2 回答

?
米脂

TA贡献1836条经验 获得超3个赞

因为文档没有充分涵盖这一点,所以我花了一天时间研究颤动源和不同事物的反复试验来解决它。所以不妨分享一下。


Golang 默认情况下在序列化为 Json 时在 RFC3339 中编码 time.Time(如在给定的示例中)。Flutter 明确支持 RFC3339,为什么它不起作用?答案是秒小数部分的支持方式略有不同。虽然 Golang 产生 7 位数字的精度,但 Dart 最多只支持 6 位数字并且不会优雅地处理违规情况。因此,如果将示例更正为只有 6 位精度,它将在 Dart 中解析得很好:


{

    ...

    "dateCreated": "2018-09-29T19:51:57.413978-07:00",

    ...

}

为了以通用的方式解决这个问题,您有两个选择:1. 从字符串中截断额外的精度,或者 2. 实现您自己的解析。假设我们扩展DateTime类并创建您自己的CustomDateTime. 新类重写了parse方法,在将其交给父类的解析方法之前删除 6 位数字后的所有多余部分。


现在我们可以在我们的 Dart 类中使用了CustomDateTime。例如:


@JsonSerializable()

class MyObj {


  CustomDateTime dateCreated;


  MyObj( this.dateCreated);


  factory MyObj.fromJson(Map<String, dynamic> json) => _$MyObjFromJson(json);  

  Map<String, dynamic> toJson() => _$MyObjToJson(this); 

}

但是当然现在代码生成被破坏了,我们得到以下错误:


Error running JsonSerializableGenerator

Could not generate 'toJson' code for 'dateCreated'.

None of the provided 'TypeHelper' instances support the defined type.

幸运的是,该json_annotation软件包现在为我们提供了一个简单的解决方案 - The JsonConverter. 以下是如何在我们的示例中使用它:


首先定义一个转换器,向代码生成器解释如何转换我们的CustomDateTime类型:


class CustomDateTimeConverter implements JsonConverter<CustomDateTime, String> {

  const CustomDateTimeConverter();


  @override

  CustomDateTime fromJson(String json) =>

      json == null ? null : CustomDateTime.parse(json);


  @override

  String toJson(CustomDateTime object) => object.toIso8601String();

}

其次,我们只是将此转换器注释为使用我们的 CustomDateTime 数据类型的每个类:


@JsonSerializable()

@CustomDateTimeConverter()

class MyObj {


  CustomDateTime dateCreated;


  MyObj( this.dateCreated);


  factory MyObj.fromJson(Map<String, dynamic> json) => _$MyObjFromJson(json);  

  Map<String, dynamic> toJson() => _$MyObjToJson(this); 

}

这满足了代码生成器和 Voila!我们可以读取带有来自 golang time.Time 的 RFC3339 时间戳的 json。


查看完整回答
反对 回复 2023-04-24
?
泛舟湖上清波郎朗

TA贡献1818条经验 获得超3个赞

我有同样的问题。我找到了一个非常简单的解决方案。我们可以使用带有 JsonConverter 的自定义转换器。


import 'package:json_annotation/json_annotation.dart';


class CustomDateTimeConverter implements JsonConverter<DateTime, String> {

  const CustomDateTimeConverter();


  @override

  DateTime fromJson(String json) {

    if (json.contains(".")) {

      json = json.substring(0, json.length - 1);

    }


    return DateTime.parse(json);

  }


  @override

  String toJson(DateTime json) => json.toIso8601String();

}

import 'package:json_annotation/json_annotation.dart';

import 'package:my_app/shared/helpers/custom_datetime.dart';


part 'publication_document.g.dart';


@JsonSerializable()

@CustomDateTimeConverter()

class PublicationDocument {

  final int id;

  final int publicationId;


  final DateTime publicationDate;

  final DateTime createTime;

  final DateTime updateTime;

  final bool isFree;


  PublicationDocument({

    this.id,

    this.publicationId,

    this.publicationDate,

    this.createTime,

    this.updateTime,

    this.isFree,

  });


  factory PublicationDocument.fromJson(Map<String, dynamic> json) =>

      _$PublicationDocumentFromJson(json);

  Map<String, dynamic> toJson() => _$PublicationDocumentToJson(this);

}


查看完整回答
反对 回复 2023-04-24
  • 2 回答
  • 0 关注
  • 153 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信