Description
二哥想知道在一段时期内,一共有多少个交易日。期货交易日的限定如下:
- 周六、周日不能交易
- 元旦期间(1月1日)不能交易
- 五一劳动节期间(5月1日至3日)不能交易
- 十一国庆节期间(10月1日至7日)不能交易
- 没有在上述要求中提到的日期均可交易
Input Format
第一行有一个整数n,表示一共有n组数据。
每组数据都有一行,是两个用空格分开的日期,分别为开始日期和结束日期。日期格式为YYYY-MM-DD(比如2010-11-11);数据保证开始日期不晚于结束日期。
对于所有数据:n≤365n≤365
对于30%的数据:日期范围从2010-11-23至2012-12-21
对于70%的数据:日期范围从1900-01-01至9999-12-31
Output Format
输出共n行,每行一个整数,对应于一组数据。
每组数据需要输出在指定日期区间内,共有多少个交易日;区间的开始和结束日期也算在内(如果是交易日的话)。
Sample Input
4
2010-11-18 2010-11-20
2010-01-01 2010-01-01
2010-05-01 2010-05-03
2010-10-01 2010-10-07
Sample Output
2
0
0
0
代码:
#include <iostream>
#include <stdlib.h>
using namespace std;
int calendar[2][13] = {{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
class Date{
public:
int year;
int month;
int day;
// 构造函数
Date() {
}
Date(int y, int m, int d) {
year = y;
month = m;
day = d;
}
// 获得下一天
Date getNextday(){
Date nextday(year, month, day);
int leapResult;
if(isLeap()) leapResult = 1;
else leapResult = 0;
if(day < calendar[leapResult][month]) nextday.day++; // 下一天在当月
else{ // 下一天在下一月
if(month < 12) {
nextday.month++;
nextday.day = 1;
}
else { // 下一天在下一年
nextday.year++;
nextday.month = 1;
nextday.day = 1;
}
}
return nextday;
}
// 闰年判断
bool isLeap() {
if(year % 4 == 0 && year % 100 != 0 || year % 400 ==0) return true;
else return false;
}
/**交易日判断
* 要求:
* 1.非周末
* 2.非节假日(元旦、五一、十一)
*/
bool isDealDay() {
if(isWeekend()) return false;
else if(isHoliday()) return false;
else return true;
}
// 周末判断
bool isWeekend() {
int y = year, m = month ,d = day;
if(m == 1 || m == 2) {
y--;
m += 12;
}
// 基姆拉尔森计算公式,可根据日期计算这一天是星期几
int week = (d + 2 * m + 3 * (m + 1) / 5 + y + y /4 -y /100 + y / 400) % 7 + 1; // 注意求余后加1
if(week > 5) return true;
else return false;
}
// 节假日判断
bool isHoliday() {
if(month == 1 && day == 1 || month == 5 && day >= 1 && day <= 3 || month == 10 && day >= 1 && day <= 7) return true;
else return false;
}
// 计算一年的交易日
int calDealDay() {
// 一年的周末
// 364 = 7 * 52:一年有52个整周,剩余的一或两天由平闰年决定
// 平年判断12.30 12.31是否周末,闰年判断12.31
int dd = 104, totalDay;
Date d1(year, 12, 30), d2(year, 12, 31);
if(isLeap()) {
if(d1.isWeekend()) dd++;
if(d2.isWeekend()) dd++;
totalDay = 366;
}
else{
if(d2.isWeekend()) dd++;
totalDay = 365;
}
// 一年的节假日
if(!Date(year, 1, 1).isWeekend()) dd++;
for(int i = 1; i < 4; i++) {
if(!Date(year, 5, i).isWeekend()) dd++;
}
for(int i = 1; i < 8; i++) {
if(!Date(year, 10, i).isWeekend()) dd++;
}
return totalDay - dd;
}
};
// 两个日期是否相等
bool equals(Date d1, Date d2) {
return d1.year == d2.year && d1.month == d2.month && d1.day == d2.day;
}
int main() {
int n;
cin >> n;
string s1[n], s2[n];
for(int i = 0; i < n; i++){
// 输入时有空格会默认为两个字符串,所以设为s1 s2
cin >> s1[i];
cin >> s2[i];
// 分离string(2010-11-18 2010-11-20)中的年月日
string sy1, sy2, sm1, sm2, sd1, sd2;
sy1 = s1[i].substr(0, 4);
sm1 = s1[i].substr(5, 2);
sd1 = s1[i].substr(8, 2);
sy2 = s2[i].substr(0, 4);
sm2 = s2[i].substr(5, 2);
sd2 = s2[i].substr(8, 2);
int y1, y2, m1, m2, d1, d2;
y1 = atoi(sy1.c_str()); // string->int,加<stdlib.h>头文件
m1 = atoi(sm1.c_str());
d1 = atoi(sd1.c_str());
y2 = atoi(sy2.c_str());
m2 = atoi(sm2.c_str());
d2 = atoi(sd2.c_str());
Date date1(y1, m1, d1), date2(y2, m2, d2), di;
int dayNum = 0; // 交易日
// 判断是否同年
if(y1 == y2) {
for(di = date1; !equals(di, date2.getNextday()); di = di.getNextday()) {
if(di.isDealDay()) dayNum++;
}
}
else{
// 不同年,计算d1到年底的交易日+一年的交易日(若有)+年初到对d2的交易日
for(di = date1; !equals(di, Date(y1 + 1, 1, 1)); di = di.getNextday()) {
if(di.isDealDay()) dayNum++;
}
for(int i = y1 + 1; i < y2; i++) {
Date temp(i, 1, 1);
dayNum += temp.calDealDay();
}
for(di = Date(y2, 1, 1); !equals(di, date2.getNextday()); di = di.getNextday()) {
if(di.isDealDay()) dayNum++;
}
}
cout << dayNum << endl;
}
}
思路:
1.将交易日分为三部分:开始日期到该年底,开始日期到结束日期之间完整的年份,年初到结束日期年底。例如2010-02-03 2018-09-01,可分为:2010-02-03到2010年年底、、2011-2017年、2018年年初到2018-09-01,三部分。
2.第一、第三部分采用遍历判断来计算非交易日,第二部分用calDealDay()函数计算这一年的交易日。
3.遍历时,对每一天进行isDealDay()的判断(即是否为交易日的判断,该判断由是否为周末和节假日决定)。
4.计算一年中的交易日数。首先计算出周末天数,考虑364=52*7,一年有52整周,即104天周末(非交易日)。平年多出两天 (12.30 12.31),进行isWeekend()的判断;闰年多出一天(12.31),同样进行isWeekend()的判断。接着对节假日进行判断,判断节假日是否为周末,否则非交易日自增,是则不增。
5.这样三部分的交易日数均计算出。
另:
网上搜集了一个计算某天是周几的公式:基姆拉尔森计算公式,W= (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400) mod 7+1,在用此公式时需要注意mod 7后还需加1,此外一月二月需要看成上一年的十三月、十四月。