C 或 C++ 中日历日期的算术(向给定日期添加 N 天)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15668638/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 19:37:01  来源:igfitidea点击:

Arithmetics on calendar dates in C or C++ (add N days to given date)

c++cdatedate-arithmetic

提问by vivek jain

I have been given a date, Which I am taking as an input like (day, month, year): 12, 03, 87.

我得到了一个日期,我将其作为输入,例如 (day, month, year): 12, 03, 87

Now I need to find out the date after ndays.

现在我需要在n几天后找出日期。

I have written code for this, But its not efficient. Can you please tell me any good logic which works faster and have less complexity.

我为此编写了代码,但效率不高。你能告诉我任何运行速度更快且复杂性更低的好的逻辑吗?

#include <stdio.h>

static int days_in_month[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int day, month, year;

unsigned short day_counter;

int is_leap(int y) {
    return ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0);
}

next_day()
{
    day += 1; day_counter++;
    if (day > days_in_month[month]) {
        day = 1;
        month += 1;
        if (month > 12) {
            month = 1;
            year += 1;
            if (is_leap(year)) {
                days_in_month[2] = 29;
            } else {
                days_in_month[2] = 28;
            }
        }
    }
}

set_date(int d, int m, int y) 
{
    m < 1 ? m = 1 : 0;
    m > 12 ? m = 12 : 0;
    d < 1 ? d = 1 : 0;
    d > days_in_month[m] ? d = days_in_month[m] : 0;
    if (is_leap(y)){
        days_in_month[2] = 29;
    } 
    else {
        days_in_month[2] = 28;
    }
    day = d;
    month = m;
    year = y;
}

skip_days(int x)
{
    int i;
    for (i=0;i<x;i++) next_day();
}

print_date()
{
    printf ("day: %d month: %d year: %d\n", day, month, year);
}

int main(int argc, char **argv)
{
    int i;

    set_date(5, 2, 1980);
    skip_days(40);
    day_counter = 0;
    /* after this call next_day each day */

    print_date();
    return 0;
}

回答by moooeeeep

Can you please tell me any good logic which works faster and have less complexity.

你能告诉我任何运行速度更快且复杂性更低的好的逻辑吗?

If this exact thing is indeed a performance critical part of your application, you're likely doing something wrong. For the sake of clarity and correctness, you should stick to the existing solutions. Select the one that is most appropriate to your development environment.

如果这个确切的东西确实是您的应用程序的性能关键部分,那么您可能做错了什么。为了清晰和正确,您应该坚持使用现有的解决方案。选择最适合您的开发环境的一种。



The C approach:

C 方法:

#include <stdio.h>
#include <time.h>

int main()
{        
    /* initialize */
    int y=1980, m=2, d=5;    
    struct tm t = { .tm_year=y-1900, .tm_mon=m-1, .tm_mday=d };
    /* modify */
    t.tm_mday += 40;
    mktime(&t);
    /* show result */
    printf("%s", asctime(&t)); /* prints: Sun Mar 16 00:00:00 1980 */
    return 0;
}

The C++ without using Boost approach:

不使用 Boost 方法的 C++:

#include <ctime>
#include <iostream>

int main()
{        
    // initialize
    int y=1980, m=2, d=5;
    std::tm t = {};
    t.tm_year = y-1900;
    t.tm_mon  = m-1;
    t.tm_mday = d;
    // modify
    t.tm_mday += 40;
    std::mktime(&t);
    // show result
    std::cout << std::asctime(&t); // prints: Sun Mar 16 00:00:00 1980
}

The Boost.Date_Timeapproach:

的Boost.Date_Time方法:

#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>

int main()
{
    using namespace boost::gregorian;
    // initialize
    date d(1980,2,5);
    // modify
    d += days(40);
    // show result
    std::cout << d << '\n'; // prints: 1980-Mar-16
}

回答by han

The standard library mktimefunction includes a trick to make it easy to add a number of months or days into a given date: you can give it a date such as "45th of February" or "2nd day of the 40th month" and mktimewill normalize it into a proper date. Example:

标准库mktime函数包含一个技巧,可以轻松地将月份或天数添加到给定日期中:您可以为其指定一个日期,例如“2 月 45 日”或“第 40 个月的第 2 天”,然后mktime将其标准化进入适当的日期。例子:

#include <time.h>
#include <stdio.h>

int main() {
    int y = 1980;
    int m = 2;
    int d = 5;
    int skip = 40;

    // Represent the date as struct tm.                                                           
    // The subtractions are necessary for historical reasons.
    struct tm  t = { 0 };
    t.tm_mday = d;
    t.tm_mon = m-1;
    t.tm_year = y-1900;

    // Add 'skip' days to the date.                                                               
    t.tm_mday += skip;
    mktime(&t);

    // Print the date in ISO-8601 format.                                                         
    char buffer[30];
    strftime(buffer, 30, "%Y-%m-%d", &t);
    puts(buffer);
}

Compared to doing the arithmetic in seconds using time_t, this approach has the advantage that daylight savings transitions do not cause any problems.

与使用 以秒为单位进行算术相比time_t,这种方法的优点是夏令时转换不会引起任何问题。

回答by bames53

Here's what the solution looks like using algorithms published hereby Howard Hinnant.

以下是使用Howard Hinnant在此处发布的算法的解决方案。

int main() {
    int day_count = days_from_civil(1980, 5, 2);
    auto [year, month, day] = civil_from_days(day_count + 40);
    printf("%04i-%02i-%02-i\n", (int)year, (int)month, (int)day);
}

New date functionality has been approved for inclusion in C++20, though with a different API. A C++20 solution will probably look something like:

新的日期功能已被批准包含在 C++20 中,但具有不同的 API。C++20 解决方案可能类似于:

#include <chrono>

int main() {
    using namespace std::chrono;
    sys_days in_days = year_month_day{1980y, may, 2d};
    std::cout << year_month_day(in_days + days(40)) << '\n';
}

回答by SajithP

Can be implemented using C++ operators and in a quite OOP way by representing date as a class.

可以使用 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;

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

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

    return 0;
}

Output
2017/06/25 + 10 days = 2017/07/05

回答by lcs

Just add to a time_t object for how many days you want.

只需将您想要的天数添加到 time_t 对象即可。

#define SECOND              1
#define MINUTE              60 * SECOND
#define HOUR                60 * MINUTE
#define DAY                 24 * HOUR





time_t curTime;
time_t futureTime;

time( & curTime );

futureTime = curTime + (5 * DAY);

struct tm * futureDate = gmtime(&futureTime);
std::cout<<"5 days from now will be: "<<futureDate->tm_mday<<"/"<<futureDate->tm_mon+1<<"/"<<futureDate->tm_year+1900<<std::endl;

回答by eyalm

the easiest trick is to use time_ttype and corresponding functions.

最简单的技巧是使用time_t类型和相应的函数。

mktimewill convert tm structure to time_t. which is an integer value counting the seconds starting 01-Jan-1970.

mktime将 tm 结构转换为time_t. 这是一个整数值,从 1970 年 1 月 1 日开始计算秒数。

After you have a time_tvalue just add the seconds count you need (86400 per day).

获得time_t值后,只需添加所需的秒数(每天 86400)。

To convert back, use gmtimeor localtime

要转换回来,请使用gmtimelocaltime

回答by andy

It might be easier to do the math using seconds since the epoch instead of manipulating the date fields directly.

使用自纪元以来的秒数进行数学计算可能更容易,而不是直接操作日期字段。

For example, this program prints the date 7 daysfrom now:

例如,这个程序打印7 天后的日期:

#include <stdio.h>
#include <time.h>

main()
{
    time_t t;
    struct tm *tmp;

    time(&t);

    /* add a week to today */
    t += 7 * 24 * 60 * 60;

    tmp = localtime(&t);
    printf("%02d/%02d/%02d\n", tmp->tm_mon+1, tmp->tm_mday,
        tmp->tm_year % 100);
}

回答by ARJUN

This code will print the date coming after 10 days. Change the value to N for a user-defined number.

此代码将打印 10 天后的日期。将用户定义的数字的值更改为 N。

#include< iostream.h>

#include< conio.h>

struct date{int d,m,y;};

void main()

    {

    date d1;

    void later (date);

    cout<<"ENTER A VALID DATE (dd/mm/yy)";

    cin>>d1.d>>d1.m>>d1.y;

    later(d1);

    getch();

    }

    void later(date d1)

    {

    int mdays[12]={31,28,31,30,31,30,31,31,30,31,30,31};

    if(((d1.y%4==0) && (d1.y%100!=0))||(d1.y%400==0))
    mdays[1]=29;
    d1.d=d1.d+10;

    if(d1.d>mdays[d1.m-1])

    {

    d1.d=d1.d-mdays[d1.m-1];

    d1.m++;

    if(d1.m>12)

    {d1.m=1;

    d1.y++;

    }

    }
    cout<<"DATE AFTER TEN DAYS IS "<<d1.d<<"\t"<<d1.m<<"\t"<<d1.y;

    getch();

    }