diff --git a/benchmarks/noaa.ts b/benchmarks/noaa.ts index 4b12bbe..957fdcf 100644 --- a/benchmarks/noaa.ts +++ b/benchmarks/noaa.ts @@ -76,7 +76,7 @@ for (const id of stations) { end, }) .extremes.map((e) => ({ - time: e.time.getTime(), + time: e.time.epochMilliseconds, level: e.level, type: e.high ? "H" : "L", })); diff --git a/examples/temporal-example.ts b/examples/temporal-example.ts new file mode 100644 index 0000000..b78219f --- /dev/null +++ b/examples/temporal-example.ts @@ -0,0 +1,62 @@ +#!/usr/bin/env node +/** + * Example demonstrating Temporal.Instant support in Neaps + * Run with: node examples/temporal-example.mjs + */ + +import { Temporal } from "@js-temporal/polyfill"; +import { getExtremesPrediction } from "neaps"; + +// Example 1: Using JavaScript Date (backward compatible) +console.log("=== Using JavaScript Date ==="); +const predictionWithDate = getExtremesPrediction({ + lat: 26.772, + lon: -80.05, + start: new Date("2025-12-18T00:00:00Z"), + end: new Date("2025-12-19T00:00:00Z"), + datum: "MLLW", +}); + +console.log("Extremes found:", predictionWithDate.extremes.length); +console.log("First extreme:", { + time: predictionWithDate.extremes[0].time.toString(), + level: predictionWithDate.extremes[0].level.toFixed(2), + type: predictionWithDate.extremes[0].high ? "High" : "Low", +}); + +// Example 2: Using Temporal.Instant (native Temporal support) +console.log("\n=== Using Temporal.Instant ==="); +const startInstant = Temporal.Instant.from("2025-12-18T00:00:00Z"); +const endInstant = Temporal.Instant.from("2025-12-19T00:00:00Z"); + +const predictionWithTemporal = getExtremesPrediction({ + lat: 26.772, + lon: -80.05, + start: startInstant, + end: endInstant, + datum: "MLLW", +}); + +console.log("Extremes found:", predictionWithTemporal.extremes.length); +console.log("First extreme:", { + time: predictionWithTemporal.extremes[0].time.toString(), + level: predictionWithTemporal.extremes[0].level.toFixed(2), + type: predictionWithTemporal.extremes[0].high ? "High" : "Low", +}); + +// Example 3: Converting returned Temporal.Instant to Date +console.log("\n=== Converting Temporal.Instant back to Date ==="); +const instant = predictionWithTemporal.extremes[0].time; +const date = new Date(instant.epochMilliseconds); +console.log("As Date object:", date.toISOString()); +console.log("As Date string:", date.toString()); + +// Example 4: Using Temporal for manipulation +console.log("\n=== Temporal API benefits ==="); +const timeOfExtreme = predictionWithTemporal.extremes[0].time; +const oneHourLater = timeOfExtreme.add({ hours: 1 }); +const oneHourEarlier = timeOfExtreme.subtract({ hours: 1 }); + +console.log("One hour earlier:", oneHourEarlier.toString()); +console.log("Extreme time:", timeOfExtreme.toString()); +console.log("One hour later:", oneHourLater.toString()); diff --git a/package.json b/package.json index bb6dfc6..a568f81 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ }, "devDependencies": { "@eslint/js": "^9.39.2", + "@neaps/tide-database": "*", "@types/make-fetch-happen": "^10.0.4", "@types/node": "^25.0.2", "@vitest/coverage-v8": "^4.0.15", diff --git a/packages/neaps/package.json b/packages/neaps/package.json index 9ef2768..acbb3cf 100644 --- a/packages/neaps/package.json +++ b/packages/neaps/package.json @@ -34,6 +34,7 @@ "prepack": "npm run build" }, "dependencies": { + "@js-temporal/polyfill": "^0.5", "@neaps/tide-database": "0.3", "@neaps/tide-predictor": "^0.4.0", "geolib": "^3.3.4" diff --git a/packages/neaps/src/index.ts b/packages/neaps/src/index.ts index 6d4a0a5..bcab2af 100644 --- a/packages/neaps/src/index.ts +++ b/packages/neaps/src/index.ts @@ -1,6 +1,12 @@ +import { Temporal } from "@js-temporal/polyfill"; import { getDistance } from "geolib"; import { stations, type Station } from "@neaps/tide-database"; -import tidePredictor, { type TimeSpan, type ExtremesInput } from "@neaps/tide-predictor"; +import tidePredictor, { + type TimeSpan, + type ExtremesInput, + Extreme, + TimelinePoint, +} from "@neaps/tide-predictor"; import type { GeolibInputCoordinates } from "geolib/es/types"; type Units = "meters" | "feet"; @@ -14,7 +20,7 @@ type PredictionOptions = { export type ExtremesOptions = ExtremesInput & PredictionOptions; export type TimelineOptions = TimeSpan & PredictionOptions; -export type WaterLevelOptions = { time: Date } & PredictionOptions; +export type WaterLevelOptions = { time: Date | Temporal.Instant } & PredictionOptions; const feetPerMeter = 3.2808399; const defaultUnits: Units = "meters"; @@ -89,7 +95,32 @@ export function findStation(query: string) { return useStation(found); } -export function useStation(station: Station, distance?: number) { +export type StationPrediction = { + datum: string | undefined; + units: Units; + station: Station; + distance?: number; +}; + +export type StationExtremesPrediction = StationPrediction & { + extremes: Extreme[]; +}; + +export type StationTimelinePrediction = StationPrediction & { + timeline: TimelinePoint[]; +}; + +export type StationWaterLevelPrediction = StationPrediction & TimelinePoint; + +export type StationPredictor = Station & { + distance?: number; + defaultDatum?: string; + getExtremesPrediction: (options: ExtremesOptions) => StationExtremesPrediction; + getTimelinePrediction: (options: TimelineOptions) => StationTimelinePrediction; + getWaterLevelAtTime: (options: WaterLevelOptions) => StationWaterLevelPrediction; +}; + +export function useStation(station: Station, distance?: number): StationPredictor { // If subordinate station, use the reference station for datums and constituents let reference = station; if (station.type === "subordinate") { diff --git a/packages/neaps/test/index.test.ts b/packages/neaps/test/index.test.ts index 9668593..2c88ed7 100644 --- a/packages/neaps/test/index.test.ts +++ b/packages/neaps/test/index.test.ts @@ -43,7 +43,7 @@ describe("timezone independence", () => { expect(result.length).toBe(baseline.length); result.forEach((extreme, index) => { const base = baseline[index]; - expect(extreme.time.valueOf()).toBe(base.time.valueOf()); + expect(extreme.time.epochMilliseconds).toBe(base.time.epochMilliseconds); expect(extreme.high).toBe(base.high); expect(extreme.low).toBe(base.low); expect(extreme.label).toBe(base.label); @@ -71,7 +71,9 @@ describe("getExtremesPrediction", () => { const { extremes } = prediction; expect(extremes.length).toBe(4); - expect(extremes[0].time).toEqual(new Date("2025-12-18T05:30:00.000Z")); + expect(extremes[0].time.epochMilliseconds).toEqual( + new Date("2025-12-18T05:30:00.000Z").getTime(), + ); expect(extremes[0].level).toBeCloseTo(0.02, 2); expect(extremes[0].high).toBe(false); expect(extremes[0].low).toBe(true); @@ -126,7 +128,9 @@ describe("getWaterLevelAtTime", () => { expect(prediction.station.id).toEqual("noaa/8722588"); expect(prediction.datum).toBe("MSL"); - expect(prediction.time).toEqual(new Date("2025-12-19T05:30:00.000Z")); + expect(prediction.time.epochMilliseconds).toEqual( + new Date("2025-12-19T05:30:00.000Z").getTime(), + ); expect(typeof prediction.level).toBe("number"); }); @@ -173,7 +177,9 @@ describe("for a specific station", () => { }); expect(predictions.length).toBe(4); - expect(predictions[0].time).toEqual(new Date("2025-12-17T11:23:00.000Z")); + expect(predictions[0].time.epochMilliseconds).toEqual( + new Date("2025-12-17T11:23:00.000Z").getTime(), + ); expect(predictions[0].level).toBeCloseTo(0.9, 1); expect(predictions[0].high).toBe(true); expect(predictions[0].low).toBe(false); @@ -221,7 +227,10 @@ describe("for a specific station", () => { noaa.forEach((expected, index) => { const actual = prediction.extremes[index]; - expect(actual.time).toBeWithin(new Date(expected.t).valueOf(), 5 * 60 * 1000 /* min */); + expect(actual.time.epochMilliseconds).toBeWithin( + new Date(expected.t).getTime(), + 5 * 60 * 1000 /* min */, + ); expect(actual.level).toBeWithin(expected.v, 0.04 /* m */); }); }); @@ -265,7 +274,7 @@ describe("for a specific station", () => { const prediction = station.getWaterLevelAtTime({ time: new Date("2025-12-19T00:30:00Z"), }); - expect(prediction.time).toEqual(new Date("2025-12-19T00:30:00Z")); + expect(prediction.time.epochMilliseconds).toEqual(new Date("2025-12-19T00:30:00Z").getTime()); expect(prediction.datum).toBe("MLLW"); expect(typeof prediction.level).toBe("number"); }); diff --git a/packages/tide-predictor/package.json b/packages/tide-predictor/package.json index 8764fa8..7ee2c98 100644 --- a/packages/tide-predictor/package.json +++ b/packages/tide-predictor/package.json @@ -21,9 +21,11 @@ "files": [ "dist" ], - "devDependencies": {}, "scripts": { "build": "tsdown", "prepack": "npm run build" + }, + "dependencies": { + "@js-temporal/polyfill": "^0.5" } } diff --git a/packages/tide-predictor/src/astronomy/index.ts b/packages/tide-predictor/src/astronomy/index.ts index 63e5740..6cb6053 100644 --- a/packages/tide-predictor/src/astronomy/index.ts +++ b/packages/tide-predictor/src/astronomy/index.ts @@ -1,3 +1,4 @@ +import { Temporal } from "@js-temporal/polyfill"; import { d2r, r2d } from "./constants.js"; import coefficients from "./coefficients.js"; @@ -24,6 +25,14 @@ export interface AstroData { P: AstroValue; } +// Convert Date or Temporal.Instant to Temporal.Instant +const toInstant = (time: Date | Temporal.Instant): Temporal.Instant => { + if (time instanceof Temporal.Instant) { + return time; + } + return Temporal.Instant.fromEpochMilliseconds(time.getTime()); +}; + // Evaluates a polynomial at argument const polynomial = (coefficients: number[], argument: number): number => { const result: number[] = []; @@ -43,20 +52,24 @@ const derivativePolynomial = (coefficients: number[], argument: number): number }; // Meeus formula 11.1 -const T = (t: Date): number => { +const T = (t: Date | Temporal.Instant): number => { return (JD(t) - 2451545.0) / 36525; }; // Meeus formula 7.1 -const JD = (t: Date): number => { - let Y = t.getUTCFullYear(); - let M = t.getUTCMonth() + 1; +const JD = (t: Date | Temporal.Instant): number => { + const instant = toInstant(t); + // Extract UTC components directly from epoch milliseconds to avoid expensive ZonedDateTime conversion + const ms = Number(instant.epochMilliseconds); + const date = new Date(ms); + let Y = date.getUTCFullYear(); + let M = date.getUTCMonth() + 1; const D = - t.getUTCDate() + - t.getUTCHours() / 24.0 + - t.getUTCMinutes() / (24.0 * 60.0) + - t.getUTCSeconds() / (24.0 * 60.0 * 60.0) + - t.getUTCMilliseconds() / (24.0 * 60.0 * 60.0 * 1e6); + date.getUTCDate() + + date.getUTCHours() / 24.0 + + date.getUTCMinutes() / (24.0 * 60.0) + + date.getUTCSeconds() / (24.0 * 60.0 * 60.0) + + date.getUTCMilliseconds() / (24.0 * 60.0 * 60.0 * 1e6); if (M <= 2) { Y = Y - 1; M = M + 12; @@ -122,7 +135,8 @@ const modulus = (a: number, b: number): number => { return ((a % b) + b) % b; }; -const astro = (time: Date): AstroData => { +const astro = (time: Date | Temporal.Instant): AstroData => { + const instant = toInstant(time); // This gets cast to `AstroData` later, but we build it up step by step here // eslint-disable-next-line @typescript-eslint/no-explicit-any const result: any = {}; @@ -143,8 +157,8 @@ const astro = (time: Date): AstroData => { const dTdHour = 1 / (24 * 365.25 * 100); for (const name in polynomials) { result[name] = { - value: modulus(polynomial(polynomials[name], T(time)), 360.0), - speed: derivativePolynomial(polynomials[name], T(time)) * dTdHour, + value: modulus(polynomial(polynomials[name], T(instant)), 360.0), + speed: derivativePolynomial(polynomials[name], T(instant)) * dTdHour, }; } @@ -170,7 +184,7 @@ const astro = (time: Date): AstroData => { // set for equilibrium arguments #is given by T+h-s, s, h, p, N, pp, 90. // This is in line with convention. const hour = { - value: (JD(time) - Math.floor(JD(time))) * 360.0, + value: (JD(instant) - Math.floor(JD(instant))) * 360.0, speed: 15.0, }; @@ -191,4 +205,4 @@ const astro = (time: Date): AstroData => { }; export default astro; -export { polynomial, derivativePolynomial, T, JD, _I, _xi, _nu, _nup, _nupp }; +export { toInstant, polynomial, derivativePolynomial, T, JD, _I, _xi, _nu, _nup, _nupp }; diff --git a/packages/tide-predictor/src/harmonics/index.ts b/packages/tide-predictor/src/harmonics/index.ts index 6e75509..0aa37bb 100644 --- a/packages/tide-predictor/src/harmonics/index.ts +++ b/packages/tide-predictor/src/harmonics/index.ts @@ -1,3 +1,4 @@ +import { Temporal } from "@js-temporal/polyfill"; import prediction from "./prediction.js"; import constituentModels from "../constituents/index.js"; import { d2r } from "../astronomy/constants.js"; @@ -15,28 +16,34 @@ export interface PredictionOptions { } export interface Harmonics { - setTimeSpan: (startTime: Date | number, endTime: Date | number) => Harmonics; + setTimeSpan: ( + startTime: Date | Temporal.Instant | number, + endTime: Date | Temporal.Instant | number, + ) => Harmonics; prediction: (options?: PredictionOptions) => Prediction; } -const getDate = (time: Date | number): Date => { - if (time instanceof Date) { +const getInstant = (time: Date | Temporal.Instant | number): Temporal.Instant => { + if (time instanceof Temporal.Instant) { return time; } + if (time instanceof Date) { + return Temporal.Instant.fromEpochMilliseconds(time.getTime()); + } if (typeof time === "number") { - return new Date(time * 1000); + return Temporal.Instant.fromEpochMilliseconds(time * 1000); } - throw new Error("Invalid date format, should be a Date object, or timestamp"); + throw new Error("Invalid date format, should be a Date, Temporal.Instant, or timestamp"); }; -const getTimeline = (start: Date, end: Date, seconds: number = 10 * 60) => { - const items: Date[] = []; - const endTime = end.getTime() / 1000; - let lastTime = start.getTime() / 1000; +const getTimeline = (start: Temporal.Instant, end: Temporal.Instant, seconds: number = 10 * 60) => { + const items: Temporal.Instant[] = []; + const endEpochSeconds = end.epochMilliseconds / 1000; + let lastTime = start.epochMilliseconds / 1000; const startTime = lastTime; const hours: number[] = []; - while (lastTime <= endTime) { - items.push(new Date(lastTime * 1000)); + while (lastTime <= endEpochSeconds) { + items.push(Temporal.Instant.fromEpochMilliseconds(lastTime * 1000)); hours.push((lastTime - startTime) / (60 * 60)); lastTime += seconds; } @@ -72,15 +79,18 @@ const harmonicsFactory = ({ harmonicConstituents, offset }: HarmonicsOptions): H }); } - let start = new Date(); - let end = new Date(); + let start = Temporal.Now.instant(); + let end = Temporal.Now.instant(); const harmonics: Harmonics = {} as Harmonics; - harmonics.setTimeSpan = (startTime: Date | number, endTime: Date | number): Harmonics => { - start = getDate(startTime); - end = getDate(endTime); - if (start.getTime() >= end.getTime()) { + harmonics.setTimeSpan = ( + startTime: Date | Temporal.Instant | number, + endTime: Date | Temporal.Instant | number, + ): Harmonics => { + start = getInstant(startTime); + end = getInstant(endTime); + if (Temporal.Instant.compare(start, end) >= 0) { throw new Error("Start time must be before end time"); } return harmonics; @@ -99,4 +109,4 @@ const harmonicsFactory = ({ harmonicConstituents, offset }: HarmonicsOptions): H }; export default harmonicsFactory; -export { getDate, getTimeline }; +export { getInstant, getTimeline }; diff --git a/packages/tide-predictor/src/harmonics/prediction.ts b/packages/tide-predictor/src/harmonics/prediction.ts index e3bf407..9386741 100644 --- a/packages/tide-predictor/src/harmonics/prediction.ts +++ b/packages/tide-predictor/src/harmonics/prediction.ts @@ -1,9 +1,10 @@ +import { Temporal } from "@js-temporal/polyfill"; import astro from "../astronomy/index.js"; import { d2r } from "../astronomy/constants.js"; import constituentModels from "../constituents/index.js"; export interface Timeline { - items: Date[]; + items: Temporal.Instant[]; hours: number[]; } @@ -16,13 +17,13 @@ export interface HarmonicConstituent { } export interface TimelinePoint { - time: Date; + time: Temporal.Instant; hour: number; level: number; } export interface Extreme { - time: Date; + time: Temporal.Instant; level: number; high: boolean; low: boolean; @@ -80,10 +81,10 @@ const addExtremesOffsets = (extreme: Extreme, offsets?: ExtremeOffsets): Extreme } } if (extreme.high && offsets.time?.high) { - extreme.time = new Date(extreme.time.getTime() + offsets.time.high * 60 * 1000); + extreme.time = extreme.time.add({ milliseconds: offsets.time.high * 60 * 1000 }); } if (extreme.low && offsets.time?.low) { - extreme.time = new Date(extreme.time.getTime() + offsets.time.low * 60 * 1000); + extreme.time = extreme.time.add({ milliseconds: offsets.time.low * 60 * 1000 }); } return extreme; }; @@ -102,7 +103,7 @@ const getExtremeLabel = (label: "high" | "low", highLowLabels?: ExtremeLabels): interface PredictionFactoryParams { timeline: Timeline; constituents: HarmonicConstituent[]; - start: Date; + start: Temporal.Instant; } const predictionFactory = ({ @@ -142,6 +143,7 @@ const predictionFactory = ({ const { labels, offsets } = typeof options !== "undefined" ? options : {}; const results: Extreme[] = []; const { baseSpeed, u, f, baseValue } = prepare(); + let goingUp = false; let goingDown = false; let lastLevel = getLevel(0, baseSpeed, u[0], f[0], baseValue); diff --git a/packages/tide-predictor/src/index.ts b/packages/tide-predictor/src/index.ts index 944c961..9fb6b76 100644 --- a/packages/tide-predictor/src/index.ts +++ b/packages/tide-predictor/src/index.ts @@ -1,3 +1,4 @@ +import { Temporal } from "@js-temporal/polyfill"; import harmonics from "./harmonics/index.js"; import { default as constituents } from "./constituents/index.js"; import type { HarmonicConstituent } from "./harmonics/index.js"; @@ -8,8 +9,8 @@ export interface TidePredictionOptions { } export interface TimeSpan { - start: Date; - end: Date; + start: Date | Temporal.Instant; + end: Date | Temporal.Instant; timeFidelity?: number; } @@ -24,7 +25,7 @@ export interface ExtremesInput extends TimeSpan { export interface TidePrediction { getTimelinePrediction: (params: TimeSpan) => TimelinePoint[]; getExtremesPrediction: (params: ExtremesInput) => Extreme[]; - getWaterLevelAtTime: (params: { time: Date }) => TimelinePoint; + getWaterLevelAtTime: (params: { time: Date | Temporal.Instant }) => TimelinePoint; } const tidePredictionFactory = ( @@ -58,10 +59,14 @@ const tidePredictionFactory = ( .getExtremesPrediction({ labels, offsets }); }, - getWaterLevelAtTime: ({ time }: { time: Date }): TimelinePoint => { - const endDate = new Date(time.getTime() + 10 * 60 * 1000); + getWaterLevelAtTime: ({ time }: { time: Date | Temporal.Instant }): TimelinePoint => { + const instant = + time instanceof Temporal.Instant + ? time + : Temporal.Instant.fromEpochMilliseconds(time.getTime()); + const endInstant = instant.add({ minutes: 10 }); return harmonics(harmonicsOptions) - .setTimeSpan(time, endDate) + .setTimeSpan(instant, endInstant) .prediction() .getTimelinePrediction()[0]; }, diff --git a/packages/tide-predictor/test/harmonics/index.test.ts b/packages/tide-predictor/test/harmonics/index.test.ts index a2979e0..d0a5cc3 100644 --- a/packages/tide-predictor/test/harmonics/index.test.ts +++ b/packages/tide-predictor/test/harmonics/index.test.ts @@ -1,9 +1,10 @@ +import { Temporal } from "@js-temporal/polyfill"; import { describe, it, expect } from "vitest"; -import harmonics, { getDate, getTimeline } from "../../src/harmonics/index.js"; +import harmonics, { getInstant, getTimeline } from "../../src/harmonics/index.js"; import mockHarmonicConstituents from "../_mocks/constituents.js"; -const startDate = new Date(1567346400 * 1000); // 2019-09-01 -const endDate = new Date(1569966078 * 1000); // 2019-10-01 +const startDate = Temporal.Instant.fromEpochMilliseconds(1567346400 * 1000); // 2019-09-01 +const endDate = Temporal.Instant.fromEpochMilliseconds(1569966078 * 1000); // 2019-10-01 describe("harmonics", () => { it("it checks constituents", () => { @@ -55,7 +56,7 @@ describe("harmonics", () => { expect(() => { // @ts-expect-error: Testing invalid input testHarmonics.setTimeSpan("lkjsdlf", "sdfklj"); - }).toThrow("Invalid date format, should be a Date object, or timestamp"); + }).toThrow("Invalid date format, should be a Date, Temporal.Instant, or timestamp"); expect(() => { testHarmonics.setTimeSpan(startDate, startDate); @@ -67,17 +68,16 @@ describe("harmonics", () => { }); it("it parses dates correctly", () => { - const parsedDate = getDate(startDate); - expect(parsedDate.getTime()).toBe(startDate.getTime()); + const parsedDate = getInstant(startDate); + expect(parsedDate.epochMilliseconds).toBe(startDate.epochMilliseconds); - const parsedUnixDate = getDate(startDate.getTime() / 1000); - expect(parsedUnixDate.getTime()).toBe(startDate.getTime()); + const parsedUnixDate = getInstant(startDate.epochMilliseconds / 1000); + expect(parsedUnixDate.epochMilliseconds).toBe(startDate.epochMilliseconds); }); it("it creates timeline correctly", () => { const seconds = 20 * 60; - const difference = - Math.round((endDate.getTime() / 1000 - startDate.getTime() / 1000) / seconds) + 1; + const difference = Math.round(endDate.since(startDate).total("seconds") / seconds) + 1; const { items, hours } = getTimeline(startDate, endDate, seconds); expect(items.length).toBe(difference); expect(hours.length).toBe(difference); diff --git a/packages/tide-predictor/test/harmonics/prediction.test.ts b/packages/tide-predictor/test/harmonics/prediction.test.ts index ece82f6..ebcdc30 100644 --- a/packages/tide-predictor/test/harmonics/prediction.test.ts +++ b/packages/tide-predictor/test/harmonics/prediction.test.ts @@ -97,8 +97,8 @@ describe("Secondary stations", () => { regularResults[index].level * offsets.height!.low!, 4, ); - expect(offsetResult.time.getTime()).toBe( - regularResults[index].time.getTime() + offsets.time!.low! * 60 * 1000, + expect(offsetResult.time.epochMilliseconds).toBe( + regularResults[index].time.epochMilliseconds + offsets.time!.low! * 60 * 1000, ); } if (offsetResult.high) { @@ -107,8 +107,8 @@ describe("Secondary stations", () => { 4, ); - expect(offsetResult.time.getTime()).toBe( - regularResults[index].time.getTime() + offsets.time!.high! * 60 * 1000, + expect(offsetResult.time.epochMilliseconds).toBe( + regularResults[index].time.epochMilliseconds + offsets.time!.high! * 60 * 1000, ); } }); @@ -140,8 +140,8 @@ describe("Secondary stations", () => { regularResults[index].level + offsets.height!.low!, 4, ); - expect(offsetResult.time.getTime()).toBe( - regularResults[index].time.getTime() + offsets.time!.low! * 60 * 1000, + expect(offsetResult.time.epochMilliseconds).toBe( + regularResults[index].time.epochMilliseconds + offsets.time!.low! * 60 * 1000, ); } if (offsetResult.high) { @@ -150,8 +150,8 @@ describe("Secondary stations", () => { 4, ); - expect(offsetResult.time.getTime()).toBe( - regularResults[index].time.getTime() + offsets.time!.high! * 60 * 1000, + expect(offsetResult.time.epochMilliseconds).toBe( + regularResults[index].time.epochMilliseconds + offsets.time!.high! * 60 * 1000, ); } });