从日期中添加或减去天数的算法?

发布于 2024-08-23 02:55:23 字数 123 浏览 12 评论 0原文

我正在尝试编写一个 Date 类以尝试学习 C++。

我正在尝试找到一种算法来添加或减去日期的天数,其中日从 1 开始,月从 1 开始。事实证明它非常复杂,谷歌并没有出现太多,

有谁知道算法这是哪个?

I'm trying to write a Date class in an attempt to learn C++.

I'm trying to find an algorithm to add or subtract days to a date, where Day starts from 1 and Month starts from 1. It's proving to be very complex, and google doesn't turn up much,

Does anyone know of an algorithm which does this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

彼岸花似海 2024-08-30 02:55:23

最简单的方法是实际编写两个函数,一个将日期转换为给定开始日期的天数,另一个将转换回日期。一旦日期被表示为天数,对其进行添加或减去就很简单了。

您可以在这里找到算法: http://alcor.concordia.ca/~gpkatch/gdate-algorithm.html

The easiest way is to actually write two functions, one which converts the day to a number of days from a given start date, then another which converts back to a date. Once the date is expressed as a number of days, it's trivial to add or subtract to it.

You can find the algorithms here: http://alcor.concordia.ca/~gpkatch/gdate-algorithm.html

爱本泡沫多脆弱 2024-08-30 02:55:23

您实际上并不需要这样的算法(至少不是名副其实的算法),标准库可以完成大部分繁重的工作;日历计算是出了名的棘手。只要您不需要早于 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 ;
}

You don't really need an algorithm as such (at least not something worthy of the name), the standard library can do most of the heavy lifting; calender calculations are notoriously tricky. So long as you don't need dates earlier than 1900, then:

#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 ) ; ;
}

Example usage:

#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 ;
}
毁梦 2024-08-30 02:55:23

我假设这是为了某种练习,否则您将使用已经提供给您的时间课程。

您可以将时间存储为自特定日期以来的毫秒数。然后,您可以添加适当的值,并在调用类的访问器时将其转换为日期。

I'm assuming this is for some kind of an exercise, otherwise you would use a time class that's already provided to you.

You could store your time as the number of milliseconds since a certain date. And then you can add the appropriate value and convert from that to the date upon calling the accessors of your class.

余罪 2024-08-30 02:55:23

这是一个非常简单的方法的草图。为了简单起见,我假设要添加的天数 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< /code> 大于 365:

while(d >= 365) {
    d -= 365;
    if(isLeapYear(y)) {
        d -= 1;
    }
    y++;
}
// now use the case where d is less than 365

或者,您可以用 儒略形式 然后仅添加到 Julian 形式并转换为 ymd 格式。

Here's a sketch of a very simple approach. For simplicity of ideas I will assume that d, the number of days to add, is positive. It is easy to extend the below to cases where d is negative.

Either d is less than 365 or d is greater than or equal to 365.

If d is less than 365:

m = 1;
while(d > numberOfDaysInMonth(m, y)) {
    d -= numberOfDaysInMonth(m, y);
    m++;
}
return date with year = y, month = m, day = d;

If d is greater than 365:

while(d >= 365) {
    d -= 365;
    if(isLeapYear(y)) {
        d -= 1;
    }
    y++;
}
// now use the case where d is less than 365

Alternatively, you could express the date in, say, Julian form and then merely add to the Julian form and conver to ymd format.

执着的年纪 2024-08-30 02:55:23

一种方法是将日期映射到日期的儒略数,进行整数运算,然后转换回来。

您将找到大量有关朱利安函数的资源。

One approach is to map the date to the Julian number of the date, do your integer operations and then transform back.

You will find plenty of resources for the julian functions.

桃扇骨 2024-08-30 02:55:23

我建议首先编写一个例程,将年月日转换为自固定日期(例如,自 1.01.01 以来)的天数。以及一个将其转换回来的对称例程。

不要忘记正确处理闰年!

有了这两个,你的任务就变得微不足道了。

I would suggest writing first a routine which converts year-month-day into a number of days since fixed date, say, since 1.01.01. And a symmetric routine which would convert it back.

Don't forget to process leap years correctly!

Having those two, your task would be trivial.

梦里南柯 2024-08-30 02:55:23

试试这个功能。它可以正确计算加法或减法。 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

Try this function. It correctly calculates additions or subtractions. dateTime argument must be in UTC format.

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);
}

And there are example of using:

time_t t = time(NULL);
tm* utc = gmtime(&t);
tm* newUtc = dateTimeAdd(utc, -5, 0, 0, 0); //subtract 5 days
你的笑 2024-08-30 02:55:23

我知道这是一个非常古老的问题,但在处理日期和时间时,这是一个有趣且常见的问题。所以我想分享一些计算新日期的代码,而不使用 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

I know this is a very old question but it's an interesting and some common one when it comes to working with dates and times. So I thought of sharing some code which calculates the new date without using any inbuilt time functionality in 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
☆獨立☆ 2024-08-30 02:55:23

我知道这是一个近十年前提出的老问题。但几天前我遇到了同样的作业,这是答案,如 这里

// 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; 
} 

I know it is an old question asked almost a decade before. But a few days before I came across the same for an assignment, and here is the answer as in here

// 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; 
} 
孤单情人 2024-08-30 02:55:23

不知道这是否有帮助。我正在开发一个调度系统(在第一个简单草案中),该系统将开始日期计算为到期日 - 天数提前期。我使用了几秒钟的时间(自纪元以来),以便在未来的代码草案中获得更高的精度。

#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";
}

Don't know if this helps or not. I was working on a scheduling system which (in the first simple draft) calculated start date as due date - days lead time. I worked with seconds elapsed (since epoch) to allow greater precision in future drafts of the code.

#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";
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文