web-dev-qa-db-ja.com

日付間の違いを判断する

プログラムで日付(2003年2月2日など)を取得し、うるう年を除く別の日付(2012年4月2日など)との違いを示す方法を見つけようとしています。これまでのところ、「日」を引くだけで、日付が同じ月にあるかどうかしかわかりませんでした。このプログラムでは、「月」、「日」、「年」の2組の整数を使用します。私はここからどこへ行くのか途方に暮れています。これは私の割り当ての完全にオプションの部分ですが、それを機能させる方法についてのアイデアを取得したいと思います。面倒に思えますが、考えていない簡単な数式があるのではないでしょうか。

申し訳ありませんが、この部分の既存のコードはありません。残りの割り当てでは、ユーザーに日付を入力させてから1日を加算および減算するだけです。

11
Hydlide

これは、y/m/dで日付の差を計算するための完全なコードです。

toおよびfromdateタイプであり、月と日が-から始まると仮定します。 1(Qtと同様):

static int increment[12] = { 1, -2, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1 };

int daysInc = 0;
if (to.day() - from.day() < 0)
{
    int month = to.month() - 2; // -1 from zero, -1 previous month.
    if (month < 0)
        month = 11; // Previous month is December.
    daysInc = increment[month];
    if ( (month == 1) && (to.year()%4 == 0) )
        daysInc++; // Increment days for leap year.
}

int total1 = from.year()*360 + from.month()*30 + from.day();
int total2 = to.year()*360 + to.month()*30 + to.day();
int diff = total2 - total1;
int years = diff/360;
int months = (diff - years*360)/30;
int days = diff - years*360 - months*30 + daysInc;

// Extra calculation when we can pass one month instead of 30 days.
if (from.day() == 1 && to.day() == 31) {
    months--;
    days = 30;
}

このアルゴリズムを試しましたが、問題なく動作しています。使用/理解に問題がある場合はお知らせください。

7
Borzh

標準ライブラリだけを使用すると、適度に異常な日付構造を任意のゼロ点からの秒数に変換できます。次に、減算して日数に変換します。

#include <ctime>

// Make a tm structure representing this date
std::tm make_tm(int year, int month, int day)
{
    std::tm tm = {0};
    tm.tm_year = year - 1900; // years count from 1900
    tm.tm_mon = month - 1;    // months count from January=0
    tm.tm_mday = day;         // days count from 1
    return tm;
}

// Structures representing the two dates
std::tm tm1 = make_tm(2012,4,2);    // April 2nd, 2012
std::tm tm2 = make_tm(2003,2,2);    // February 2nd, 2003

// Arithmetic time values.
// On a posix system, these are seconds since 1970-01-01 00:00:00 UTC
std::time_t time1 = std::mktime(&tm1);
std::time_t time2 = std::mktime(&tm2);

// Divide by the number of seconds in a day
const int seconds_per_day = 60*60*24;
std::time_t difference = (time1 - time2) / seconds_per_day;    

// To be fully portable, we shouldn't assume that these are Unix time;
// instead, we should use "difftime" to give the difference in seconds:
double portable_difference = std::difftime(time1, time2) / seconds_per_day;

Boost.Date_Timeの使用は、少し奇妙ではありません。

#include "boost/date_time/gregorian/gregorian_types.hpp"

using namespace boost::gregorian;
date date1(2012, Apr, 2);
date date2(2003, Feb, 2);
long difference = (date1 - date2).days();

面倒に思えますが、考えていない簡単な数式があるのではないでしょうか。

確かに面倒ですが、自分で計算したい場合は があります。

15
Mike Seymour

あなたは数式を探しているので、それはあなたがあなたの問題の解決策を見つけるのを助けるでしょう。 Yを年、Mを月、Dを日とします。両方の日付に対してこの計算を行います。

合計= Y * 365 + M * 30 + D、次に、対応する日付の2つの合計の差を求めます。

30にM値を掛けるときは、その月の日数を指定する必要があります。 #define値またはifループでそれを行うことができます。同様に、366にYを掛けることで、うるう年についても行うことができます。

これがあなたを助けることを願っています....

7
Revathy

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

chrono-互換性のある低レベルの日付アルゴリズム

{年、月、日}のトリプルを日数のシリアルカウントに変換するための数式があります。これを使用して、次のように2つの日付間の日数を計算できます。

std::cout << days_from_civil(2012, 4, 2) - days_from_civil(2003, 2, 2) << '\n';

出力:

3347

このペーパーはハウツーマニュアルであり、ライブラリではありません。 C++ 14を使用して式を示します。各数式には詳細な説明と派生が付属しており、数式がどのように機能するかを知りたい場合にのみ読む必要があります。

数式は非常に効率的で、非常に広い範囲で有効です。たとえば、32ビット演算を使用すると、+/-500万年(十分すぎるほど)。

連続日数は、1970年の正月から(または負の値の場合はそれ以前)の日数であり、式を nix Time およびstd::chrono::system_clockのすべての既知の実装と互換性があります。

days_from_civil アルゴリズムは目新しいものではなく、同じことを行うための他のアルゴリズムと非常によく似ているはずです。ただし、逆に、日数を{年、月、日}のトリプルに戻すのは難しいです。これは civil_from_days によって文書化された式であり、これほどコンパクトな他の式は見たことがありません。

このペーパーには、 典型的な計算std::chrono相互運用性 、および広範な 単体テスト が+/- 100万を超える正確さを示す使用例が含まれています。年( 先発グレゴリオ暦 を使用)。

すべての数式とソフトウェアはパブリックドメインです。

6
Howard Hinnant

別の方法があります...

  • 2つの日付がある場合、前の日付の年を参照年とします。
  • 次に、noを計算します。与えられた2つの日付のそれぞれとその1/1/<その年>の間の日数
  • 特定の月までの経過日数を示す別の関数を保持します。
  • これら2つの絶対差いいえ。日数は、指定された2つの日付の差を示します。
  • また、うるう年を考慮することを忘れないでください!

コード:

#‎include‬<stdio.h>
#include<math.h>
typedef struct
{
    int d, m, y;
} Date;
int isLeap (int y)
{
    return (y % 4 == 0) && ( y % 100 != 0) || (y % 400 == 0);
}
int diff (Date d1, Date d2)                         //logic here!
{
    int dd1 = 0, dd2 = 0, y, yref;                  //dd1 and dd2 store the <i>no. of days</i> between d1, d2 and the reference year
    yref = (d1.y < d2.y)? d1.y: d2.y;               //that <b>reference year</b>
    for (y = yref; y < d1.y; y++)
        if (isLeap(y))                              //check if there is any leap year between the reference year and d1's year (exclusive)
            dd1++;
    if (isLeap(d1.y) && d1.m > 2) dd1++;                //add another day if the date is past a leap year's February
    dd1 += daysTill(d1.m) + d1.d + (d1.y - yref) * 365;     //sum up all the tiny bits (days)
    for (y = yref; y < d2.y; y++)                       //repeat for d2
        if(isLeap(y))
            dd2++;
    if (isLeap(y) && d2.m > 2) dd2++;
    dd2 += daysTill(d2.m) + d2.d + (d2.y - yref) * 365;
    return abs(dd2 - dd1);                          //return the absolute difference between the two <i>no. of days elapsed past the reference year</i>
}
int daysTill (int month)                            //some logic here too!!
{
    int days = 0;
    switch (month)
    {
        case 1: days = 0;
        break;
        case 2: days = 31;
        break;
        case 3: days = 59;
        break;
        case 4: days = 90;      //number of days elapsed before April in a non-leap year
        break;
        case 5: days = 120;
        break;
        case 6: days = 151;
        break;
        case 7: days = 181;
        break;
        case 8: days = 212;
        break;
        case 9: days = 243;
        break;
        case 10:days = 273;
        break;
        case 11:days = 304;
        break;
        case 12:days = 334;
        break;
    }
    return days;
}
main()
{
    int t;          //no. of test cases
    Date d1, d2;    //d1 is the first date, d2 is the second one! obvious, duh!?
    scanf ("%d", &t);
    while (t--)
    {
        scanf ("%d %d %d", &d1.d, &d1.m, &d1.y);
        scanf ("%d %d %d", &d2.d, &d2.m, &d2.y);
        printf ("%d\n", diff(d1, d2));
    }
}

標準入力:

1
23 9 1960
11 3 2015

標準出力:

19892

動作中のコード: https://ideone.com/RrADFR

より良いアルゴリズム、最適化、編集はいつでも歓迎です!

2
skrtbhtngr

どのプラットフォームを使用しているのかわかりませんか? Windows、Linux?ただし、プラットフォームに依存しないソリューションが必要であり、言語は標準のC++であると仮定しましょう。

ライブラリを使用できる場合は、Boost :: Date_Timeライブラリ(http://www.boost.org/doc/libs/1_49_0/doc/html/date_time.html)を使用できます。

ライブラリを使用して割り当てを解決できない場合は、共通の単純な根拠を見つける必要があります。たぶん、すべての日付を秒に変換するか、日を差し引いて、それを再びデータに変換することができます。日または月を整数として減算しても、残りを考慮しない限り、誤った結果が生じるため、役に立ちません。お役に立てば幸いです。

Dbrank0が指摘したように。 :)

2

自分で行う必要がある場合、これを非常に簡単に行う1つの方法は、日付を ユリウス日 に変換することです。そのリンクで数式を取得し、変換以降は、1日が1単位であるフロートのみを操作します。

1
dbrank0

DateTime クラスを確認する必要があります。

また、C++構文の場合は msdn reference です。

0
nikhil