22

C#、Java の例を見ましたが、C++ の場合、2 つの日付の間の日数を計算する解決策が見つかりません。

たとえば、2012-01-24 と 2013-01-08 の間

ありがとう!

4

5 に答える 5

27

これは一つの方法です。

#include <iostream>
#include <ctime>

int main()
{
    struct std::tm a = {0,0,0,24,5,104}; /* June 24, 2004 */
    struct std::tm b = {0,0,0,5,6,104}; /* July 5, 2004 */
    std::time_t x = std::mktime(&a);
    std::time_t y = std::mktime(&b);
    if ( x != (std::time_t)(-1) && y != (std::time_t)(-1) )
    {
        double difference = std::difftime(y, x) / (60 * 60 * 24);
        std::cout << std::ctime(&x);
        std::cout << std::ctime(&y);
        std::cout << "difference = " << difference << " days" << std::endl;
    }
    return 0;
}

私の出力

Thu Jun 24 01:00:00 2004
Mon Jul 05 01:00:00 2004
difference = 11 days

元の著者の投稿への参照は次のとおりです

于 2013-01-08T15:58:39.333 に答える
18

日付をエポックからの日数を示す整数に変換してから減算します。この例ではRata Dieを選択しました。アルゴリズムの説明は < http://mysite.verizon.net/aesir_research/date/rata.htm > にあります。

int
rdn(int y, int m, int d) { /* Rata Die day one is 0001-01-01 */
    if (m < 3)
        y--, m += 12;
    return 365*y + y/4 - y/100 + y/400 + (153*m - 457)/5 + d - 306;
}

int days = rdn(2013, 1, 8) - rdn(2012, 1, 24);
于 2013-01-08T21:20:13.787 に答える
16

古い質問に対する新しい回答:

このC++11/C++14 ヘッダーのみの日付ライブラリを使用して、次のように記述できるようになりました。

#include "date.h"
#include <iostream>

int
main()
{
    using namespace date;
    using namespace std;
    auto x = 2012_y/1/24;
    auto y = 2013_y/1/8;
    cout << x << '\n';
    cout << y << '\n';
    cout << "difference = " << (sys_days{y} - sys_days{x}).count() << " days\n";
}

どの出力:

2012-01-24
2013-01-08
difference = 350 days

このライブラリに依存したくない場合は、上記の日付ライブラリが使用するのと同じ日付アルゴリズムを使用して、独自に作成できます。それらは、このペーパーに記載されています: chrono-Compatible Low-Level Date Algorithms . この例で実行されているこの論文のアルゴリズムは次のとおりです。

// Returns number of days since civil 1970-01-01.  Negative values indicate
//    days prior to 1970-01-01.
// Preconditions:  y-m-d represents a date in the civil (Gregorian) calendar
//                 m is in [1, 12]
//                 d is in [1, last_day_of_month(y, m)]
//                 y is "approximately" in
//                   [numeric_limits<Int>::min()/366, numeric_limits<Int>::max()/366]
//                 Exact range of validity is:
//                 [civil_from_days(numeric_limits<Int>::min()),
//                  civil_from_days(numeric_limits<Int>::max()-719468)]
template <class Int>
constexpr
Int
days_from_civil(Int y, unsigned m, unsigned d) noexcept
{
    static_assert(std::numeric_limits<unsigned>::digits >= 18,
             "This algorithm has not been ported to a 16 bit unsigned integer");
    static_assert(std::numeric_limits<Int>::digits >= 20,
             "This algorithm has not been ported to a 16 bit signed integer");
    y -= m <= 2;
    const Int era = (y >= 0 ? y : y-399) / 400;
    const unsigned yoe = static_cast<unsigned>(y - era * 400);      // [0, 399]
    const unsigned doy = (153*(m + (m > 2 ? -3 : 9)) + 2)/5 + d-1;  // [0, 365]
    const unsigned doe = yoe * 365 + yoe/4 - yoe/100 + doy;         // [0, 146096]
    return era * 146097 + static_cast<Int>(doe) - 719468;
}

このアルゴリズムの仕組み、単体テスト、有効範囲の詳細については、クロノ互換の低レベル日付アルゴリズムを参照してください

このアルゴリズムは、グレゴリオ暦を前後に無期限に拡張する先発グレゴリオ暦をモデル化します。他の暦 (ユリウス暦など) をモデル化するには、ここに示すような他のアルゴリズムが必要になります。他のカレンダーを設定し、同じシリアル エポック (これらのアルゴリズムは、Unix 時間エポックでもある 1970-01-01 グレゴリオ暦を使用します) に同期すると、任意の 2 つの日付間の日数だけでなく、また、モデル化した 2 つのカレンダー間でも同様です。

これにより、ユリウス暦からグレゴリオ暦への切り替えの日付をハードコーディングする必要がなくなります。入力データがどのカレンダーに対して参照されているかを知る必要があるだけです。

あいまいな歴史的文書の日付は、それぞれユリウス暦またはグレゴリオ暦を示すために、旧式 / 新式の注釈が付けられることがあります。

日付の時刻についても懸念がある場合は、この同じ日付ライブラリを、、、、およびを<chrono>使用するライブラリとシームレスに統合して、現在の日付と時刻を取得します。hoursminutessecondsmillisecondsmicrosecondsnanosecondssystem_clock::now()

タイム ゾーンが気になる場合は、追加の (別の)タイム ゾーン ライブラリが日付ライブラリの上に書き込まれ、 IANA タイム ゾーン データベースを使用してタイム ゾーンを処理します。必要に応じて、タイムゾーン ライブラリにはうるう秒を含む計算機能もあります。

于 2015-08-10T19:54:11.427 に答える
6

ブーストdate_timeライブラリを試すことができます

于 2013-01-08T15:55:44.637 に答える
0

独自の関数を作成しないようにするには、Boostのdate_timeを使用できます。

于 2013-01-08T21:53:37.010 に答える