Флаттер при разборе json с DateTime из Golang RFC3339: FormatException: неверный формат даты - PullRequest
0 голосов
/ 13 октября 2018

При попытке прочитать файлы json, сгенерированные с помощью пакета golangs json в Dart / Flutter, я заметил, что даты разбора выдают ошибку:

FormatException: Invalid date format

Примером является следующий json, сгенерированный на сервере Go:

{
    ...
    "dateCreated": "2018-09-29T19:51:57.4139787-07:00",
    ...
}

Я использую подход генерации кода для сериализации json (de), чтобы избежать написания всего кода панели котла.Пакет 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 ]

0 голосов
/ 29 апреля 2019

У меня та же проблема.Я нашел очень простое решение.Мы можем использовать пользовательский конвертер с 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);
}
0 голосов
/ 13 октября 2018

Поскольку документация не покрывает это в достаточной мере, мне потребовался день, чтобы исследовать источники флаттера и проб и ошибок различных вещей, чтобы решить его.Так что может также поделиться им.

Golang по умолчанию кодирует время. Время в RFC3339 при сериализации в Json (как в данном примере).Flutter явно поддерживает RFC3339, так почему же он не работает?Ответ - небольшая разница в том, как поддерживается часть доли секунды.В то время как Golang дает точность 7 цифр, Dart поддерживает только до 6 цифр и не обрабатывает нарушения корректно.Таким образом, если пример исправлен так, чтобы иметь только 6 цифр точности, он будет очень хорошо разбираться в Dart:

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

Для общего решения этой проблемы у вас есть два варианта: 1. усечь дополнительноеточность из строки, или 2. реализовать свой собственный анализ.Давайте предположим, что мы расширили класс DateTime и создали ваш собственный CustomDateTime.Новый класс имеет метод parse, переопределенный для удаления всего лишнего после 6 цифр перед передачей его методу разбора родительского класса.

Теперь мы можем использовать CustomDateTime в наших классах Dart.Например:

@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 теперь имеет простое решение для нас- 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); 
}

Это удовлетворяет генератор кода и вуаля!Мы можем читать json с метками времени RFC3339, которые приходят из времени Голанга. Время.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...