我正在尝试编写一个 Date 类以尝试学习 C++。
我正在尝试找到一种算法来添加或减去日期到日期,其中 Day 从 1 开始,Month 从 1 开始。事实证明它非常复杂,而且谷歌并没有出现太多,
有谁知道这样做的算法?
我正在尝试编写一个 Date 类以尝试学习 C++。
我正在尝试找到一种算法来添加或减去日期到日期,其中 Day 从 1 开始,Month 从 1 开始。事实证明它非常复杂,而且谷歌并没有出现太多,
有谁知道这样做的算法?
最简单的方法是实际编写两个函数,一个将天转换为从给定开始日期开始的天数,另一个将转换回日期。一旦日期表示为天数,添加或减去它是微不足道的。
你可以在这里找到算法:http: //alcor.concordia.ca/~gpkatch/gdate-algorithm.html
你真的不需要这样的算法(至少不是名副其实的东西),标准库可以完成大部分繁重的工作;日历计算是出了名的棘手。只要您不需要早于 1900 年的日期,那么:
#include <ctime>
// Adjust date by a number of days +/-
void DatePlusDays( struct tm* date, int days )
{
const time_t ONE_DAY = 24 * 60 * 60 ;
// Seconds since start of epoch
time_t date_seconds = mktime( date ) + (days * ONE_DAY) ;
// Update caller's date
// Use localtime because mktime converts to UTC so may change date
*date = *localtime( &date_seconds ) ; ;
}
示例用法:
#include <iostream>
int main()
{
struct tm date = { 0, 0, 12 } ; // nominal time midday (arbitrary).
int year = 2010 ;
int month = 2 ; // February
int day = 26 ; // 26th
// Set up the date structure
date.tm_year = year - 1900 ;
date.tm_mon = month - 1 ; // note: zero indexed
date.tm_mday = day ; // note: not zero indexed
// Date, less 100 days
DatePlusDays( &date, -100 ) ;
// Show time/date using default formatting
std::cout << asctime( &date ) << std::endl ;
}
我假设这是为了某种练习,否则您将使用已经提供给您的时间课程。
您可以将时间存储为自某个日期以来的毫秒数。然后您可以添加适当的值并在调用类的访问器时将其转换为日期。
这是一个非常简单的方法的草图。为了简单起见,我假设d
要添加的天数 是正数。很容易将以下内容扩展到d
否定的情况。
要么d
小于 365,要么d
大于或等于 365。
如果d
小于 365:
m = 1;
while(d > numberOfDaysInMonth(m, y)) {
d -= numberOfDaysInMonth(m, y);
m++;
}
return date with year = y, month = m, day = d;
如果d
大于 365:
while(d >= 365) {
d -= 365;
if(isLeapYear(y)) {
d -= 1;
}
y++;
}
// now use the case where d is less than 365
或者,您可以用Julian 形式表示日期,然后只需添加到 Julian 形式并转换为 ymd 格式。
一种方法是将日期映射到日期的儒略数,进行整数运算,然后转换回来。
您会发现大量有关 julian 函数的资源。
试试这个功能。它正确计算加法或减法。dateTime 参数必须采用 UTC 格式。
tm* dateTimeAdd(const tm* const dateTime, const int& days, const int& hours, const int& mins, const int& secs) {
tm* newTime = new tm;
memcpy(newTime, dateTime, sizeof(tm));
newTime->tm_mday += days;
newTime->tm_hour += hours;
newTime->tm_min += mins;
newTime->tm_sec += secs;
time_t nt_seconds = mktime(newTime) - timezone;
delete newTime;
return gmtime(&nt_seconds);
}
并且有使用示例:
time_t t = time(NULL);
tm* utc = gmtime(&t);
tm* newUtc = dateTimeAdd(utc, -5, 0, 0, 0); //subtract 5 days
我知道这是一个非常古老的问题,但在处理日期和时间时,这是一个有趣且常见的问题。所以我想分享一些代码来计算新日期,而不使用 C++ 中的任何内置时间功能。
#include <iostream>
#include <string>
using namespace std;
class Date {
public:
Date(size_t year, size_t month, size_t day):m_year(year), m_month(month), m_day(day) {}
~Date() {}
// Add specified number of days to date
Date operator + (size_t days) const;
// Subtract specified number of days from date
Date operator - (size_t days) const;
size_t Year() { return m_year; }
size_t Month() { return m_month; }
size_t Day() { return m_day; }
string DateStr();
private:
// Leap year check
inline bool LeapYear(int year) const
{ return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); }
// Holds all max days in a general year
static const int MaxDayInMonth[13];
// Private members
size_t m_year;
size_t m_month;
size_t m_day;
};
// Define MaxDayInMonth
const int Date::MaxDayInMonth[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
//===========================================================================================
/// Add specified number of days to date
Date Date::operator + (size_t days) const {
// Maximum days in the month
int nMaxDays(MaxDayInMonth[m_month] + (m_month == 2 && LeapYear(m_year) ? 1 : 0));
// Initialize the Year, Month, Days
int nYear(m_year);
int nMonth(m_month);
int nDays(m_day + days);
// Iterate till it becomes a valid day of a month
while (nDays > nMaxDays) {
// Subtract the max number of days of current month
nDays -= nMaxDays;
// Advance to next month
++nMonth;
// Falls on to next year?
if (nMonth > 12) {
nMonth = 1; // January
++nYear; // Next year
}
// Update the max days of the new month
nMaxDays = MaxDayInMonth[nMonth] + (nMonth == 2 && LeapYear(nYear) ? 1 : 0);
}
// Construct date
return Date(nYear, nMonth, nDays);
}
//===========================================================================================
/// Subtract specified number of days from date
Date Date::operator - (size_t days) const {
// Falls within the same month?
if (0 < (m_day - days)) {
return Date(m_year, m_month, m_day - days);
}
// Start from this year
int nYear(m_year);
// Start from specified days and go back to first day of this month
int nDays(days);
nDays -= m_day;
// Start from previous month and check if it falls on to previous year
int nMonth(m_month - 1);
if (nMonth < 1) {
nMonth = 12; // December
--nYear; // Previous year
}
// Maximum days in the current month
int nDaysInMonth = MaxDayInMonth[nMonth] + (nMonth == 2 && LeapYear(nYear) ? 1 : 0);
// Iterate till it becomes a valid day of a month
while (nDays >= 0) {
// Subtract the max number of days of current month
nDays -= nDaysInMonth;
// Falls on to previous month?
if (nDays > 0) {
// Go to previous month
--nMonth;
// Falls on to previous year?
if (nMonth < 1) {
nMonth = 12; // December
--nYear; // Previous year
}
}
// Update the max days of the new month
nDaysInMonth = MaxDayInMonth[nMonth] + (nMonth == 2 && LeapYear(nYear) ? 1 : 0);
}
// Construct date
return Date(nYear, nMonth, (0 < nDays ? nDays : -nDays));
}
//===========================================================================================
/// Get the date string in yyyy/mm/dd format
string Date::DateStr() {
return to_string(m_year)
+ string("/")
+ string(m_month < 10 ? string("0") + to_string(m_month) : to_string(m_month))
+ string("/")
+ string(m_day < 10 ? string("0") + to_string(m_day) : to_string(m_day));
}
int main() {
// Add n days to a date
cout << Date(2017, 6, 25).DateStr() << " + 10 days = "
<< (Date(2017, 6, 25) /* Given Date */ + 10 /* Days to add */).DateStr() << endl;
// Subtract n days from a date
cout << Date(2017, 6, 25).DateStr() << " - 10 days = "
<< (Date(2017, 6, 25) /* Given Date */ - 10 /* Days to subract */).DateStr() << endl;
return 0;
}
Output
2017/06/25 + 10 days = 2017/07/05
2017/06/25 - 10 days = 2017/06/15
我建议首先编写一个例程,将年月日转换为自固定日期以来的天数,例如自 1.01.01 以来。还有一个对称的例程可以将其转换回来。
不要忘记正确处理闰年!
拥有这两个,您的任务将是微不足道的。
我知道这是近十年前提出的一个老问题。但是几天前我遇到了同样的任务,这是这里的答案
// C++ program to find date after adding
// given number of days.
#include<bits/stdc++.h>
using namespace std;
// Return if year is leap year or not.
bool isLeap(int y)
{
if (y%100 != 0 && y%4 == 0 || y %400 == 0)
return true;
return false;
}
// Given a date, returns number of days elapsed
// from the beginning of the current year (1st
// jan).
int offsetDays(int d, int m, int y)
{
int offset = d;
switch (m - 1)
{
case 11:
offset += 30;
case 10:
offset += 31;
case 9:
offset += 30;
case 8:
offset += 31;
case 7:
offset += 31;
case 6:
offset += 30;
case 5:
offset += 31;
case 4:
offset += 30;
case 3:
offset += 31;
case 2:
offset += 28;
case 1:
offset += 31;
}
if (isLeap(y) && m > 2)
offset += 1;
return offset;
}
// Given a year and days elapsed in it, finds
// date by storing results in d and m.
void revoffsetDays(int offset, int y, int *d, int *m)
{
int month[13] = { 0, 31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31 };
if (isLeap(y))
month[2] = 29;
int i;
for (i = 1; i <= 12; i++)
{
if (offset <= month[i])
break;
offset = offset - month[i];
}
*d = offset;
*m = i;
}
// Add x days to the given date.
void addDays(int d1, int m1, int y1, int x)
{
int offset1 = offsetDays(d1, m1, y1);
int remDays = isLeap(y1)?(366-offset1):(365-offset1);
// y2 is going to store result year and
// offset2 is going to store offset days
// in result year.
int y2, offset2;
if (x <= remDays)
{
y2 = y1;
offset2 = offset1 + x;
}
else
{
// x may store thousands of days.
// We find correct year and offset
// in the year.
x -= remDays;
y2 = y1 + 1;
int y2days = isLeap(y2)?366:365;
while (x >= y2days)
{
x -= y2days;
y2++;
y2days = isLeap(y2)?366:365;
}
offset2 = x;
}
// Find values of day and month from
// offset of result year.
int m2, d2;
revoffsetDays(offset2, y2, &d2, &m2);
cout << "d2 = " << d2 << ", m2 = " << m2
<< ", y2 = " << y2;
}
// Driven Program
int main()
{
int d = 14, m = 3, y = 2015;
int x = 366;
addDays(d, m, y, x);
return 0;
}
不知道这是否有帮助。我正在研究一个调度系统,该系统(在第一个简单草案中)将开始日期计算为截止日期 - 提前期天数。我处理了经过的秒数(自纪元以来),以便在未来的代码草案中实现更高的精度。
#include <iostream>
#include <ctime>
int main() {
// lead time in days
int lead_time = 20;
// assign a due_date of (midnight on) 3rd November 2020
tm tm_due_date = { 0, 0, 0, 3, 11, 2020-1900};
// convert due_date to seconds elapsed (since epoch)
time_t tt_due_date = mktime(&tm_due_date);
// subtract lead time seconds
tt_due_date -= 60 * 60 * 24 * lead_time;
// convert back (to local time)
tm *start_date = localtime(&tt_due_date);
// otput the result as something we can readily read
std::cout << asctime(start_date) << "\n";
}