DOBON.NET DOBON.NETプログラミング掲示板過去ログ

DateDiffをC#で使いたい。

環境/言語:[C# XP]
分類:[.NET]

こんにちは。
VBでいうDateDiff関数に似たものはC#にはないのでしょうか?

12/1と10/1を比較して 2 という数値が欲しいのです。

TimeSpan型を使って

TimeSpan ts = Date1 - Date2

ts.Days で日数は取ることはできますが、「月」「年」などはどのようにして
取得すればいいのでしょうか?

よろしくお願いします。
■No7944に返信(ああああさんの記事)
> こんにちは。
> VBでいうDateDiff関数に似たものはC#にはないのでしょうか?
>
> 12/1と10/1を比較して 2 という数値が欲しいのです。
>
> TimeSpan型を使って
>
> TimeSpan ts = Date1 - Date2
>
> ts.Days で日数は取ることはできますが、「月」「年」などはどのようにして
> 取得すればいいのでしょうか?
>
> よろしくお願いします。
>

こんにちは 平ちゃんです。
Date1、Date2 から年月日をint で取得し引き算した方が簡単と思います。
ただ 詳細な検討はしていません。どちらかと言うと直感です。

(例)
対象日 2004年3月5日
基準日 2004年1月10日

日の計算
 負になるので対象月(この場合1月)の日数(1月は31日)を5日に加えて
 36とし36−10=26日
 対象月の日数は 翌月の1日をDatetime1とすると
 Datetime1=Datetime1.AddDay(-1) で日部分を取得すればできます。
月の計算
 3月ですが日の計算に使用したので2月となる。
 2−1=1
年の計算
 2004−2004 =0

結果 1月26日(1月と26日と読む?)
■No7946に返信(平ちゃんさんの記事)
> 負になるので対象月(この場合1月)の日数(1月は31日)を5日に加えて
初め、拝見した時に「1月」を、違う"読み"で解釈してました (-_-;)
日本語って難しいですね... (こんな誤解するのは私だけかも...)

> Date1、Date2 から年月日をint で取得し引き算した方が簡単と思います。
そうですね、それしかないでしょう。
「日数」からじゃ、"またぐ月"によって、1月(ひとつき)がズレてしまいますからね。

> 負になるので対象月(この場合1月)の日数(1月は31日)を5日に加えて
> 36とし36−10=26日
この手法を毎回やるのは面倒なので (1月(いちがつ)とも限らない)
関数化してみると良い感じになりますね。

     :
     :
     :

■No7944に返信(ああああさんの記事)
> VBでいうDateDiff関数に似たものはC#にはないのでしょうか?
DateDiff関数と同じ動きのメソッドはないです。

> TimeSpan ts = Date1 - Date2
System.DateTime.Subtractして、TimeSpanを取得しても日数しか取得できません。
となると、自作で作るほかないでしょうね。

> 「月」「年」などはどのようにして取得すればいいのでしょうか?
暦上の「年」と「月」のスパンだけで良いなら、比較的簡単にできますよ。



Source:--------------------------------------------------------------------

private string GetDateSpan(DateTime bigDate, DateTime smallDate) {
    int iYear, iMonth, iDay;

    iYear  = bigDate.Year  - smallDate.Year;
    iMonth = bigDate.Month - smallDate.Month;
    iDay   = bigDate.Day   - (smallDate.Day - 1);

    if (iDay < 0) {
        iMonth--;
    }

    if (iMonth < 0) {
        iYear--;
        iMonth += 12;
    }

    return iYear.ToString() + '年' + iMonth.ToString() + '月';
}

---------------------------------------------------------------------------

ちなみに、

> iDay = bigDate.Day - (smallDate.Day - 1);

1月(ひとつき)は、比較する日付の前日までを指すので、こうなってます。
つまり、("2004/05/04" - "2003/05/03") == 1年 が正しいそうです。



# ベタ打ちで書きました... 間違いがありましたらフォロー宜しくです。
■No7949に返信(java.lang.Nullpoさんの記事)

java.lang.Nullpoさん こんにちは
私の案は安直すぎたと反省し検討、確認しました。

> ちなみに、
>
>>iDay = bigDate.Day - (smallDate.Day - 1);
>
> 1月(ひとつき)は、比較する日付の前日までを指すので、こうなってます。
> つまり、("2004/05/04" - "2003/05/03") == 1年 が正しいそうです。
>

java.lang.Nullpoさんの通りだと思いますが DateTime.Add...メソッドは
次のように計算します。
("2004/05/04"+ 1日) == "2004/05/05"
("2004/05/05" + 1月) == "2004/06/05"
("2004/05/05" + 1年) == "2005/05/05"

これに合わせると("2004/05/04" - "2003/05/03") == 1年と1日になります。
しつこいですが ("2003/05/03"+ 1年と1日) == "2004/05/04"

ですので計算は iDay = bigDate.Day - smallDate.Day ; で行い
最後の1日はお好みに応じて調整して頂いた方がいいかと。

この方式で日まで計算できるソースを書いてみました。
(java.lang.Nullpoさんを参考にさせていただきました。)

private string GetDateSpan(DateTime bigDate, DateTime smallDate)
{
int iYear=0;
int iMonth=0;
int iDay=0;

//iDay = bigDate.Day - (smallDate.Day - 1);
iDay = bigDate.Day - smallDate.Day;
if (iDay < 0)
{
//smallDate の当月の日数を計算
DateTime nextMonth = smallDate.AddMonths(1); //次の月
DateTime temp = new DateTime(nextMonth.Year,nextMonth.Month,1); //smallDate の次の月の1日
int monthdays = temp.AddDays(-1).Day;
//これで日数の差の計算ができます。
iDay += monthdays;

iMonth--;
}

iMonth = iMonth + bigDate.Month - smallDate.Month;
if (iMonth < 0)
{
iYear--;
iMonth += 12;
}

iYear = iYear + bigDate.Year - smallDate.Year;

return iYear.ToString() + '年' + iMonth.ToString() + '月' + iDay.ToString() + '日';
}


*********
結果は日付により±1日の誤差がでました。
誤差とは 小さい日付 + 計算結果年月日 = 大きい日付 になるはずが
大きい日付 が ±1日 のずれを生じる場合がありました。
(大抵は正確に戻します)
ちなみに次の計算は計算結果年月日を DateTime.Add...する順序が(日、月、年) か (年、月、日) かで 大きい日付 が1日違ってきます。
( "2004/12/9"-"2003/12/10" ) = "11/30"
( "2004/12/31"-"2004/11/10" ) = "1/21"


まあ、簡易的な計算なのでこんなもんかなあと。
正確に計算するのは大変と思います。
あとは ああああさんの プログラムの仕様で判断してください。
返信ありがとうございます。
参考になりました。

ただ、年月を取る、というよりは
差分が欲しいのです。

同年10/5 と 8/25 を比較して 2、
2003/12/1 と  2004/1/15 を比較して 1というint型が欲しいのです。

私の質問が紛らわしくてすいません。
■No7953に返信(平ちゃんさんの記事)

> ですので計算は iDay = bigDate.Day - smallDate.Day ; で行い
> 最後の1日はお好みに応じて調整して頂いた方がいいかと。

... (;--)
私が言っているのは「○年△月 経過」を表す時の話です。

例を挙げると、「勤続年数」を算出する時が"コレ"に当たります。
15日締め16日始めの会社では、16日〜翌月15日が 勤続1月(ひとつき) に当たります。
16日〜翌月16日で初めて 勤続1月(ひとつき) とする会社はあるんでしょうか?
数々この手の業務はやってきましたが、聞いたことないですね < 少なくとも私は
(いや、どっかにあるかもしれないけど、一般的ではないでしょう)

今回の質問者の意図を勝手に先読みしているかもしれませんが、
○年△月 という形式で求めたい時は通常コレにあたると思ったわけです。


ときに、

---------------------------------------------------------------------------
■No7944に返信(ああああさんの記事)
> 12/1と10/1を比較して 2 という数値が欲しいのです。
---------------------------------------------------------------------------

12/01 と 10/02 を比較した時はどうするつもりなんでしょ?
勤続年数などの概念なら、これも「2」という解になりますが? > 元質問者さま


> java.lang.Nullpoさんの通りだと思いますが DateTime.Add...メソッドは
> 次のように計算します。
> ("2004/05/04"+ 1日) == "2004/05/05"
> ("2004/05/05" + 1月) == "2004/06/05"
> ("2004/05/05" + 1年) == "2005/05/05"
> これに合わせると("2004/05/04" - "2003/05/03") == 1年と1日になります。
> しつこいですが ("2003/05/03"+ 1年と1日) == "2004/05/04"

で、DateTime.Addxxx() メソッドと、"コレ"を比較されても...
ということで、反論じみた投稿をしましたが、気分を悪くされたらごめんなさい。

まあ、上記の件、これを知った上での回答だと思って欲しかったわけです。
そのためにも、わざわざ注釈で書いたのですがね...。
当方も、文章書くのが下手なので、誤解されても当然ですが。

> ちなみに次の計算は計算結果年月日を DateTime.Add...する順序が(日、月、年)
> か (年、月、日) かで 大きい日付 が1日違ってきます。
> ( "2004/12/9"-"2003/12/10" ) = "11/30"
> ( "2004/12/31"-"2004/11/10" ) = "1/21"
> まあ、簡易的な計算なのでこんなもんかなあと。
> 正確に計算するのは大変と思います。

誤差があることも問題な気がしますが、元質問者さまが、

--------------------------------------------------------------------------
■No7944に返信(ああああさんの記事)
> 「月」「年」などはどのようにして取得すればいいのでしょうか?
--------------------------------------------------------------------------

と言ってたりするので「日」は必要ないのでは? と思います。
すいません。ああああです。
紹介していただいた関数を改良すればできる事でした。
本当にありがとうございます。
もっと簡単にできる事だとタカをくくっていたのですが、
結構難しいですね・・。

ありがとうございました。
>12/01 と 10/02 を比較した時はどうするつもりなんでしょ?
>勤続年数などの概念なら、これも「2」という解になりますが? > 元質問者さま

その通りです。
12/1と 10/18 日を比較しても「2」というint型が欲しいです。
DateDiffの月差分が欲しいといった感じで・・・。

上にも書きましたが
2004/12/1 と 2005/1/18だと 「1」というint型が欲しいです。
2004/12/09(Thu) 10:28:48 編集(投稿者)

// 誤字を修正しました。

■No7957に返信(ああああさんの記事)
> > 12/01 と 10/02 を比較した時はどうするつもりなんでしょ?
> > 勤続年数などの概念なら、これも「2」という解になりますが? > 元質問者さま
> その通りです。
> 12/1と 10/18 日を比較しても「2」というint型が欲しいです。
> DateDiffの月差分が欲しいといった感じで・・・。

つまり、"日"は関係ないってことですか?
ということは、例の関数の "日" の比較部分を除けば良いわけですね。
その辺りは、自分で改造できますよね?

... って既にやってそうですね。( ´ー`)
おはようございます。
面倒なら、DateDiffを利用する為に、Microsoft.VisualBasic.dllを
利用するという方法がありますが...
>おはようございます。
>面倒なら、DateDiffを利用する為に、Microsoft.VisualBasic.dllを
>利用するという方法がありますが...

それもちょっと考えたのですが、
やっぱりそれはちょっとよろしくないかな、、とか思って・・。


教えていただいた関数を改良してうまくいきました!
どうもありがとうございました(^^)
解決済み!
■No7964に返信(ああああさんの記事)

当初の計算ロジックに論理的な誤りがありそうな気がして不安です。
改良して頂いたとの事なので安心です。

>
> 教えていただいた関数を改良してうまくいきました!
> どうもありがとうございました(^^)


java.lang.Nullpo さん

>ということで、反論じみた投稿をしましたが、気分を悪くされたらごめんなさい。

そんなことありません。
逆に感謝してます。
また色々と教えてください。
解決済み!
■No7968に返信(平ちゃんさんの記事)

自己レスです。

>
> 当初の計算ロジックに論理的な誤りがありそうな気がして不安です。

私の計算方法での日数の取得は誤りです。
参考にされた方は忘れてください。

年数、月数の取得方法は java.lang.Nullpo さんのソース通りです。
但し適用できないのは
@小さい日付が月の初めの場合(1月1日、2月1日 ...)で
 大きい日付が月末の場合、1ヶ月少なくなる。
A小さい日付が30日、31日の場合で
 大きい日付が2月28日の場合、1ヶ月少なくなる。

これに気をつけてくださいね。

# ああああ さんは

java.lang.Nullpo さんの次の質問に
>12/01 と 10/02 を比較した時はどうするつもりなんでしょ?
>勤続年数などの概念なら、これも「2」という解になりますが? > 元質問者さま

若干違った回答をしている気がしますので再度取り上げます。

>その通りです。
>12/1と 10/18 日を比較しても「2」というint型が欲しいです。
>DateDiffの月差分が欲しいといった感じで・・・。

この場合小さい日付が18日なので問題ないです。

>上にも書きましたが
>2004/12/1 と 2005/1/18だと 「1」というint型が欲しいです。
 
この場合小さい日付が1日ですが大きい日付が月末でないので
問題なしです。
但し大きい日付が2004/12/31の場合はどうなのでしょうか?。
1 または 0 のどちらにするのでしょうか。
それとも大きい日付が月末になることは無いのでしょうか?

やや心配なので解決済みをはずします。
すみませんが再度解決済みにチェックをいれて下さい。
> >上にも書きましたが
> >2004/12/1 と 2005/1/18だと 「1」というint型が欲しいです。
>  
> この場合小さい日付が1日ですが大きい日付が月末でないので
> 問題なしです。
> 但し大きい日付が2004/12/31の場合はどうなのでしょうか?。
> 1 または 0 のどちらにするのでしょうか。
> それとも大きい日付が月末になることは無いのでしょうか?

またわかりにくい回答をしてすみません。
ようは、年度末(大体3月かな?でも可変対応です。)
まであと何カ月あるかが取りたかっただけなんです・・・。

今日が12月なら、3月まで自月を含めてあと4カ月。

今日が1日でも30日でも12月は12月なので4というint型がほしかったのです。
年度末は固定でなく可変です。

2004/12/30 と 2005/3/1の比較だと4というint型が欲しいという事です。
まぎらわしくて本当にごめんなさい。
ひょっとしてこういう事ならもっとサクっと求めることが出来るとか・・・・??
2004/12/10(Fri) 12:36:14 編集(投稿者)

■No7980に返信(ああああさんの記事)
>>>上にも書きましたが
>>>2004/12/1 と 2005/1/18だと 「1」というint型が欲しいです。
>> 
>>この場合小さい日付が1日ですが大きい日付が月末でないので
>>問題なしです。
>>但し大きい日付が2004/12/31の場合はどうなのでしょうか?。
>>1 または 0 のどちらにするのでしょうか。
>>それとも大きい日付が月末になることは無いのでしょうか?
>
> またわかりにくい回答をしてすみません。
> ようは、年度末(大体3月かな?でも可変対応です。)
> まであと何カ月あるかが取りたかっただけなんです・・・。
>
> 今日が12月なら、3月まで自月を含めてあと4カ月。
>
> 今日が1日でも30日でも12月は12月なので4というint型がほしかったのです。
> 年度末は固定でなく可変です。
>
> 2004/12/30 と 2005/3/1の比較だと4というint型が欲しいという事です。
> まぎらわしくて本当にごめんなさい。
> ひょっとしてこういう事ならもっとサクっと求めることが出来るとか・・・・??
>

そういうことですか
やっと質問の意味がわかりました。
すみませんでした。
つまり
2004/12/1と2004/12/31 --> 1
2004/12/31と2005/1/1 --> 2
2004/12/1と2005/1/31 --> 2
2004/12/1と2005/2/1 --> 3
なのですね

それならば
java.lang.Nullpo さんの変形になります。
Source:--------------------------------------------------------------------

private string GetDateSpan(DateTime bigDate, DateTime smallDate) {
int iYear, iMonth; //, iDay;

iYear = bigDate.Year - smallDate.Year;
iMonth = bigDate.Month - smallDate.Month + 1; //自月も含める
//iDay = bigDate.Day - (smallDate.Day - 1);

//if (iDay < 0) {
// iMonth--;
//}

if (iMonth < 0) {
iYear--;
iMonth += 12;
}

return iYear.ToString() + '年' + iMonth.ToString() + '月';
}

---------------------------------------------------------------------------


このように変更して動作確認してみてください。
と書いてて既にもう変更されてる訳ですね。いま気がつきました。
お騒がせしました。お恥ずかしい。

DOBON.NET | プログラミング道 | プログラミング掲示板