如何在JavaScript中处理时区

我正在做一个从控制台运行的应用程序,它会计算每个月的星期日数量,并在5个星期日输出数月。 所以最后如果有6个月,有5个星期日,它输出6.我input这种格式的date:2014年1月2014年6月和params是在一个txt文件作为parameter passing。 我做了它在PHP中,这是非常简单的,但在节点js,我很痛苦。 CES或CEST正在杀死我。 我试图只与UTCdate,但我无法控制它,我有奇怪的输出。 例如,如果我介绍“2014年1月2014年6月”我得到两个月,但是当我介绍“2016年6月2月2017”我得到4,应该是3.我把一个console.log(date),当程序计数五星期日,我得到这些date:

Sun Mar 30 2014 00:00:00 GMT+0100 (CET) Sun Jun 01 2014 01:00:00 GMT+0200 (CEST) 2 //the output of months that have 5 sundays Sun Jul 31 2016 00:00:00 GMT+0200 (CEST) Sun Oct 30 2016 00:00:00 GMT+0200 (CEST) Sat Dec 31 2016 23:00:00 GMT+0100 (CET) Sat Feb 04 2017 23:00:00 GMT+0100 (CET) 4 //the output of months that have 5 sundays 

正如你所看到的,有两个星期六,GMT + 0100(CET)23:00:00。 这个输出真的很奇怪,我真的不知道如何处理这个问题。 任何帮助,将不胜感激。

 // Make sure we got a filename on the command line. if (process.argv.length < 3) { console.log('Usage: node ' + process.argv[1] + ' FILENAME'); process.exit(1); } // Read the file and print its contents. var fs = require('fs'), filename = process.argv[2]; fs.readFile(filename, 'utf8', function(err, data) { if (err) throw err; //split by carriage return data = data.split(/[\n\r]+/g); data.forEach(function(value){ var secureDate = securizeData(value); var totalDays = getDaysBetweenDates(secureDate[0],secureDate[1],secureDate[2],secureDate[3]); calculateSundays(totalDays, secureDate[0],secureDate[1]) }); }); /** * Description: checks the data and returns it as an array * @param {string} data * @return {array} data */ function securizeData(data){ //Looks for two strings (months) and two int ( year) matches with regexp var matchCount = data.match(/([az]+ [0-9]{4})/g); if(matchCount == 0){ process.exit('Insert a valid input'); } //clean carriage return data = data.replace(/[\n\r]+/g,' ',data); //clean left over blank spaces data = data.replace(/ +/g,' ',data); //split data in an array data = data.split(' '); //check array length var nIndex = data.length; //returns an array which it's total index number is a pair number or else error if(nIndex%2==0){ return (data); }else{ process.exit('Insert a valid input'); } } /** * Description: * @param {string} firstMonth * @param {int} firstYear * @param {string} secondMonth * @param {int} secondYear */ function getDaysBetweenDates(firstMonth, firstYear, secondMonth, secondYear){ var daysFirstDate = getDaysFirstDate(firstMonth, firstYear); var daysSecondDate = getDaysSecondDate(secondMonth,secondYear); var daysBetweenDates = substractDays(daysFirstDate,daysSecondDate); return daysBetweenDates; } /** * Description: substraction of two given unix dates * @param {int} daysFirstDate * @param {int} daysSecondDate * @return {int} days in unix format. Error if first date is later than second */ function substractDays(daysFirstDate,daysSecondDate){ if(daysFirstDate>daysSecondDate){ process.exit('First date must be earlier than second date'); }else{ var datediff = daysSecondDate-daysFirstDate; datediff = datediff/(60*60*24)/1000; var roundedNumber = Math.floor(datediff) return (roundedNumber); } } /** * Description: get the first date from day one in unix format * @param {string} @firstMonth * @param {int} @firstYear * @return {int} @date */ function getDaysFirstDate(firstMonth,firstYear){ var month = getMonthFromString(firstMonth,firstYear); return (Date.UTC(firstYear, month ,01)); } /** * Description: get the second date from last day of it's month in unix format * @param {string} @secondMonth * @param {int} @secondYear * @return {int} @date2 */ function getDaysSecondDate(secondMonth,secondYear){ var secondMonthNumber = getMonthFromString(secondMonth,secondYear); //Get last day of the month var lastDayMonth = getLastDayOfTheMonth(secondMonthNumber,secondYear); //Add last day of the month to secondDate return (Date.parse(secondMonth + ' ' + lastDayMonth +', ' + secondYear)); } /** * Description: get month number from a month string * @param {string} @month * @return {int} @month */ function getMonthFromString(mon,year){ return new Date(Date.parse(mon +" 1, "+year)).getMonth(); } /** * Description: get the Last day of the Month given in params * @param {int} @secondYear * @param {int} @secondMonthNumber * @return {int} UTCDate * */ function getLastDayOfTheMonth(secondMonthNumber, secondYear){ var lastDay = new Date(secondYear, secondMonthNumber +1, 0); return(lastDay.getUTCDate()); } /** * Description: * @param {int} totalDays * @param {array} tempDate */ function calculateSundays(totalDays,month, year){ var sundays={ num: '0' , output: '0' }; var intMonth = { val: new Date(Date.parse(month + year)).getMonth() }; intMonth.previousVal = intMonth.val; var d = Math.floor((new Date(year, intMonth.val,1)).getTime()); /// console.log(e); // process.exit(); var d = new Date(year, intMonth.val, 1); var dayOfTheWeek = d.getUTCDay(); for(var day = 2;day<=totalDays;day++) { resetSundaysIfMonthIncrease(intMonth, sundays); //update sundays if(dayOfTheWeek == 6) { sundays.num++; } //if there is 5 days in a month increase output if(sundays.num == 5) { sundays.output++; sundays.num = 0; console.log(d); } //increment date d.setUTCDate(d.getUTCDate() + 1); //update Day of the week dayOfTheWeek = d.getUTCDay(); //update Month intMonth.val = d.getUTCMonth(); } if(sundays.output == 0)process.exit("Please enter more than one month distance between dates \n"); else console.log(sundays.output + "\n"); } /** * description: reset sunday counter to 0 if current month is greater than previous month * @param {Object} intMonth * @param {Object} sundays */ function resetSundaysIfMonthIncrease(intMonth, sundays) { if(intMonth.val>intMonth.previousVal) { intMonth.previousVal = intMonth.val; sundays.num = 0; } } 

一个简单的algorithm是获得本月的第一个星期天,看看是否不到28天到月底。 如果是这样,那么这个月有4个星期天,否则5个UTC是无关紧要的。

这里有一些代码,希望评论是足够的:

 /* Return the number of months with 5 sundays between two dates ** specified as year, month where month number is the calendar month, ** Jan = 1, Feb - 2, etc. ** ** @param {number} y0 - start year ** @param {number} y1 - end year ** @param {number} m0 - start month (calendar number) ** @param {number} m1 - end month (calendar number) ** @returns {number} number of months with 5 Sundays between start and end */ function countMonthsWith5Sundays(y0, m0, y1, m1) { // Create dates for first of start and end month var start = new Date(y0, m0-1, 1); var end = new Date(y1, m1-1, 1); var count = 0; // If end is before start, swap dates if (start > end) { var t = start; start = end; end = t; } // Step month by month from start to end, counting months with 5 Sundays while (start <= end) { if (sundaysInMonth(start.getFullYear(), start.getMonth() + 1) === 5) { ++count; } start.setMonth(start.getMonth() + 1); } return count; } // Month number is calendar month, jan = 1, feb = 2, etc. /* Calculate number of Sundays in a month ** ** @param {number} y - year ** @param {number} m - month number (calendar number) */ function sundaysInMonth(y, m) { // Create date for start of month, move to first Sunday var d = new Date(y, m-1, 1); d.setDate(d.getDate() + (d.getDay()? 7 - d.getDay() : 0)); // Get number of days in month, subtract current date and // if there are 28 days or more left, there are 5 Sundays // Use calendar month number and date of 0 to get last day of // month var daysInMonth = new Date(y, m, 0).getDate(); return daysInMonth - d.getDate() > 27 ? 5 : 4; } document.write(countMonthsWith5Sundays(2016,1,2016,6)); 

列出5个星期日的月份的解决scheme似乎围绕着2个规则:

  1. 本月应该有28天以上; 和
  2. 第一个星期天的日子应该less于当月28日以上的天数。

我修改了你的代码来使用moment.js 。

它看起来像这样:

 // Make sure we got a filename on the command line. if (process.argv.length < 3) { console.log('Usage: node ' + process.argv[1] + ' FILENAME'); process.exit(1); } // Read the file and print its contents. var fs = require('fs'), filename = process.argv[2]; fs.readFile(filename, 'utf8', function(err, data) { if (err) throw err; //split by carriage return data = data.split(/[\n\r]+/g); data.forEach(function(value){ var secureDate = securizeData(value); calcSundays(secureDate[0], secureDate[1], secureDate[2], secureDate[3]); }); }); /** * Description: checks the data and returns it as an array * @param {string} data * @return {array} data */ function securizeData(data){ //Looks for two strings (months) and two int ( year) matches with regexp var matchCount = data.match(/([az]+ [0-9]{4})/g); if(matchCount == 0){ process.exit('Insert a valid input'); } //clean carriage return data = data.replace(/[\n\r]+/g,' ',data); //clean left over blank spaces data = data.replace(/ +/g,' ',data); //split data in an array data = data.split(' '); //check array length var nIndex = data.length; //returns an array which it's total index number is a pair number or else error if(nIndex%2==0){ return (data); }else{ process.exit('Insert a valid input'); } } /** * Description: loop through the months between the start and end dates and count the sundays in each month. * @param {string} firstMonth * @param {int} firstYear * @param {string} secondMonth * @param {int} secondYear */ function calcSundays(startMonth, startYear, endMonth, endYear) { var intStartMonth = getMonthFromString(startMonth, startYear); var intEndMonth = getMonthFromString(endMonth, endYear); var date = { month: intStartMonth, year: startYear }; while (date.month <= intEndMonth && date.year <= endYear) { var sundays = countSundaysInMonth(date); if (sundays == 5) { // Log the last sunday of the month with 5 sundays. console.log(moment(date).endOf('month').day(-7).format()); } } } /** * Description: count the number of sundays in a month. * @param {object} date */ function countSundaysInMonth(date) { var totDays = moment(date).endOf('month').date(); if (totDays < 29) return 4; var firstSunday = moment(date).day('Sunday').date(); if (firstSunday <= totDays - 28) return 5; return 4; } /** * Description: get month number from a month string * @param {string} @month * @return {int} @month */ function getMonthFromString(mon,year){ return new Date(Date.parse(mon +" 1, "+year)).getMonth(); }