diff --git a/android/src/main/java/io/invertase/firebase/firestore/FirestoreSerialize.java b/android/src/main/java/io/invertase/firebase/firestore/FirestoreSerialize.java index 8139e527..982189b5 100644 --- a/android/src/main/java/io/invertase/firebase/firestore/FirestoreSerialize.java +++ b/android/src/main/java/io/invertase/firebase/firestore/FirestoreSerialize.java @@ -31,8 +31,6 @@ import io.invertase.firebase.Utils; public class FirestoreSerialize { private static final String TAG = "FirestoreSerialize"; - private static final DateFormat READ_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); - private static final DateFormat WRITE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); private static final String KEY_CHANGES = "changes"; private static final String KEY_DATA = "data"; private static final String KEY_DOC_CHANGE_DOCUMENT = "document"; @@ -43,12 +41,6 @@ public class FirestoreSerialize { private static final String KEY_METADATA = "metadata"; private static final String KEY_PATH = "path"; - static { - // Javascript Date.toISOString is always formatted to UTC - // We set the read TimeZone to UTC to account for this - READ_DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC")); - } - /** * Convert a DocumentSnapshot instance into a React Native WritableMap * @@ -220,7 +212,7 @@ public class FirestoreSerialize { typeMap.putMap("value", geoPoint); } else if (value instanceof Date) { typeMap.putString("type", "date"); - typeMap.putString("value", WRITE_DATE_FORMAT.format((Date) value)); + typeMap.putDouble("value", ((Date) value).getTime()); } else { // TODO: Changed to log an error rather than crash - is this correct? Log.e(TAG, "buildTypeMap: Cannot convert object of type " + value.getClass()); @@ -275,13 +267,8 @@ public class FirestoreSerialize { ReadableMap geoPoint = typeMap.getMap("value"); return new GeoPoint(geoPoint.getDouble("latitude"), geoPoint.getDouble("longitude")); } else if ("date".equals(type)) { - try { - String date = typeMap.getString("value"); - return READ_DATE_FORMAT.parse(date); - } catch (ParseException exception) { - Log.e(TAG, "parseTypeMap", exception); - return null; - } + Double time = typeMap.getDouble("value"); + return new Date(time.longValue()); } else if ("fieldvalue".equals(type)) { String value = typeMap.getString("value"); if ("delete".equals(value)) { diff --git a/ios/RNFirebase/firestore/RNFirebaseFirestoreDocumentReference.m b/ios/RNFirebase/firestore/RNFirebaseFirestoreDocumentReference.m index caa5495f..cd04347d 100644 --- a/ios/RNFirebase/firestore/RNFirebaseFirestoreDocumentReference.m +++ b/ios/RNFirebase/firestore/RNFirebaseFirestoreDocumentReference.m @@ -205,9 +205,9 @@ static NSMutableDictionary *_listeners; typeMap[@"value"] = geopoint; } else if ([value isKindOfClass:[NSDate class]]) { typeMap[@"type"] = @"date"; - NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; - [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"]; - typeMap[@"value"] = [dateFormatter stringFromDate:(NSDate *)value]; + // NOTE: The round() is important as iOS ends up giving .999 otherwise, + // and loses a millisecond when going between native and JS + typeMap[@"value"] = @(round([(NSDate *)value timeIntervalSince1970] * 1000.0)); } else if ([value isKindOfClass:[NSNumber class]]) { NSNumber *number = (NSNumber *)value; if (number == (void*)kCFBooleanFalse || number == (void*)kCFBooleanTrue) { @@ -262,9 +262,7 @@ static NSMutableDictionary *_listeners; NSNumber *longitude = geopoint[@"longitude"]; return [[FIRGeoPoint alloc] initWithLatitude:[latitude doubleValue] longitude:[longitude doubleValue]]; } else if ([type isEqualToString:@"date"]) { - NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; - [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"]; - return [dateFormatter dateFromString:value]; + return [NSDate dateWithTimeIntervalSince1970:([(NSNumber *)value doubleValue] / 1000.0)]; } else if ([type isEqualToString:@"fieldvalue"]) { NSString *string = (NSString*)value; if ([string isEqualToString:@"delete"]) { diff --git a/lib/modules/firestore/utils/serialize.js b/lib/modules/firestore/utils/serialize.js index 3ef0b09a..5bdebf26 100644 --- a/lib/modules/firestore/utils/serialize.js +++ b/lib/modules/firestore/utils/serialize.js @@ -67,7 +67,7 @@ const buildTypeMap = (value: any): any => { }; } else if (value instanceof Date) { typeMap.type = 'date'; - typeMap.value = value.toISOString(); + typeMap.value = value.getTime(); } else { typeMap.type = 'object'; typeMap.value = buildNativeMap(value); diff --git a/tests/src/tests/firestore/documentReferenceTests.js b/tests/src/tests/firestore/documentReferenceTests.js index 968cb28b..a6aa2f65 100644 --- a/tests/src/tests/firestore/documentReferenceTests.js +++ b/tests/src/tests/firestore/documentReferenceTests.js @@ -435,6 +435,7 @@ function documentReferenceTests({ describe, it, context, firebase }) { const doc = await docRef.get(); doc.data().field.should.be.instanceof(Date); should.equal(doc.data().field.toISOString(), date.toISOString()); + should.equal(doc.data().field.getTime(), date.getTime()); }); });