day_of_year.js (3666B)
1 /** 2 * @license Apache-2.0 3 * 4 * Copyright (c) 2018 The Stdlib Authors. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 'use strict'; 20 21 // MODULES // 22 23 var isDateObject = require( '@stdlib/assert/is-date-object' ); 24 var isString = require( '@stdlib/assert/is-string' ).isPrimitive; 25 var isInteger = require( '@stdlib/assert/is-integer' ).isPrimitive; 26 var daysInMonth = require( './../../days-in-month' ); 27 var isLeapYear = require( '@stdlib/assert/is-leap-year' ); 28 var lowercase = require( '@stdlib/string/lowercase' ); 29 var MONTHS = require( './months.json' ); 30 var DAYS = require( './days.json' ); 31 32 33 // MAIN // 34 35 /** 36 * Returns the day of the year. 37 * 38 * @param {(string|integer|Date)} [month] - month (or Date) 39 * @param {integer} [day] - day 40 * @param {integer} [year] - year 41 * @throws {TypeError} first argument must be either a string, integer, or `Date` object 42 * @throws {Error} must provide a recognized month 43 * @throws {RangeError} an integer month argument must be on the interval `[1,12]` 44 * @throws {TypeError} second argument must be an integer 45 * @throws {RangeError} second argument must be greater than `0` and less than or equal to the maximum number of days in a month 46 * @throws {TypeError} third argument must be an integer 47 * @returns {integer} day of the year 48 * 49 * @example 50 * var day = dayOfYear(); 51 * // returns <number> 52 * 53 * @example 54 * var day = dayOfYear( new Date() ); 55 * // returns <number> 56 * 57 * @example 58 * var day = dayOfYear( 12, 31, 2017 ); 59 * // returns 365 60 * 61 * @example 62 * var day = dayOfYear( 12, 31, 2016 ); 63 * // returns 366 64 */ 65 function dayOfYear( month, day, year ) { 66 var date; 67 var days; 68 var num; 69 var mon; 70 var yr; 71 var d; 72 var i; 73 if ( arguments.length === 0 ) { 74 // Note: cannot cache as application may cross over into a new year: 75 date = new Date(); 76 mon = date.getMonth() + 1; // zero-based 77 yr = date.getFullYear(); 78 d = date.getDate(); 79 } else if ( arguments.length === 1 ) { 80 if ( isDateObject( month ) ) { 81 date = month; 82 mon = date.getMonth() + 1; // zero-based 83 yr = date.getFullYear(); 84 d = date.getDate(); 85 } else { 86 throw new TypeError( 'invalid argument. If only providing a single argument, must provide a `Date` object. Value: `'+month+'`.' ); 87 } 88 } else { 89 if ( !isString( month ) && !isInteger( month ) ) { 90 throw new TypeError( 'invalid argument. First argument must be either a string or integer. Value: `'+month+'`.' ); 91 } 92 if ( !isInteger( day ) ) { 93 throw new TypeError( 'invalid argument. Second argument must be an integer. Value: `'+day+'`.' ); 94 } 95 if ( !isInteger( year ) ) { 96 throw new TypeError( 'invalid argument. Third argument must be an integer. Value: `'+year+'`.' ); 97 } 98 mon = month; 99 d = day; 100 yr = year; 101 } 102 days = daysInMonth( mon, yr ); 103 if ( d < 1 || d > days ) { 104 throw new RangeError( 'invalid argument. Day number must be on the interval `[1,'+days+']`. Value: `'+d+'`.' ); 105 } 106 mon = lowercase( mon.toString() ); 107 mon = MONTHS[ mon ]; 108 num = 0; 109 for ( i = 0; i < mon-1; i++ ) { 110 num += DAYS[ i ]; 111 112 // Check for February during a leap year... 113 if ( i === 1 && isLeapYear( yr ) ) { 114 num += 1; 115 } 116 } 117 num += d; 118 return num; 119 } 120 121 122 // EXPORTS // 123 124 module.exports = dayOfYear;