diff --git a/lib/mysql.js b/lib/mysql.js index 1b56900..fd01fc1 100644 --- a/lib/mysql.js +++ b/lib/mysql.js @@ -152,6 +152,13 @@ function generateOptions(settings) { options[p] = s[p]; } } + // Legacy UTC Date Processing fallback - SHOULD BE TRANSITIONAL + if (s.legacyUtcDateProcessing === undefined) { + s.legacyUtcDateProcessing = true; + } + if (s.legacyUtcDateProcessing) { + options.timezone = 'Z'; + } } return options; } @@ -307,19 +314,6 @@ MySQL.prototype.updateOrCreate = function(model, data, options, cb) { this._modifyOrCreate(model, data, options, fields, cb); }; -function dateToMysql(val) { - return val.getUTCFullYear() + '-' + - fillZeros(val.getUTCMonth() + 1) + '-' + - fillZeros(val.getUTCDate()) + ' ' + - fillZeros(val.getUTCHours()) + ':' + - fillZeros(val.getUTCMinutes()) + ':' + - fillZeros(val.getUTCSeconds()); - - function fillZeros(v) { - return v < 10 ? '0' + v : v; - } -} - MySQL.prototype.getInsertedId = function(model, info) { var insertedId = info && typeof info.insertId === 'number' ? info.insertId : undefined; @@ -356,7 +350,10 @@ MySQL.prototype.toColumnValue = function(prop, val) { if (!val.toUTCString) { val = new Date(val); } - return dateToMysql(val); + return val; + } + if (prop.type.name === 'DateString') { + return val.when; } if (prop.type === Boolean) { return !!val; @@ -411,14 +408,12 @@ MySQL.prototype.fromColumnValue = function(prop, val) { val = String(val); break; case 'Date': - + case 'DateString': // MySQL allows, unless NO_ZERO_DATE is set, dummy date/time entries // new Date() will return Invalid Date for those, so we need to handle // those separate. - if (val == '0000-00-00 00:00:00') { + if (!val || val == '0000-00-00 00:00:00' || val == '0000-00-00') { val = null; - } else { - val = new Date(val.toString().replace(/GMT.*$/, 'GMT')); } break; case 'Boolean': diff --git a/test/datetime.test.js b/test/datetime.test.js new file mode 100644 index 0000000..1924b6f --- /dev/null +++ b/test/datetime.test.js @@ -0,0 +1,95 @@ +// Copyright IBM Corp. 2012,2017. All Rights Reserved. +// Node module: loopback-connector-mysql +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +'use strict'; + +var DateString = require('../node_modules/loopback-datasource-juggler/lib/date-string'); +var fmt = require('util').format; +var should = require('./init.js'); + +var db, Person; +describe('MySQL datetime handling', function() { + var personDefinition = { + name: String, + gender: String, + married: Boolean, + dob: {type: 'DateString'}, + createdAt: {type: Date, default: Date}, + }; + + // Modifying the connection timezones mid-flight is a pain, + // but closing the existing connection requires more effort. + function setConnectionTimezones(tz) { + db.connector.client._allConnections.forEach(function(con) { + con.config.timezone = tz; + }); + } + before(function(done) { + db = getSchema({ + dateStrings: true, + }); + Person = db.define('Person', personDefinition, {forceId: true, strict: true}); + db.automigrate(['Person'], done); + }); + + beforeEach(function() { + setConnectionTimezones('Z'); + }); + after(function(done) { + Person.destroyAll(function(err) { + db.disconnect(function() { + return done(err); + }); + }); + }); + + it('should allow use of DateStrings', function(done) { + var d = new DateString('1971-06-22'); + return Person.create({ + name: 'Mr. Pink', + gender: 'M', + dob: d, + createdAt: new Date(), + }).then(function(inst) { + return Person.findById(inst.id); + }).then(function(inst) { + inst.should.not.eql(null); + inst.dob.toString().should.eql(d.toString()); + return done(); + }).catch(function(err) { + return done(err); + }); + }); + + describe('should allow use of alternate timezone settings', function() { + var d = new Date('1971-06-22T00:00:00.000Z'); + testDateTime(d, '+04:00', '1971-06-22 04:00:00'); + testDateTime(d, '-04:00', '1971-06-21 20:00:00'); + testDateTime(d, '-11:00', '1971-06-21 13:00:00'); + testDateTime(d, '+12:00', '1971-06-22 12:00:00'); + + function testDateTime(date, tz, expected) { + it(tz, function(done) { + setConnectionTimezones(tz); + db.settings.legacyUtcDateProcessing = false; + db.settings.timezone = tz; + var dt = new Date(date); + return Person.create({ + name: 'Mr. Pink', + gender: 'M', + createdAt: dt, + }).then(function(inst) { + return Person.findById(inst.id); + }).then(function(inst) { + inst.should.not.eql(null); + inst.createdAt.toString().should.eql(expected); + return done(); + }).catch(function(err) { + return done(err); + }); + }); + } + }); +});