和暦の引き算や平均について?


あや  2008-09-18 09:24:54  No: 140452  IP: 192.*.*.*

DBからの読み込みで西暦を和暦に変換することは出来ました。(例:20080918→平成20年9月18日というような形で出すことは出来ました。)

ここでまたわからない問題が発生したのですが和暦同士の引き算や平均を出すためにはどうしたらいいのでしょうか??

1.10年前の平成20年9月18日から平成10年9月18を引き算するためには?

2.平成15年5月18日、平成11年10月27日、平成20年9月16日、平成6年7月20日
があったとしたら平均を出すには??

です。
よろしくお願いします。
VB2008、SQL2005です。

編集 削除
特攻隊長まるるう  2008-09-18 10:14:27  No: 140453  IP: 192.*.*.*

[前スレ]
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200809/08090028.txt
結果報告(どのように解決したか)が書かれていないため
助言できません。

日付の演算をするためには、
VB側で日付型の変数に格納して、Date クラスの関数を利用するとか、
検索時にSQLでデータベースに用意された関数を使うなどが考えられます。

編集 削除
あや  2008-09-18 10:35:34  No: 140454  IP: 192.*.*.*

特攻隊長まるるうさんご返答ありがとうございます。
結果なのですが
1.に関しては1年と出したいのです。
もし仮に平成20年9月18日から平成10年9月18日ではなく平成20年9月18日から平成10年8月18日としたら  1年1ヶ月  という風に出したいのです。

2.の平均は平成15年5月18日、平成11年10月27日、平成20年9月16日、平成6年7月20日だとしたら  13年5月20日  という形でだしたいです。(小数点は切捨てします)

編集 削除
 2008-09-18 10:40:34  No: 140455  IP: 192.*.*.*

とりあえず細かい話ですが苦言から
ほんの少し前に指摘された事ぐらいは注意しましょう
タイトルにクエスチョンマークを付けただけでは意味が無い

で、1については
CType(???, Date) か CDate でDate型に突っ込んでから
Date.Compare か DateDiff で差を出せばいい
2については…2005でちょっと試してみたら日付をLongに変換して
足し算、とかは出来ないみたいなので、発想を変えるしかない
どれかの日付を基準にして、他の日付との差を全て計算し、
その「差の合計」を出して平均して、基準日に足せば何とかなるのでは
日付の平均って何に使うのかはピンと来ないし、やった事ないけど…

編集 削除
 2008-09-18 10:45:25  No: 140456  IP: 192.*.*.*

…って、あれ
話が進んでるな…
>もし仮に平成20年9月18日から平成10年9月18日ではなく平成20年9月18日から平成10年8月18日としたら  1年1ヶ月  という風に出したいのです。
…って、うるう年の絡みとかは どうするの?

編集 削除
あや  2008-09-18 10:55:30  No: 140457  IP: 192.*.*.*

あさんありがとうございます。
そしてすいません・・・・。

とりあえずはうるう年考えないで出したいと思ってます

編集 削除
魔界の仮面弁士  2008-09-18 11:11:05  No: 140458  IP: 192.*.*.*

これは VB2008 の話題ですか? それとも、SQL2005 の話題ですか?
SQL Server 2005 の SQL の書き方などの質問だとしたら、板違いかと。


> DBからの読み込みで西暦を和暦に変換することは出来ました。
幾つかの方法が考えられますが、どのような方法で行ったのでしょうか?
(VB2005 だと、System.Globalization.CultureInfo などを利用できますね)


> 和暦同士の引き算や平均を出すためにはどうしたらいいのでしょうか??
和暦や西暦というのは、表示上の話であって、データそのものは日付値ですよね。

表示されている「文字列」だと、直接計算するのは厄介ですけれども、
元データ(日付型)に対しては、そのまま算出できるはずですよ。


> 1.10年前の平成20年9月18日から平成10年9月18を引き算するためには?
主要なデータベース製品の多くは、日付型同士をそのまま引き算でき、
その結果を、日数を表す数値で返すことが多いです。SQL Server もそうです。

直接引き算できない DB の場合は、日付計算のための関数等が
用意されていると思いますので、それらを使えば良いかと。

また、(データベース側ではなく)VB2005 の日付型に対して計算する場合は、
単純に引き算すれば、その日数差が TimeSpan 型で返されるので、そこから算出できます。



> 2.平成15年5月18日、平成11年10月27日、平成20年9月16日、平成6年7月20日
> があったとしたら平均を出すには??
どのような結果になるのを想定しているのか、にもよりますが、ロジック的には
適当な基準日(固定値でも良いし、上記いずれかの日付の1つを使っても良い)を用意し
  (1) 基準日から、平成15年 5月18日 までの経過日数を求める
  (2) 基準日から、平成11年10月27日 までの経過日数を求める
  (3) 基準日から、平成20年 9月16日 までの経過日数を求める
  (4) 基準日から、平成 6年 7月20日 までの経過日数を求める
  (5) 上記 (1)〜(4) で得た経過日数の平均値を求める
  (6) 基準日に、上記 (5) で得た経過日数を加えて、日付を出す
という処理で得られますね。VB であっても、SQL Server であっても。


ここは VB の掲示板なので、VB 側の算出方法で書きますが、
たとえばこんな感じで、平成13年8月8日という日付が得られます。

'================================
'日付値の一覧を用意
Dim dateList As New List(Of Date)()

'今回の処理対象の日付 4 つを登録
'ちなみに #M/d/yyyy# というのは、VB の日付型リテラル表記法です。
dateList.Add(#5/1/2003#)
dateList.Add(#10/27/1999#)
dateList.Add(#9/16/2008#)
dateList.Add(#7/20/1994#)
'推奨はしませんが、一応、下記の書き方もできます。
'dateList.Add(CDate("平成6年7月20日"))

'---> 計算処理の本体 ここから --->
'基準日から、各日付までの日数差を合計する。
Dim t As TimeSpan
For Each d As Date In dateList
  t += (d - Date.MinValue)
Next

'日数差の平均値を得る
Dim avg As New TimeSpan(t.Ticks \ dateList.Count)

'その平均値を、基準日に足して答えを得る
Dim answer As Date = Date.MinValue + avg
'<--- 計算処理の本体 ここまで <---


'日付型を和暦表記の文字列にして表示
Dim culture As New CultureInfo("ja-JP", False)
culture.DateTimeFormat.Calendar = New JapaneseCalendar()
Dim s As String = answer.ToString("ggy年M月d日 HH:mm:ss.ffff", culture)

Console.WriteLine(s)
'================================

また、上記のように TimeSpan.Ticks を使うかわりに、
DateTime.Ticks のみで処理すると、もっと単純に書けます。

'================================
Dim ticks As Long
For Each d As Date In dateList
  ticks += d.Ticks
Next
Dim answer As New Date(ticks \ dateList.Count)
'================================


VB2008 の場合は、さらに短く 1 行で算出する事もできます。
'================================
Dim answer As New Date(CLng((From d In dateList Select d.Ticks).Average()))
'================================

編集 削除
 2008-09-18 11:59:13  No: 140459  IP: 192.*.*.*

あ、言われてみればTimeSpanなんてのもあったなぁ(ぉぃ
普段使わないのでスッカリ忘れてました(滝汗

とりあえずVBでやることを前提に書かせてもらうとして
(当方VB2005の環境と知識しかないのでご了承を)、
例えば H20/3/1 と H19/2/1 の差と、
H20/8/1 と H19/7/1 の差だと
見かけ上は1年1ヶ月だけど日数は数日違うかと思う
その辺は どうする?

その辺も あまり考えないようにするとなると、
逆に大変かもしれない
例えば 1年1ヶ月 = 1年 + 31日、
1年2ヶ月 = 1年 + 59日、…で固定とするなら
何年にもまたがるなら Dateでの計算(適当に基準日を決めて、それに足して
計算するとか)でもうるう年による誤差が出るから、Dateでの計算は
無理があると思う
うるう年でない各月の日数を DateTime.DaysInMonthとかで認識して
それを足し込みながら比較するしかないかも
(もちろん、はじめに 日数 \ 365 で年を求めて、
  日数 Mod 365 で剰余を出して、その剰余に対して判定とか)
私の頭では、それ以上は思いつかない
(逆に、うるう年では確実に誤差が出るけど…無視でいいんだよね)

編集 削除
魔界の仮面弁士  2008-09-18 12:14:03  No: 140460  IP: 192.*.*.*

>平成20年9月18日から平成10年8月18日としたら  1年1ヶ月  という風に出したいのです。

1年1ヶ月という事は、13ヶ月ですよね。
どうみても、一致していないように思えますが…。


> 2.の平均は
>   平成15年5月18日
>   平成11年10月27日
>   平成20年9月16日
>   平成6年7月20日
> だとしたら
>   13年5月20日
> という形でだしたいです。(小数点は切捨てします)

…? この算出結果の根拠が良く分かりませんでした。
「13年5月20日」という平均値は、どのようにして算出された物なのでしょうか?


(予想1) 閏年も含め、基準日からの経過日数ベースで算出
  計算方式は、先の私の回答を見ていただくとして:
  結果  =  平成13年8月8日  →  13年5月20日にはならない…。


(予想2) 経過日数等を考慮せず、年,月,日の3つに単純分割して処理
  年  =  (15+11+20+ 6)÷4 = 13.00
  月  =  ( 5+10+ 9+ 7)÷4 =  7.75  → 小数部…22〜23日間相当?
  日  =  (18+27+16+20)÷4 = 20.25  → 小数部…6時間相当?
  結果  =  端数を切り捨てても、13年7月20日以降の日付にしかならない…。


(予想3) とりあえず日部は無視して、年月部だけを、元年1月からの経過月数で計算してみる
  平成15年 5月18日  →  (14 * 12 +  4)ヶ月後+17日後  = 172ヶ月後+α日
  平成11年10月27日  →  (10 * 12 +  9)ヶ月後+26日後  = 129ヶ月後+α日
  平成20年 9月16日  →  (19 * 12 +  8)ヶ月後+15日後  = 236ヶ月後+α日
  平成 6年 7月20日  →  ( 5 * 12 +  6)ヶ月後+19日後  =  66ヶ月後+α日
  合計  =  603ヶ月後+α日
  平均  =  150.75 ヶ月後  =  (12 * 12 + 6.75)ヶ月後+α日
  結果  =  13年8月相当、端数を切り捨てても 13年7月相当

編集 削除
もげ  2008-09-18 12:49:24  No: 140461  IP: 192.*.*.*

Parseできなくも無いですが、いろいろ演算を行うのであれば、
データはDate,DateTimeで持っておいて、
最終的な表示だけ和暦にして出すほうがお薦めかもしれません。


文字通り引き算
?date.Parse("平成19年9月18日").subtract(date.Parse("平成18年8月18日")).Days
396


TimeSpanはあってもDateSpanは無かったですね。
?DateDiff(DateInterval.Year,date.Parse("平成18年8月18日"),date.Parse("平成19年9月18日"))
1
?DateDiff(DateInterval.Month,date.Parse("平成18年8月18日"),date.Parse("平成19年9月18日"))
13
のようになるので、

http://blog.killfly.com/index.php/2008/04/14/vbnet-datespan-class/
こんな感じでクラス作っておくとスマートなのかもしれませんね。

編集 削除
魔界の仮面弁士  2008-09-18 12:58:46  No: 140462  IP: 192.*.*.*

> 見かけ上は1年1ヶ月だけど日数は数日違うかと思う
> その辺は どうする?

閏年を考慮しないぐらいだから、無視しちゃっても良いのかな…。


たとえば『年齢計算』では、大の月/小の月の差は無視して、
  Dim a As Date = 今日の日付
  Dim b As Date = 誕生日
  Dim 年齢 As Integer = (CInt(a.ToString("yyyyMMdd")) - CInt(b.ToString("yyyyMMdd"))) \ 10000
と単純化する処理系も良く見かけますし。

あるいは別の方法では、
  [年齢] = [現在の年] - [誕生日の年]
  If [現在の月日] < [誕生日の月日] Then
    [年齢] = [年齢] - 1  'その年の誕生日に到達していなければ -1
  End If
のように算出されたりとか。
こちらの手法だと、年(y歳)ではなく、年月(y歳mヶ月)への置き換えも容易かと。

# 前日加算法か当日加算法かによって、If条件が"<", "≦"で異なりますが。


ただし私の方では、そのように計算した(つもりだった)のですが、
提示された期待値通りの計算結果を出す事ができなかったので、
これ以上は、詳しい算出方法を提示してもらわないことには何とも。

仕様に関して、もう少し詳しい情報をください。>元質問者殿

編集 削除
あや  2008-09-18 16:41:10  No: 140463  IP: 192.*.*.*

魔界の仮面弁士さん、あさん、もげさんみなさん本当に親切にありがとうございます。
嬉しいです。

1.の話なんですが13年5月20日ではなく私の計算ミスで13年7月20日でした。
本当にすいません。

2.はうるう年は無視で一年が365日だと考えて出したかったんです。

1.に関しては何とかできました。(もちろん参考にさせてもらいました♪)
2.も皆さんのを参考にしてやってみます。

編集 削除