Skip to content

Commit

Permalink
Added timezone ability to parseDateTimeField.
Browse files Browse the repository at this point in the history
`moment` is now returned and is a timezone aware moment.js object.
  • Loading branch information
shepherdsam committed Feb 7, 2017
1 parent 9af9c20 commit c5568e5
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 12 deletions.
59 changes: 53 additions & 6 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
'use strict';

var _ = require('lodash');
var SugarDate = require('sugar-date').Date;
var _ = require('lodash'),
moment = require('moment-timezone'),
SugarDate = require('sugar-date').Date;
require('sugar-date/locales');

var Utils = {};

var DEFAULT_FLATTENED_DELIMITER = '__';
var DEFAULT_FLATTENED_ARRAY_DELIMITER = '_+_';
var TIMEZONE_TO_LOCALE = {
'Europe/London': 'en-GB'
};

var humanize = function(str) {
/* istanbul ignore if */
Expand Down Expand Up @@ -406,6 +410,7 @@ Utils.cloneTerse = function(input) {
* - Utils.parseDateTimeField('2014-01-18 09:30:00')
* - Utils.parseDateTimeField('2014-01-18 09:30:00 -0400')
* - Utils.parseDateTimeField('2014-01-18 09:30:00', {locale: 'en-GB'})
* - Utils.parseDateTimeField('2014-01-18 09:30:00', {timezone: 'America/Chicago'})
* - Utils.parseDateTimeField('2014-01-18 09:30:00', {fromUTC: true, setUTC: true})
* - Utils.parseDateTimeField('in 2 days')
* - Utils.parseDateTimeField('5 minutes from now')
Expand All @@ -426,12 +431,33 @@ Utils.parseDateTimeField = function(field, options) {
var getRtnObject = function(parsed, isValid) {
return formatParsedObject('date', field, isValid, parsed);
};
options = options || {};

// Copy options
options = _.assign({}, options);

// Default timezone
var timezone = options.timezone || 'UTC';
var isUTC = timezone.toLowerCase() === 'utc';

// Lookup Locale. Check options, then look up based on timezone. Default to 'en'
options.locale = options.locale || TIMEZONE_TO_LOCALE[timezone] || 'en';

// If invalid
if (moment.tz.zone(timezone) === null) {
Utils.Logger.warn('Utils.parseDateTimeField - Timezone "' + timezone + '" is invalid. Assuming UTC');
timezone = 'UTC';
}

// This special case is here to get around a bug in SugarDate. Issue: #582
options.fromUTC = field === 'now' ? false : isUTC;

// Help SugarDate be aware of timezones
var previousNewDateInternal;
if (_.isFunction(options.newDateInternal)) {
if (timezone) {
previousNewDateInternal = SugarDate.getOption('newDateInternal');
SugarDate.setOption('newDateInternal', options.newDateInternal);
SugarDate.setOption('newDateInternal', function() {
return moment().tz(timezone).toDate();
});
}

var parsedDate;
Expand Down Expand Up @@ -503,8 +529,29 @@ Utils.parseDateTimeField = function(field, options) {
SugarDate.setOption('newDateInternal', previousNewDateInternal);
}

var dateMoment;
if (SugarDate.isValid(parsedDate)) {
var hasTZOffset = new RegExp('[+-]{1}[0-9]{2}:?[0-9]{2}').test(field);

// Convert to string. Important to remove offset/tz info (if none was provided originally)
// or moment will ignore the passed in tz in later step.
var tzFormatStr = hasTZOffset ? '{Z}' : '';
var dateString = SugarDate.format(SugarDate.setUTC(parsedDate, isUTC), '{yyyy}-{MM}-{dd}T{HH}:{mm}:{ss}' + tzFormatStr);
Utils.Logger.debug('Utils.parseDateTimeField: dateString:' + dateString);

// This parses the dateString in the timezone specified.
dateMoment = moment.tz(dateString, timezone);
// Utils.Logger.debug('Utils.parseDateTimeField: moment:' + dateMoment);
}

// parsedDate will always be a date at this point.
return getRtnObject(parsedDate, SugarDate.isValid(parsedDate));
var rtnObject = getRtnObject(parsedDate, SugarDate.isValid(parsedDate));

// Add the dateMoment to the return object
if (dateMoment) {
rtnObject.moment = dateMoment;
}
return rtnObject;
};

/**
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"dependencies": {
"bluebird": "^3.4.1",
"lodash": "^4.14.2",
"moment-timezone": "^0.5.11",
"sugar-date": "^2.0.4"
}
}
40 changes: 34 additions & 6 deletions spec/specs.js
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,8 @@ describe('Utils', function() {
type: 'date',
input: input,
valid: true,
parsed: expected
parsed: expected,
moment: jasmine.any(Object)
});
};

Expand All @@ -782,6 +783,7 @@ describe('Utils', function() {

beforeEach(function() {
epoch = new Date(0);
// spyOn(Utils, '_getFutureDate').and.callThrough();
spyOn(Utils, '_getFutureDate').and.callFake(function(str) {
var parsed = SugarDate.create(str, {future: true});
return SugarDate.isValid(parsed) ? epoch : parsed;
Expand All @@ -800,7 +802,7 @@ describe('Utils', function() {

it('should parse a datetime string', function() {
expectValidDate('tomorrow', epoch);
expect(Utils._getFutureDate).toHaveBeenCalledWith('tomorrow', {});
expect(Utils._getFutureDate).toHaveBeenCalledWith('tomorrow', {locale: 'en', fromUTC: true});
});

it('should return as invalid if no string is passed', function() {
Expand Down Expand Up @@ -839,7 +841,7 @@ describe('Utils', function() {
describe('Locales', function() {
it('parses a date without locale', function() {
Utils.parseDateTimeField('now +1d');
expect(Utils._getFutureDate).toHaveBeenCalledWith('now', {});
expect(Utils._getFutureDate).toHaveBeenCalledWith('now', {locale: 'en', fromUTC: true});

epoch = SugarDate.create('1/11/2017', {fromUTC: true});
var d = Utils.parseDateTimeField('1/11/2017');
Expand All @@ -848,18 +850,44 @@ describe('Utils', function() {

it('parses a date with locale', function() {
Utils.parseDateTimeField('now +1d', {locale: 'en-GB'});
expect(Utils._getFutureDate).toHaveBeenCalledWith('now', {locale: 'en-GB'});
expect(Utils._getFutureDate).toHaveBeenCalledWith('now', {locale: 'en-GB', fromUTC: true});

epoch = SugarDate.create('1/11/2017', {fromUTC: true});
var d = Utils.parseDateTimeField('11/1/2017');
expect(d.parsed.toISOString()).toEqual('2017-01-11T00:00:00.000Z');
});

});

describe('Timezones', function() {
it('parses a date without timezone', function() {
Utils.parseDateTimeField('1/11/2017 +1d');
expect(Utils._getFutureDate).toHaveBeenCalledWith('1/11/2017', {locale: 'en', fromUTC: true});

epoch = SugarDate.create('1/12/2017', {fromUTC: true});
var d = Utils.parseDateTimeField('1/12/2017');
expect(d.moment.toISOString()).toEqual('2017-01-12T00:00:00.000Z');
});

it('parses a date with timezone', function() {
Utils.parseDateTimeField('1/11/2017 +1d', {timezone: 'America/New_York'});
expect(Utils._getFutureDate).toHaveBeenCalledWith('1/11/2017', {
locale: 'en',
timezone: 'America/New_York',
fromUTC: false
});

epoch = SugarDate.create('1/12/2017');
var d = Utils.parseDateTimeField('1/12/2017', {timezone: 'America/New_York'});
expect(d.moment.toISOString()).toEqual('2017-01-12T05:00:00.000Z');
});

});

describe('Offset Modifiers', function() {
it('should strip offset modifier from string to parse', function() {
Utils.parseDateTimeField('now +1d');
expect(Utils._getFutureDate).toHaveBeenCalledWith('now', {});
expect(Utils._getFutureDate).toHaveBeenCalledWith('now', {locale: 'en', fromUTC: true});
});

describe('Increment', function() {
Expand Down Expand Up @@ -962,7 +990,7 @@ describe('Utils', function() {

it('should not apply the offset modifier if it is 0', function() {
spyOn(SugarDate, 'addSeconds');
Utils.parseDateTimeField('now');
// console.log(Utils.parseDateTimeField('now'));
expect(SugarDate.addSeconds)
.not.toHaveBeenCalled();
});
Expand Down

0 comments on commit c5568e5

Please sign in to comment.