From 909c0f18725d895c9e2c1f524d25057250d7378e Mon Sep 17 00:00:00 2001
From: Seth Pollack <seth@pollackphoto.com>
Date: Tue, 23 Feb 2016 17:02:08 -0800
Subject: [PATCH] add option to parse input Dates as UTC

---
 lib/defaults.js          |  6 ++++--
 lib/utils.js             | 33 ++++++++++++++++++++++++++-------
 test/unit/utils-tests.js | 11 +++++++++++
 3 files changed, 41 insertions(+), 9 deletions(-)

diff --git a/lib/defaults.js b/lib/defaults.js
index d3cb911a4..3b37e3676 100644
--- a/lib/defaults.js
+++ b/lib/defaults.js
@@ -40,8 +40,10 @@ var defaults = module.exports = {
 
   ssl: false,
 
-  application_name : undefined,
-  fallback_application_name: undefined
+  application_name: undefined,
+  fallback_application_name: undefined,
+
+  parseInputDatesAsUTC: false
 };
 
 //parse int8 so you can get your count values as actual numbers
diff --git a/lib/utils.js b/lib/utils.js
index d102d6352..ff6b226f0 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -1,3 +1,4 @@
+var defaults = require('./defaults');
 
 // convert a JS array to a postgres array literal
 // uses comma separator so won't work for types like box that use
@@ -32,7 +33,11 @@ var prepareValue = function(val, seen) {
     return val;
   }
   if(val instanceof Date) {
-    return dateToString(val);
+    if(defaults.parseInputDatesAsUTC) {
+      return dateToStringUTC(val);
+    } else {
+      return dateToString(val);
+    }
   }
   if(Array.isArray(val)) {
     return arrayString(val);
@@ -59,13 +64,14 @@ function prepareObject(val, seen) {
   return JSON.stringify(val);
 }
 
+function pad(number, digits) {
+  number = ""  +number;
+  while(number.length < digits)
+    number = "0" + number;
+  return number;
+}
+
 function dateToString(date) {
-  function pad(number, digits) {
-    number = ""+number;
-    while(number.length < digits)
-      number = "0"+number;
-    return number;
-  }
 
   var offset = -date.getTimezoneOffset();
   var ret = pad(date.getFullYear(), 4) + '-' +
@@ -86,6 +92,19 @@ function dateToString(date) {
   return ret + pad(Math.floor(offset/60), 2) + ":" + pad(offset%60, 2);
 }
 
+function dateToStringUTC(date) {
+  
+  var ret = pad(date.getUTCFullYear(), 4) + '-' +
+      pad(date.getUTCMonth() + 1, 2) + '-' +
+      pad(date.getUTCDate(), 2) + 'T' +
+      pad(date.getUTCHours(), 2) + ':' +
+      pad(date.getUTCMinutes(), 2) + ':' +
+      pad(date.getUTCSeconds(), 2) + '.' +
+      pad(date.getUTCMilliseconds(), 3);
+  
+  return ret + "+00:00";
+}
+
 function normalizeQueryConfig (config, values, callback) {
   //can take in strings or config objects
   config = (typeof(config) == 'string') ? { text: config } : config;
diff --git a/test/unit/utils-tests.js b/test/unit/utils-tests.js
index b0e3e91fd..d640f9880 100644
--- a/test/unit/utils-tests.js
+++ b/test/unit/utils-tests.js
@@ -65,6 +65,17 @@ test('prepareValues: date prepared properly', function() {
   helper.resetTimezoneOffset();
 });
 
+test('prepareValues: date prepared properly as UTC', function() {
+  defaults.parseInputDatesAsUTC = true;
+
+  // make a date in the local timezone that represents a specific UTC point in time
+  var date = new Date(Date.UTC(2014, 1, 1, 11, 11, 1, 7));
+  var out = utils.prepareValue(date);
+  assert.strictEqual(out, "2014-02-01T11:11:01.007+00:00");
+
+  defaults.parseInputDatesAsUTC = false;
+});
+
 test('prepareValues: undefined prepared properly', function() {
   var out = utils.prepareValue(void 0);
   assert.strictEqual(out, null);