Repository: googlemaps/google-maps-services-js (ts)

Issue:
timezone: INVALID_REQUEST 
Hi all, 

It seems something is wrong with googlemaps/google-maps-services-js  for the timezone API.

The below code returns  INVALID_REQUEST
Could you please take a look?

---


#### Code example nodejs

```

const gmapsClient = require("@googlemaps/google-maps-services-js").Client;
const gmaps_API_KEY = "key"; 
const gmaps = new gmapsClient({}); 

let today = new Date();
      let locat =  "30, 50";
      await gmaps
      .timezone({
        params: {
          location: locat,
          timestamp: today,
          key: gmaps_API_KEY
        },
        timeout: 1000 // milliseconds
      })
      .then(r => {
        console.log("timezone: " + JSON.stringify(r.data));
        console.log(`updateObjWithDateTime:  + rawOffset:${r.data.rawOffset} dstOffset: ${r.data.dstOffset} `);
 
      })
      .catch(e => {
        console.error(e);
      });
```


Thanks!


Pull request description:
fix: handle date objects correctly in serializer
closes #369

Patch:
diff --git a/src/directions.ts b/src/directions.ts
index 897d986ad..e83bef085 100644
--- a/src/directions.ts
+++ b/src/directions.ts
@@ -1,20 +1,21 @@
+import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
 import {
   DirectionsRoute,
   GeocodedWaypoint,
-  TrafficModel,
-  TransitRoutingPreference,
-  TravelRestriction,
-  LatLng,
   Language,
-  UnitSystem,
+  LatLng,
+  RequestParams,
+  ResponseData,
+  TrafficModel,
   TransitMode,
+  TransitRoutingPreference,
   TravelMode,
-  ResponseData,
-  RequestParams
+  TravelRestriction,
+  UnitSystem
 } from "./common";
-import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
+import { latLngToString, serializer, toTimestamp } from "./serialize";
+
 import { defaultAxiosInstance } from "./client";
-import { serializer, latLngToString } from "./serialize";
 
 export interface DirectionsRequest extends Partial<AxiosRequestConfig> {
   params: {
@@ -176,8 +177,8 @@ export const defaultParamsSerializer = serializer({
   origin: latLngToString,
   destination: latLngToString,
   waypoints: o => o.map(latLngToString),
-  arrival_time: Number,
-  departure_time: Number
+  arrival_time: toTimestamp,
+  departure_time: toTimestamp
 });
 
 export function directions(
diff --git a/src/distance.ts b/src/distance.ts
index 09c249efa..916b0b30a 100644
--- a/src/distance.ts
+++ b/src/distance.ts
@@ -1,18 +1,19 @@
+import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
 import {
   DistanceMatrixRow,
-  TrafficModel,
-  TransitRoutingPreference,
-  TravelRestriction,
   LatLng,
-  UnitSystem,
+  RequestParams,
+  ResponseData,
+  TrafficModel,
   TransitMode,
+  TransitRoutingPreference,
   TravelMode,
-  ResponseData,
-  RequestParams
+  TravelRestriction,
+  UnitSystem
 } from "./common";
-import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
+import { latLngToString, serializer, toTimestamp } from "./serialize";
+
 import { defaultAxiosInstance } from "./client";
-import { serializer, latLngToString } from "./serialize";
 
 export interface DistanceMatrixRequest extends Partial<AxiosRequestConfig> {
   params: {
@@ -155,8 +156,8 @@ export const defaultUrl =
 export const defaultParamsSerializer = serializer({
   origins: o => o.map(latLngToString),
   destinations: o => o.map(latLngToString),
-  arrival_time: Number,
-  departure_time: Number
+  arrival_time: toTimestamp,
+  departure_time: toTimestamp
 });
 
 export function distancematrix(
diff --git a/src/serialize.ts b/src/serialize.ts
index 4550c1ab4..d6d17e243 100644
--- a/src/serialize.ts
+++ b/src/serialize.ts
@@ -1,6 +1,7 @@
 import { LatLng, LatLngBounds, LatLngLiteral } from "./common";
-import { stringify as qs } from "query-string";
+
 import { encodePath } from "./util";
+import { stringify as qs } from "query-string";
 
 const separator = "|";
 
@@ -96,3 +97,10 @@ export function serializer(
     return qs(params, queryStringOptions);
   };
 }
+
+export function toTimestamp(o: number | Date) {
+  if (o instanceof Date) {
+    return Number(o) / 1000;
+  }
+  return o
+}
diff --git a/src/timezone.ts b/src/timezone.ts
index 229501bf8..521f3f3a9 100644
--- a/src/timezone.ts
+++ b/src/timezone.ts
@@ -1,7 +1,8 @@
-import { LatLng, Language, ResponseData, RequestParams } from "./common";
 import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
+import { Language, LatLng, RequestParams, ResponseData } from "./common";
+import { latLngToString, serializer, toTimestamp } from "./serialize";
+
 import { defaultAxiosInstance } from "./client";
-import { serializer, latLngToString } from "./serialize";
 
 export interface TimeZoneRequest extends Partial<AxiosRequestConfig> {
   params: {
@@ -55,7 +56,7 @@ export interface TimeZoneResponse extends AxiosResponse {
 
 export const defaultUrl = "https://maps.googleapis.com/maps/api/timezone/json";
 export const defaultParamsSerializer = serializer({
-  timestamp: Number,
+  timestamp: toTimestamp,
   location: latLngToString
 });
 export function timezone(


Test patch:
diff --git a/e2e/timezone.test.ts b/e2e/timezone.test.ts
index ec8f03d26..18f4fdeb7 100644
--- a/e2e/timezone.test.ts
+++ b/e2e/timezone.test.ts
@@ -1,9 +1,9 @@
 import { timezone } from "../src/timezone";
 
-test("elevation should call axios correctly", async () => {
+test("elevation should get an ok response", async () => {
   const params = {
-    location: { lat: 35, lng: -110 },
-    timestamp: 0,
+    location: "30, 50",
+    timestamp: new Date(),
     language: "en" as const,
     key: process.env.GOOGLE_MAPS_API_KEY
   };
diff --git a/src/serialize.test.ts b/src/serialize.test.ts
index 5809b0b9d..76d71653c 100644
--- a/src/serialize.test.ts
+++ b/src/serialize.test.ts
@@ -1,12 +1,13 @@
+import { LatLng, LatLngLiteral } from "./common";
 import {
+  latLngArrayToStringMaybeEncoded,
+  latLngBoundsToString,
   latLngToString,
-  serializer,
   objectToString,
-  latLngBoundsToString,
-  latLngArrayToStringMaybeEncoded,
-  toLatLngLiteral
+  serializer,
+  toLatLngLiteral,
+  toTimestamp
 } from "./serialize";
-import { LatLngLiteral, LatLng } from "./common";
 
 test("latLngToString is correct", () => {
   expect(latLngToString("")).toBe("");
@@ -78,3 +79,13 @@ test("toLatLngLiteral", () => {
     toLatLngLiteral({} as LatLngLiteral);
   }).toThrow(TypeError);
 });
+
+test("toTimestamp", () => {
+  expect(toTimestamp(100)).toEqual(100);
+  
+  const dt = new Date();
+  const seconds = Number(dt) / 1000
+  expect(toTimestamp(dt)).toEqual(seconds);
+
+});
+
diff --git a/src/timezone.test.ts b/src/timezone.test.ts
index c7945f284..51b1b6e17 100644
--- a/src/timezone.test.ts
+++ b/src/timezone.test.ts
@@ -1,5 +1,6 @@
+import { defaultParamsSerializer, defaultUrl, timezone } from "./timezone";
+
 import axios from "axios";
-import { timezone, defaultParamsSerializer, defaultUrl } from "./timezone";
 
 jest.mock("axios");
 
@@ -25,3 +26,8 @@ test("elevation should call axios correctly", () => {
     url: defaultUrl
   });
 });
+
+test("serializer should handle date object", () => {
+  const dt = new Date();
+  expect(defaultParamsSerializer({timestamp: dt})).toEqual(`timestamp=${Number(dt)/1000}`)
+});