Skip to content

Commit 6db185b

Browse files
author
Brian Chen
authored
remove floating point rounding error in Timestamp.fromMillis() (#4745)
1 parent 7354a0e commit 6db185b

File tree

3 files changed

+16
-2
lines changed

3 files changed

+16
-2
lines changed

.changeset/rich-olives-tease.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@firebase/firestore': patch
3+
---
4+
5+
Fixed a bug where decimal inputs to `Timestamp.fromMillis()` calculated incorrectly due to floating point precision loss

packages/firestore/src/lite/timestamp.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ import { primitiveComparator } from '../util/misc';
2121
// The earliest date supported by Firestore timestamps (0001-01-01T00:00:00Z).
2222
const MIN_SECONDS = -62135596800;
2323

24+
// Number of nanoseconds in a millisecond.
25+
const MS_TO_NANOS = 1e6;
26+
2427
/**
2528
* A `Timestamp` represents a point in time independent of any time zone or
2629
* calendar, represented as seconds and fractions of seconds at nanosecond
@@ -66,7 +69,7 @@ export class Timestamp {
6669
*/
6770
static fromMillis(milliseconds: number): Timestamp {
6871
const seconds = Math.floor(milliseconds / 1000);
69-
const nanos = (milliseconds - seconds * 1000) * 1e6;
72+
const nanos = Math.floor((milliseconds - seconds * 1000) * MS_TO_NANOS);
7073
return new Timestamp(seconds, nanos);
7174
}
7275

@@ -138,7 +141,7 @@ export class Timestamp {
138141
* the number of milliseconds since Unix epoch 1970-01-01T00:00:00Z.
139142
*/
140143
toMillis(): number {
141-
return this.seconds * 1000 + this.nanoseconds / 1e6;
144+
return this.seconds * 1000 + this.nanoseconds / MS_TO_NANOS;
142145
}
143146

144147
_compareTo(other: Timestamp): number {

packages/firestore/test/unit/api/timestamp.test.ts

+6
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,12 @@ describe('Timestamp', () => {
134134
expect(t1 >= t2).to.be.false;
135135
});
136136

137+
it('handles decimal inputs in fromMillis()', () => {
138+
const actual = Timestamp.fromMillis(1000.1);
139+
const expected = new Timestamp(1, 100000);
140+
expect(actual.isEqual(expected)).to.be.true;
141+
});
142+
137143
it('serializes to JSON', () => {
138144
expect(new Timestamp(123, 456).toJSON()).to.deep.equal({
139145
seconds: 123,

0 commit comments

Comments
 (0)