我正在做一个从控制台运行的应用程序,它计算在过去的日期之间的每个月中的星期日数,并且仅在5个星期日输出几个月。所以最后如果有6个月有5个星期日,则输出6.我以这种格式输入日期:2014年1月2014年,并且params在作为参数传递的txt文件中。我在php中做到了这很简单,但在节点js中,我很痛苦。 CES或CEST正在扼杀我。我只是尝试使用UTC日期,但我无法控制它并且我有奇怪的输出。例如,如果我介绍" 2014年1月2014"我得到两个月,但是当我介绍" 2016年6月和2017年2月"我得到4,应该是3。 当程序计算五个星期日时,我放了一个console.log(日期),我得到了那些日期:
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
如你所见,有两个星期六,格林威治标准时间23:00:00 + 0100(CET)。这个输出很奇怪,我真的不知道如何处理这个问题。任何帮助,将不胜感激。
// 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(/([a-z]+ [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;
}
}
答案 0 :(得分:2)
一个简单的算法是获取当月的第一个星期日,看看它是否在本月底之前不到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));
&#13;
上述内容可以轻松修改,以便在有5个星期日的月份中返回代表第一天或第一个星期日的日期。
答案 1 :(得分:0)
似乎列出有5个星期日的月份的解决方案围绕2条规则:
我修改了您的代码以使用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(/([a-z]+ [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();
}