Reputation: 5987
I'm fetching data cloud firestore & trying to show in my app by using the following piece of code.
new Text(timeago.format(document.data['tripDoc']['docCreatedOn'])),
I'm using timeago
dart package to format that. But, after making updating to latest cloud firestore plugin I'm getting this error -
Another exception was thrown: type 'Timestamp' is not a subtype of type 'DateTime'
Can't able to understand how to parse this 'TimeStamp' object to 'DateTime'. Because timeago
plugin need data in DateTime object format.
Upvotes: 40
Views: 50315
Reputation: 186
Firebase cloud_firestore has changed their mechanism of storing DateTime object value in a doc field, in previous mechanism datetime.millisecondsSinceEpoch stores int in firestore, but now it will be stored as date, then you need a logic to handle them.
To overcome the obstacles during data transmission you can write toMap() and fromMap() methods as following:
class YourModel {
String? firstName;
String? phoneNumber;
DateTime? createdAt;
YourModel({
this.firstName,
this.phoneNumber,
this.createdAt,
});
Map<String, dynamic> toMap() {
return <String, dynamic>{
'firstName': firstName,
'phoneNumber': phoneNumber,
'createdAt': createdAt?.millisecondsSinceEpoch,
};
}
factory YourModel.fromMap(Map<String, dynamic> map) {
return YourModel(
firstName: map['firstName'] != null ? map['firstName'] as String : null,
phoneNumber:
map['phoneNumber'] != null ? map['phoneNumber'] as String : null,
createdAt: map['createdAt'] != null
// ? DateTime.fromMillisecondsSinceEpoch(map['createdAt'] as int) // old technique, fixed below
? (map['createdAt'] is Timestamp
? (map['createdAt'] as Timestamp).toDate()
: DateTime.fromMillisecondsSinceEpoch(map['createdAt'] as int))
: null,
);
}
}
Upvotes: 0
Reputation: 51
This solution worked for me:
DateTime convertTimestampMapToDateTime(dynamic date) {
final createdAt = date;
DateTime parsedCreatedAt;
if (createdAt is Map) {
parsedCreatedAt = Timestamp(
createdAt['_seconds'] as int,
createdAt['_nanoseconds'] as int,
).toDate();
}
return parsedCreatedAt;
}
Store your timestamp Map from Firestore in the createdAt variable and then parsedCreatedAt will have your timestamp in date format. you can then use it as per your requirements.
Upvotes: 0
Reputation: 24910
There are various ways to convert TimeStamp to DateTime
which differs based on the scenario.
I have tried to gather all the possible ways to convert Firebase timeStamp
to DateTime
. Pick which works for you.
Firebase timestamp
to DateTime
:document['timeStamp'].toDate()
(document["timeStamp"] as Timestamp).toDate()
DateTime.fromMillisecondsSinceEpoch(document['timeStamp'].millisecondsSinceEpoch);
Timestamp.fromMillisecondsSinceEpoch(document['timeStamp'].millisecondsSinceEpoch).toDate();
If timeStamp
is in microseconds
use:
DateTime.fromMicrosecondsSinceEpoch(timestamp * 1000000);
If timeStamp
is in milliseconds
use:
DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
Add the following function in your dart file.
String formatTimestamp(Timestamp timestamp) {
var format = new DateFormat('yyyy-MM-dd'); // <- use skeleton here
return format.format(timestamp.toDate());
}
call it as formatTimestamp(document['timestamp'])
Upvotes: 1
Reputation: 161
i had the same error because date is inserted as TimeStamp type in Firebase Firestore and i was trying to parse it as if it was Date type
this was my model that got me the error when trying to get data from firestore
class Post {
String title;
String body;
String teacherName;
DateTime date;
Post({
required this.title,
required this.body,
required this.teacherName,
required this.date,
});
factory Post.fromJson(Map<String, dynamic> json) => Post(
title: json["title"],
body: json["body"],
teacherName: json["teacher"],
date: DateTime.parse(json["date"]),
);
Map<String, dynamic> toJson() => {
"title": title,
"body": body,
"teacher": teacherName,
"date": date,
};
}
i discovered that firestore has toDate() method in TimeStamp() that transform timestamp to Datetime
so in my code in toJson method i parsed the date field as Timestamp then transform it as DateTime
factory Post.fromJson(Map<String, dynamic> json) => Post(
title: json["title"],
body: json["body"],
teacherName: json["teacher"],
date: (json["date"] as Timestamp).toDate(),
);
Upvotes: 3
Reputation: 443
i use this line to get date from firestore:
postDate: doc.data().toString().contains('postDate') ? doc.get('postDate') : DateTime.now()
in this method:
List<AdModel?>? _adModelListFromQuerySnapshot(QuerySnapshot snapshot) {
try {
return snapshot.docs.map((doc) {
return PostModel(
title: doc.data().toString().contains('title') ? doc.get('title') :'',
description: doc.data().toString().contains('description') ?doc.get('description') : '',
adDate: doc.data().toString().contains('adDate') ? doc.get('adDate') : DateTime.now(),
);
}).toList();
} catch (error) {
print(' Show ${error.toString()}');
return null;
}
}
PostModel {
DateTime? postDate;
PostModel({this.postDate});
}
I wish this is helpful
Upvotes: 0
Reputation: 741
Following function will take care of all.
DateTime vikiDate(dynamic dateValue) {
if (dateValue is DateTime) {
return dateValue;
} else if (dateValue is String) {
return DateTime.parse(dateValue);
}
else if (dateValue is Timestamp) {
return dateValue.toDate();
}
else{
return null;
}
}
Just use it as
DateTime acceptedAt = vikiDate(json['accepted_at']);
Upvotes: 2
Reputation: 217
For the record, if you're using freezed, this worked for me:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:flutter/foundation.dart';
part 'activity_card_model.freezed.dart';
part 'activity_card_model.g.dart';
DateTime _createdAtFromJson(Timestamp timestamp) => timestamp.toDate();
Timestamp _createdAtToJson(DateTime date) => Timestamp.fromDate(date);
DateTime _updatedAtFromJson(Timestamp timestamp) => timestamp.toDate();
Timestamp _updatedAtToJson(DateTime date) => Timestamp.fromDate(date);
@freezed
abstract class ActivityCard implements _$ActivityCard {
const ActivityCard._();
const factory ActivityCard({
@Default(true) bool active,
@Default('other') String category,
@JsonKey(name: 'created_at', fromJson: _createdAtFromJson, toJson: _createdAtToJson)
required DateTime createdAt,
required String description,
required String heading,
String? id,
@JsonKey(name: 'image_name') @Default('') String imageName,
@JsonKey(name: 'img_src') @Default('') String imageURL,
@JsonKey(name: 'link') String? linkURL,
@JsonKey(name: 'link_description') String? linkDescription,
String? subheading,
@JsonKey(name: 'updated_at', fromJson: _updatedAtFromJson, toJson: _updatedAtToJson)
required DateTime updatedAt,
}) = _ActivityCard;
factory ActivityCard.fromFirestore(DocumentSnapshot doc) {
Map<String, dynamic> json = doc.data as Map<String, dynamic>;
return ActivityCard.fromJson(json);
}
factory ActivityCard.fromJson(Map<String, dynamic> json) =>
_$ActivityCardFromJson(json);
factory ActivityCard.fromDocument(
DocumentSnapshot<Map<String, dynamic>> doc) {
final data = doc.data()!;
return ActivityCard.fromJson(data).copyWith(id: doc.id);
}
Map<String, dynamic> toDocument() => toJson()..remove('id');
}
Upvotes: -1
Reputation: 766
I made changes in my model class for that error.
from Backend, I'm getting this response
"reported_date": "2021-02-19T05:45:57.434150Z",
change from
reportedDate = json['reported_date']
to
reportedDate = json['reported_date'] == null ? null : DateTime.parse(json['reported_date'] as String);
This solves my problem.
After parsing you can use any formate to read about formates
Below some of the example, I'm testing for reference
///return in 12:08 PM format
static String returnTime(DateTime dt) {
final DateFormat formatter = DateFormat('h:mm a');
String time = formatter.format(dt);
return time;
}
///return in Thu, Feb 18 format
String returnDate(DateTime dt) {
final DateFormat formatter = DateFormat('EEE, MMM d');
String date = formatter.format(dt);
return date;
}
///return day (Thu, Feb 18, will return 18)
String standaloneDay(DateTime dt) {
final DateFormat formatter = DateFormat('c');
String date = formatter.format(dt);
return date;
}
Upvotes: 0
Reputation: 5392
It is irrelavant but for those who use Timestamp (cloud_firestore) instead of DateTime you probably will get
<String, dynamic>' is not a subtype of type 'Timestamp'
class MyUser {
String uid;
String email;
Timestamp firstJoined;
MyUser.fromJson(Map<String, dynamic> data) {
this.uid = data['uid'] ?? '';
this.email = data['email'] ?? '';
// PARSE FIRESTORE TIMESTAMP
if (data['firstJoined'] != null) {
this.firstJoined = Timestamp(
data['firstJoined']['_seconds'],
data['firstJoined']['_nanoseconds'],
);
} else {
this.firstJoined=null;
}
}
}
Upvotes: 0
Reputation: 1541
If you use JsonSerializable, Use JsonConverter
class TimestampConverter implements JsonConverter<DateTime, Timestamp> {
const TimestampConverter();
@override
DateTime fromJson(Timestamp timestamp) {
return timestamp.toDate();
}
@override
Timestamp toJson(DateTime date) => Timestamp.fromDate(date);
}
@JsonSerializable()
class User{
final String id;
@TimestampConverter()
final DateTime timeCreated;
User([this.id, this.timeCreated]);
factory User.fromSnapshot(DocumentSnapshot documentSnapshot) =>
_$UserFromJson(
documentSnapshot.data..["_id"] = documentSnapshot.documentID);
Map<String, dynamic> toJson() => _$UserToJson(this)..remove("_id");
}
Upvotes: 13
Reputation: 447
Try document.data["data"].microsecondsSinceEpoch
This is working for me:-
User.fromDocument(DocumentSnapshot document){
dataNasc = DateTime.fromMicrosecondsSinceEpoch(document.data["data"].microsecondsSinceEpoch);
}
Upvotes: 2
Reputation: 1
This could also be an error because in the database or firebase there is some type that is missing or different name on
Upvotes: 0
Reputation: 43
The Cloud Firebase timestamp field type has the structure:
Timestamp (Timestamp(seconds=1561186800, nanoseconds=0))
hashCode:423768083
microsecondsSinceEpoch:1561186800000000
millisecondsSinceEpoch:1561186800000
nanoseconds:0
runtimeType:Type (Timestamp)
seconds:1561186800
_seconds:1561186800
_nanoseconds:0
So you can use either micro- or milliseconds:
DateTime.fromMillisecondsSinceEpoch(data['tripDoc']['docCreatedOn'].millisecondsSinceEpoch)
or
DateTime.fromMicrosecondsSinceEpoch(data['tripDoc']['docCreatedOn'].microsecondsSinceEpoch)
Upvotes: 1
Reputation: 714
add toDate() method .It will work
DateTime dateTime = documents[i].data["duedate"].toDate();
Upvotes: 27
Reputation: 5929
Ios and Android will not receive same type. Ios receive the timestamps as TimeStamp and Android receive it as DateTime already. So for fixing this issue I just created this little function. This will return a DateTime and let use format it etc.
import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart';
DateTime parseTime(dynamic date) {
return Platform.isIOS ? (date as Timestamp).toDate() : (date as DateTime);
}
Upvotes: 12
Reputation: 3222
Firestore is returning a Timestamp object, which consists of seconds and nanoseconds. Oddly, on iOS you can indeed just use a .toDate() and it works. But that breaks on Android as toDate() is not a method. So you can do a platform check if you want, but the universal solution is to use Firestore's Timestamp:
import 'package:cloud_firestore/cloud_firestore.dart';
DateTime _convertStamp(Timestamp _stamp) {
if (_stamp != null) {
return Timestamp(_stamp.seconds, _stamp.nanoseconds).toDate();
/*
if (Platform.isIOS) {
return _stamp.toDate();
} else {
return Timestamp(_stamp.seconds, _stamp.nanoseconds).toDate();
}
*/
} else {
return null;
}
}
and then pass your model to it:
SomeModel.fromJson(Map<String, dynamic> parsedJson) {
updatedAt = _convertStamp(parsedJson['updatedAt']);
}
Upvotes: 1
Reputation: 2436
You can try this..
timeago.format(DateTime.tryParse(timestamp))
like in yours it will be
timeago.format(DateTime.tryParse(document.data['tripDoc']['docCreatedOn']))
Upvotes: 0
Reputation: 61
For some funny reason, I can't use toDate() on Android. Have to use it for iOS. So I'm forced to use a platform check like this:
Theme.of(context).platform == TargetPlatform.iOS
? DateFormat('dd MMM kk:mm').format(document['timestamp'].toDate())
: DateFormat('dd MMM kk:mm').format(document['timestamp'])
Upvotes: 0
Reputation: 2036
I think this is more reliable
DateTime updateDateTime = DateTime.fromMillisecondsSinceEpoch(
map['updatedatetime'].millisecondsSinceEpoch);
Upvotes: 6
Reputation: 5987
.toDate()
worked for me. Now the modified code is -
new Text(timeago.format(document.data['tripDoc']['docCreatedOn'].toDate()))
Hope, it'll help someone.
Upvotes: 64
Reputation: 21728
var date = DateTime.fromMillisecondsSinceEpoch(timestamp)
Upvotes: 0
Reputation: 53317
DateTime.fromMillisecondsSinceEpoch(timeStamp);
DateTime.fromMicrosecondsSinceEpoch(timeStamp);
Upvotes: 2