Skip to content

Commit

Permalink
Merge pull request #18 from MatthewTLackey/v2-beta
Browse files Browse the repository at this point in the history
V2 -> master
  • Loading branch information
brianbaker authored Nov 22, 2017
2 parents 0af814f + abce8fd commit f53488f
Show file tree
Hide file tree
Showing 8 changed files with 1,066 additions and 226 deletions.
7 changes: 2 additions & 5 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@
"no-underscore-dangle": 0,
"no-empty-function": 1,
"no-param-reassign": 0,
"prefer-arrow-callback": 0,
"no-var": 0
},
"env":{
"amd": true
"no-var":"off",
"prefer-arrow-callback": 0
}
}
38 changes: 38 additions & 0 deletions Gruntfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
'use strict';

module.exports = (grunt) => {
grunt.initConfig({
eslint: {
target: ['**/*.js', '!node_modules/**']
},
mochaTest: {
test: {
options: {
reporter: 'nyan'
},
src: ['test/**/*.js']
}
},
watch: {
config: {
files: './Gruntfile.js',
options: {
reload: true
}
},
tests: {
files: ['test/**.js', '!node_modules/**', './moment-msdate.js'],
tasks: ['test'],
options: {
spawn: true
}
}
}
});

grunt.loadNpmTasks('grunt-mocha-test');
grunt.loadNpmTasks('grunt-eslint');
grunt.loadNpmTasks('grunt-contrib-watch');

grunt.registerTask('test', ['eslint', 'mochaTest']);
};
77 changes: 39 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# moment-msdate [![Build Status](https://travis-ci.org/markitondemand/moment-msdate.svg?branch=master)](https://travis-ci.org/markitondemand/moment-msdate) [![npm version](https://badge.fury.io/js/moment-msdate.svg)](https://badge.fury.io/js/moment-msdate)

A [Moment.js](http://momentjs.com/) plugin for parsing OLE Automation dates.
A [moment.js](http://momentjs.com/) and [moment-timezone.js](http://momentjs.com/timezone) plugin for parsing OLE Automation dates.

Visit [http://markitondemand.github.io/moment-msdate/](http://markitondemand.github.io/moment-msdate/) for more information and examples.

Expand All @@ -10,57 +10,58 @@ An OLE Automation date, or "MSDate" as we call it, is implemented as a floating-

Read more [about OLE Automation on MSDN](http://msdn.microsoft.com/en-us/library/dt80be78(v=vs.71).aspx) (including [`DateTime.ToOADate`](http://msdn.microsoft.com/en-us/library/system.datetime.tooadate.aspx) and [`DateTime.FromOADate`](http://msdn.microsoft.com/en-us/library/system.datetime.fromoadate.aspx)).

## Usage

### toOADate()

Convert a `moment` to an OA date:

`moment().toOADate();`

This API returns a floating-point number (the OA date), so once the conversion has been made, you no longer have a `moment` object.
**Note**: OLE Automation dates are unspecified and they’re based on the local timezone by default. The moment library normalizes all time to UTC and as a result this library will return all values based on UTC time.

### fromOADate()

Convert an OA date to a `moment` (or to a JavaScript date):

`moment.fromOADate(41493)` returns `Wed Aug 07 2013 00:00:00 GMT-0600 (MDT)`

For exact date _and_ time (time is the value right of the decimal):

`moment.fromOADate(41493.706892280097000)` returns `Wed Aug 07 2013 16:57:55 GMT-0600 (MDT)`
## Usage

By default moment.fromOADate() uses the server time as the offset to UTC a second argument can be provided that indicates the offset of the OA date to UTC in minutes.
### fromOADate(oaDate, [offset])

`moment.fromOADate(42754.835023148145, 360)` returns `Fri Jan 20 2017 02:02:25 GMT+0000 (UTC)`
Convert an OA date to a `moment`:

For Moment formatting:
`moment.fromOADate(42298.6868055556)` returns `2015-10-21T16:29:00.000Z`

Convert an OA date with a known offset to UTC to a `moment` in UTC time
```
//convert OA date into Moment (JavaScript date)
var momentDate = moment.fromOADate(41493.706892280097000);
//use Moment's awesomeness
var formattedDate = momentDate.format('MMM Do YY);
//formattedDate === "Aug 7th 13"
moment.fromOADate(42298.6868055556, 240) returns 2015-10-21T20:29:00.000Z
moment.fromOADate(42298.6868055556, 'America/New_York') returns `2015-10-21T20:29:00.000Z
```

This could easily be chained together as:
### toOADate()

`moment.fromOADate(41493.706892280097000).format('MMM Do YY); //Aug 7th 13`
Convert a `moment` to a floating point OA date in UTC:
```
const momentDate = moment('2015-10-21T16:29:00.000-07:00')
momentDate.toOADate() returns 42298.978472222225
```

**Note**: OLE Automation dates are unspecified, meaning they’re based on the local timezone by default.
### Example Moment Formatting:

### fromOADateWithZone()
Converts an OLE Automation date to a moment (baking in a timezone if one is supplied) and returns a UTC Moment object instance.
Convert OA date into Moment (OA Date is assumed to be in UTC)
```
const momentDate = moment.fromOADate(42298.6868055556);
```

`moment.fromOADateWithZone('42754.835023148145', 'America/Denver');` returns `Fri Jan 20 2017 03:02:25 GMT+0000 (UTC)`
If OA date is not in UTC and the offset to UTC is known it can be specified during the moment creation in minutes
```
const momentDate = moment.fromOADate(42298.6868055556, 240)
momentDate.toISOString() returns '2015-10-21T20:29:00.000Z' (UTC)
momentDate.format('LLLL') returns 'Wednesday, October 21, 2015 8:29 PM' (UTC)
```

### toOADateWithZone()
Converts a moment (with timezone) to an OLE Automation date in UTC.
If OA date is not in UTC and the offset to UTC is known it can be specified during the moment creation as a timezone
```
const momentDate = moment.fromOADate(42298.6868055556, 'America/New_York')
momentDate.toISOString() returns '2015-10-21T20:29:00.000Z' (UTC)
momentDate.format('LLLL') returns 'Wednesday, October 21, 2015 8:29 PM' (UTC)
```

`moment('2017-01-19T20:02:26.000Z').toOADateWithZone()` returns `42754.835023148145`
Once the date is in UTC it can than easily be converted to any other timezone using moment-timezone.js
```
const momentDate = moment.fromOADate(42298.6868055556, 240)
momentDate.tz('America/New_York')
momentDate.toISOString() returns '2015-10-21T20:29:00.000Z' (UTC)
momentDate.format('LLLL') returns 'Wednesday, October 21, 2015 4:29 PM' (ET)
```

## License

Expand Down
111 changes: 67 additions & 44 deletions moment-msdate.js
Original file line number Diff line number Diff line change
@@ -1,74 +1,97 @@
'use strict';

(function(root, factory) {

/*global define*/
if (typeof define === 'function' && define.amd) {
define(['moment-timezone'], factory);
define(['moment', 'moment-timezone'], factory); // AMD
} else if (typeof module === 'object' && module.exports) {
module.exports = factory(require('moment-timezone'));
module.exports = factory(require('moment'), require('moment-timezone')); // Node
} else {
factory(root.moment);
factory(root.moment, root.moment.tz); // Browser
}

}(this, function(moment) {

/**
* Constants
*/
}(this, function(moment, momentTimezone) {
var MINUTE_MILLISECONDS = 60 * 1000;
var DAY_MILLISECONDS = 86400000;
var MS_DAY_OFFSET = 25569;

const momentVersion = moment.version.split('.');
const major = +momentVersion[0];
const minor = +momentVersion[1];

if (major < 2 || (major === 2 && minor < 6)) {
throw new Error(`moment-msdate requires Moment.js >= 2.6.0. You are using Moment.js ${moment.version}. See momentjs.com`);
}

if (!momentTimezone || !moment.tz) {
throw new Error('moment-msdate requires moment-timezone.js. see momentjs.com/timezone');
}

const oaDateToTicks = function(oaDate) {
return ((oaDate - MS_DAY_OFFSET) * DAY_MILLISECONDS) + (oaDate >= 0.0 ? 0.5 : -0.5);
};

const ticksToOADate = function(ticks) {
return (ticks / DAY_MILLISECONDS) + MS_DAY_OFFSET;
};

/**
* @description To JavaScript date from OLE Automation date
* @description takes an oaDate that is not in utc and converts it to a utc moment offset by a number of minutes
*
* @param msDate An OLE Automation date. Required.
* @param offsetToUtcInMinutes An offset from the msDate to UTC. If not supplied the offset from the system timezone will be used.
* @param {double} oaDate
* @param {string} offsetToUtcInMinutes
* @returns moment
*/
moment.fromOADate = function(msDate, offsetToUtcInMinutes) {
var jO = new Date(((msDate - MS_DAY_OFFSET) * DAY_MILLISECONDS) + (msDate >= 0.0 ? 0.5 : -0.5));
var tz = isNaN(parseInt(offsetToUtcInMinutes, 10)) ? jO.getTimezoneOffset() : offsetToUtcInMinutes;
jO = new Date((((msDate - MS_DAY_OFFSET) + (tz / (60 * 24))) * DAY_MILLISECONDS) + (msDate >= 0.0 ? 0.5 : -0.5));
return moment(jO);
const fromOADateOffsetToUtcByMinutes = function(oaDate, offsetToUtcInMinutes) {
const offsetInTicks = offsetToUtcInMinutes * MINUTE_MILLISECONDS;
const ticks = oaDateToTicks(oaDate);
return moment(ticks + offsetInTicks).utc();
};

/**
* To OLE Automation date from JavaScript date
* @description takes an oaDate that is not in utc and converts it to a utc moment offset by the specified timezone
*
* @param jsDate A JavaScript date object to convert to OA Date. Defaults to existing moment instance or new Date
* @returns Floating-point number, e.g., 41502.558798240745
* @param {double} oaDate
* @param {string} timezone
* @returns moment
*/
moment.fn.toOADate = function(jsDateInput) {
var jsDate = jsDateInput || this._d || new Date();
var timezoneOffset = jsDate.getTimezoneOffset() / (60 * 24);
var msDateObj = (jsDate.getTime() / DAY_MILLISECONDS) + (MS_DAY_OFFSET - timezoneOffset);
return msDateObj;
const fromOADateOffsetToUtcByTimezone = function(oaDate, timezone) {
if (!moment.tz.zone(timezone)) { throw new Error('timezone provided is not available in moment-timezone.js', 'moment-msdate.js', 59); }
const ticks = oaDateToTicks(oaDate);
const offset = moment(ticks).tz(timezone).utcOffset() * MINUTE_MILLISECONDS;
return moment.tz(ticks - offset, timezone).utc();
};

moment.updateLocale('en', {
invalidDate: undefined
});

/**
* Converts an OLE Automation date to a moment (baking in a timezone if one is supplied)
* Returns a UTC Moment object instance
*/
moment.fromOADateWithZone = function(msDate, timeZone) {
if (timeZone) {
return moment.fromOADate(msDate).tz(timeZone);
}
* @description takes an oaDate that is in utc and converts it to a utc moment or takes an oaDate and an offset to utc and converts it to a utc moment. The offset can be an int representing the offset to utc in minutes or a string indicating the timezone of the oaDate.
*
* @param {double} oaDate
* @param {string=} {int=} offset
* @returns moment
*/
moment.fromOADate = function(oaDate, offset) {
if (isNaN(parseInt(oaDate, 10))) { throw new TypeError('fromOADate requires an oaDate that is not null or undefined', 'moment-msdate.js', 72); }

return moment.fromOADate(msDate);
/* no offset */
if (!offset) { return fromOADateOffsetToUtcByMinutes(oaDate, 0); }

/* timezone */
const parsedOffset = parseInt(offset, 10);
if (isNaN(parsedOffset)) { return fromOADateOffsetToUtcByTimezone(oaDate, offset); }

/* minutes */
return fromOADateOffsetToUtcByMinutes(oaDate, parsedOffset);
};

/**
* Converts a moment (with timezone) to an OLE Automation date in UTC
* Returns an OLE Automation date in the form of a double
*/
moment.fn.toOADateWithZone = function() {
var nMsDate = (this.valueOf() / DAY_MILLISECONDS) + MS_DAY_OFFSET;
return nMsDate;
* @description converts a moment to a UTC OLE automation date represented as a double
*
* @returns {double}
*/
moment.fn.toOADate = function() {
const milliseconds = this.valueOf();
return ticksToOADate(milliseconds);
};


return moment;
}));
Loading

0 comments on commit f53488f

Please sign in to comment.