time-to-botec/squiggle/node_modules/@stdlib/array/datespace/lib/main.js

193 lines
5.1 KiB
JavaScript
Raw Normal View History

/**
* @license Apache-2.0
*
* Copyright (c) 2021 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
// MODULES //
var hasOwnProp = require( '@stdlib/assert/has-own-property' );
var isInteger = require( '@stdlib/assert/is-integer' );
var isString = require( '@stdlib/assert/is-string' ).isPrimitive;
var isObject = require( '@stdlib/assert/is-object' );
var floor = require( '@stdlib/math/base/special/floor' );
var round = require( '@stdlib/math/base/special/round' );
var ceil = require( '@stdlib/math/base/special/ceil' );
// VARIABLES //
var timestamp = /^\d{10}$|^\d{13}$/;
var rounders = [ 'floor', 'ceil', 'round' ];
// FUNCTIONS //
/**
* Validates a date parameter.
*
* @private
* @param {*} value - value to be validated
* @param {string} name - name to be used in error messages
* @throws {TypeError} value must either be a date string, Date object, Unix timestamp, or JavaScript timestamp
* @throws {Error} numeric date must be either a Unix or Javascript timestamp
* @returns {Date} validated date
*/
function validDate( value, name ) {
var type;
type = typeof value;
if ( type === 'string' ) {
value = Date.parse( value );
if ( value !== value ) {
throw new Error( 'invalid argument. Unable to parse ' + name.toLowerCase() + ' date.' );
}
value = new Date( value );
}
if ( type === 'number' ) {
if ( !timestamp.test( value ) ) {
throw new Error( 'invalid argument. Numeric ' + name.toLowerCase() + ' date must be either a Unix or Javascript timestamp.' );
}
if ( value.toString().length === 10 ) {
value *= 1000; // sec to ms
}
value = new Date( value );
}
if ( !(value instanceof Date) ) {
throw new TypeError( 'invalid argument. ' + name + ' date must either be a date string, Date object, Unix timestamp, or JavaScript timestamp.' );
}
return value;
}
// MAIN //
/**
* Generates an array of linearly spaced dates.
*
* @param {(Date|number|string)} start - start time as either a `Date` object, Unix timestamp, JavaScript timestamp, or date string
* @param {(Date|number|string)} stop - stop time as either a `Date` object, Unix timestamp, JavaScript timestamp, or date string
* @param {number} [length] - output array length (default: 100)
* @param {Object} [options] - function options
* @param {string} [options.round] - specifies how sub-millisecond times should be rounded: [ 'floor', 'ceil', 'round' ] (default: 'floor' )
* @throws {TypeError} length argument must a positive integer
* @throws {Error} must provide valid options
* @returns {Array} array of dates
*
* @example
* var stop = '2014-12-02T07:00:54.973Z';
* var start = new Date( stop ) - 60000;
*
* var arr = datespace( start, stop, 6 );
* // returns [...]
*
* @example
* // Equivalent of Math.ceil():
* var arr = datespace( 1417503655000, 1417503655001, 3, { 'round': 'ceil' } );
* // returns [...]
*
* // Equivalent of Math.round():
* arr = datespace( 1417503655000, 1417503655001, 3, { 'round': 'round' } );
* // returns [...]
*/
function datespace( start, stop, length, options ) {
var opts;
var len;
var flg;
var arr;
var end;
var fcn;
var tmp;
var d;
var i;
len = 100;
flg = true;
opts = {
'round': 'floor'
};
start = validDate( start, 'Start' );
stop = validDate( stop, 'Stop' );
if ( arguments.length > 2 ) {
if ( arguments.length === 3 ) {
if ( isObject( length ) ) {
opts = length;
} else {
len = length;
// Turn off checking the options object...
flg = false;
}
} else {
opts = options;
len = length;
}
if ( len === 0 ) {
return [];
}
if ( !isInteger( len ) || len < 0 ) {
throw new TypeError( 'invalid argument. Length must a positive integer.' );
}
if ( flg ) {
if ( !isObject( opts ) ) {
throw new TypeError( 'invalid argument. Options argument must be an object. Value: `' + opts + '`.' );
}
if ( hasOwnProp( opts, 'round' ) ) {
if ( !isString( opts.round ) ) {
throw new TypeError( 'invalid option. `round` option must be a string.' );
}
if ( rounders.indexOf( opts.round ) === -1 ) {
throw new Error( 'invalid input option. `round` option must be one of [' + rounders.join( ',' ) + '].' );
}
}
}
}
switch ( opts.round ) {
case 'round':
fcn = round;
break;
case 'ceil':
fcn = ceil;
break;
default:
case 'floor':
fcn = floor;
break;
}
// Calculate the increment...
end = len - 1;
d = ( stop.getTime() - start.getTime() ) / end;
// Build the output array...
arr = new Array( len );
tmp = start;
arr[ 0 ] = tmp;
tmp = tmp.getTime();
for ( i = 1; i < end; i++ ) {
tmp += d;
arr[ i ] = new Date( fcn( tmp ) );
}
arr[ end ] = stop;
return arr;
}
// EXPORTS //
module.exports = datespace;