Skip to content

Commit caad4e0

Browse files
committed
Serialize Timestamps as string (per proto3 JSON format).
1 parent 8c2bbc3 commit caad4e0

File tree

2 files changed

+48
-5
lines changed

2 files changed

+48
-5
lines changed

packages/firestore/src/remote/serializer.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,11 +207,24 @@ export class JsonProtoSerializer {
207207
* to actually return a Timestamp proto.
208208
*/
209209
private toTimestamp(timestamp: Timestamp): string {
210-
return {
211-
seconds: '' + timestamp.seconds,
212-
nanos: timestamp.nanoseconds
213-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
214-
} as any;
210+
if (this.options.useProto3Json) {
211+
// Serialize to ISO-8601 date format, but with full nano resolution.
212+
// Since JS Date has only millis, let's only use it for the seconds and
213+
// then manually add the fractions to the end.
214+
const jsDateStr = new Date(timestamp.seconds * 1000).toISOString();
215+
// Remove .xxx frac part and Z in the end.
216+
const strUntilSeconds = jsDateStr.replace(/\.\d*/, '').replace('Z', '');
217+
// Pad the fraction out to 9 digits (nanos).
218+
const nanoStr = ('000000000' + timestamp.nanoseconds).slice(-9);
219+
220+
return `${strUntilSeconds}.${nanoStr}Z`;
221+
} else {
222+
return {
223+
seconds: '' + timestamp.seconds,
224+
nanos: timestamp.nanoseconds
225+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
226+
} as any;
227+
}
215228
}
216229

217230
private fromTimestamp(date: string | TimestampProto): Timestamp {

packages/firestore/test/unit/remote/node/serializer.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,36 @@ describe('Serializer', () => {
300300
);
301301
});
302302

303+
it('converts TimestampValue to string (useProto3Json=true)', () => {
304+
expect(
305+
proto3JsonSerializer.toValue(
306+
new fieldValue.TimestampValue(new Timestamp(1488872578, 916123456)))
307+
).to.deep.equal(
308+
{ timestampValue: '2017-03-07T07:42:58.916123456Z' }
309+
);
310+
311+
expect(
312+
proto3JsonSerializer.toValue(
313+
new fieldValue.TimestampValue(new Timestamp(1488872578, 916123000)))
314+
).to.deep.equal(
315+
{ timestampValue: '2017-03-07T07:42:58.916123000Z' }
316+
);
317+
318+
expect(
319+
proto3JsonSerializer.toValue(
320+
new fieldValue.TimestampValue(new Timestamp(1488872578, 916000000)))
321+
).to.deep.equal(
322+
{ timestampValue: '2017-03-07T07:42:58.916000000Z' }
323+
);
324+
325+
expect(
326+
proto3JsonSerializer.toValue(
327+
new fieldValue.TimestampValue(new Timestamp(1488872578, 0)))
328+
).to.deep.equal(
329+
{ timestampValue: '2017-03-07T07:42:58.000000000Z' }
330+
);
331+
});
332+
303333
it('converts GeoPointValue', () => {
304334
const example = new GeoPoint(1.23, 4.56);
305335
const expected = {

0 commit comments

Comments
 (0)