エクセルから、書式設定を変更せずに、日付シリアルを取得するには?

解決


かんとく  2008-03-28 12:23:48  No: 100505  IP: 192.*.*.*

お世話になっております。

Microsoft Excel 9.0 ObjectLibrary を参照して、VB6でエクセル2000からデータを取得します。

エクセルの("A1")セルに、2008/3/27  という値が入っているとして、そのセルの書式設定→表示形式→分類を標準にすると、セルの表示が日付シリアル(39484)に変わります。

このエクセルの書式設定→表示形式→分類が日付になっていて、しかもエクセル側で書式設定を変更したくない場合に、
VB6からこのセルの値を日付シリアルで取得したいのですが、方法が分かりません。

エクセル側の書式設定を変更してもいいのならば、NumberFormatLocal  を使って書式を変更すればいいと思うのですが、エクセル側のセルの書式設定を変えたくありません。

すみませんが、よろしくお願いします。

編集 削除
魔界の仮面弁士  2008-03-28 13:00:00  No: 100506  IP: 192.*.*.*

あれ…? 環境の違いでしょうか。
当方の Excel では、日付シリアル 39484 といえば
  2008/2/6    … Date1904 プロパティが False のとき
  2012/2/7    … Date1904 プロパティが True のとき
のいずれかになるのですけれども。


> 方法が分かりません。
Debug.Print objSheet1.Range("A1").Value2

編集 削除
かんとく  2008-03-28 15:23:36  No: 100507  IP: 192.*.*.*

ありがとうございました。

Value2をValueとしていた(Value2を知らなかった)ために、取得できなかっただけのようでした。

それで、
ret = xlSheet.Range("A1").Value2
retday = DateAdd("d", 0, ret)
とすると、
retday = 2008/3/27
となりました。

ここまではいいのですが、新たな疑問が出ました。

この掲示板の以前の書き込み  
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200503/05030091.txt
を見てみると、エクセルとVB6とでは、日付シリアルが1日ずれてしまうと思い、試しに
test = DateAdd("d", 0, 1)
を実行すると、思ったとおり
test = 1899/12/31
が帰ってきました。

なのに、
ret = xlSheet.Range("A1").Value2
retday = DateAdd("d", 0, ret)
を実行すると
retday = 2008/3/27
となり、エクセルのセルに入力された日付と同じ日付が帰ってきます。

なぜだか分かりません。何か仕掛けがあるのでしょうか?教えてください。

よろしくお願いします。

編集 削除
魔界の仮面弁士  2008-03-28 16:18:43  No: 100508  IP: 192.*.*.*

> Value2を知らなかった
Value2 の定義は、Excel のバージョンによって引数定義が異なりますので注意してください。
(実行環境と開発環境の Excel バージョンを一致させておかないと、問題が発生する事があります)

ちなみに、VB側での日付シリアル変換は
  Debug.Print CDbl(#3/27/2008#)    '39534.0
  Debug.Print CDate(39534)         '2008年3月27日
のように書けますので、Value2 が使えなくとも、VB側で変換は可能です。



> エクセルのセルに入力された日付と同じ日付が帰ってきます。
Excel の日付シリアルと、VB の日付シリアルが別物であるのは確かですが、
かんとくさんは、2 つの点を誤解しておられるようです。


まず、『日付シリアルが1日ずれてしまう』というのが誤解です。
2008/03/27 のシリアル値は一緒です。


> この掲示板の以前の書き込み  
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200503/05030091.txt
> を見てみると、
そこに書かれているのは、Excel側の日付は、
      99/12/31    …非対応の日付
     100/01/01    …非対応の日付
        :                :
    1899/12/29    …非対応の日付
    1899/12/30    …非対応の日付
    1899/12/31    …非対応の日付
    1900/01/00    …シリアル値 0
    1900/01/01    …シリアル値 1
        :                :
    1900/02/28    …シリアル値 59
    1900/02/29    …シリアル値 60  ★そのURLにて問題視されている部分
    1900/03/01    …シリアル値 61
        :                :
    9999/12/31    …シリアル値 2958465
    10000/01/01    …非対応の日付
のようになっていますが、VBの日付シリアルは、
      99/12/31    …非対応の日付
     100/01/01    …シリアル値 -657434
        :                :
    1899/12/29    …シリアル値 -1
    1899/12/30    …シリアル値 0
    1899/12/31    …シリアル値 1
    1900/01/00    …★存在しない日付★(0日は存在しない)
    1900/01/01    …シリアル値 2
        :                :
    1900/02/28    …シリアル値 60
    1900/02/29    …★存在しない日付★(1900年は閏年では無い)
    1900/03/01    …シリアル値 61
        :                :
    9999/12/31    …シリアル値 2958465
    10000/01/01    …非対応の日付
のようになっています。


つまり、ごく狭い日付範囲では、確かに 1 日ずれている部分もありますが、
常用される範囲、シリアル値61〜2958465の範囲(1900/03/01以降)については、
ずれは発生していないということです。



もう一つの誤解は、日付シリアルと日付の換算についてです。

VB の日付シリアル値は、Calendar プロパティの内容で変化します。
たとえば、今回使おうとしている CDate(39484) の結果は、
Calendar = vbCalGreg なら、2008年2月6日 を示しますが、
Calendar = vbCalHijri は、1429年1月29日 を示します。
なお、既定の設定は vbCalGreg (グレゴリオ暦)です。


一方、Excel の日付シリアル値は、オプション設定画面にある
「1904 年から計算する」の設定によって変化します。
VBA でいえば、ブックの Date1904 プロパティですね。
既定では、これは Off になっています。


このような違いもありますから、日付をシリアル値として扱うのであれば、
どのモードで変換しようとしているのかを、正しく認識する必要があるでしょう。


以上の点を踏まえて、あらためて確認なのですが:

>> 当方の Excel では、日付シリアル 39484 といえば
>>   2008/2/6    … Date1904 プロパティが False のとき
>>   2012/2/7    … Date1904 プロパティが True のとき
>> のいずれかになるのですけれども。

かんとくさんの環境の Excel では、39484 は上記の日付にはならず、
2008/3/27 を示していたのですよね? Date1904 の設定はどうなっていましたか?

>>> 2008/3/27  という値が入っているとして、そのセルの書式設定→表示形式→分類を標準にすると、
>>> セルの表示が日付シリアル(39484)に変わります。

編集 削除
かんとく  2008-03-29 00:59:57  No: 100509  IP: 192.*.*.*

ありがとうございます。

すみません、39484は間違えでした。単純なミスです。
2008年3月27日はうちでも39534でした。
コピーペーストではなかったので、打ち間違えだと思います。

あと、もうひとつ勘違いをしていたようです。
VBでは、1900/1/1からの通算日をシリアル日付と呼ぶのではないと言うことですよね。

まだ本当にしたかった処理ができていませんが、質問の仕方を考えているので、また後日質問させてもらいます。

ありがとうございます。

編集 削除
かんとく  2008-04-01 12:55:25  No: 100510  IP: 192.*.*.*

ありがとうございます。

CDblで日付シリアルを取得できたのでよかったです。

ところで、まだできていない本当にしたかった処理ですが、エクセルファイルを開いて、エクセルシートをそのままVBのフォーム上で再現したいのです。
セル一つひとつの書式は、
NumberFormatLocal
を使って一つひとつ取得しなければならないと思いますが、取得した値は、日付の場合、単純に"日付"というのではなく、mやdが入っていたら日付だとか、geが入っていたら元号入り日付だとか、日付でもどのタイプの日付かを一つひとつ調べなければいけませんよね。
一発で日付だと分かる方法はないでしょうか。

あと、DAOを使って書式を取得する方法はありますでしょうか?
調べてみましたが、見つけられませんでした。

よろしくお願いします。

編集 削除
魔界の仮面弁士  2008-04-01 16:29:12  No: 100511  IP: 192.*.*.*

> エクセルシートをそのままVBのフォーム上で再現したいのです。
[プロジェクト]-[コンポーネント]  →  "コントロール" から、
  Microsoft Office Web Components 11.0
  Microsoft Office XP Web Components
  Microsoft Office Web Components 9.0
のいずれかを選択し、フォームに Microsoft Spreadsheet コントロールを
貼りつけて使うというのはどうでしょう。

データは、Excel からクリップボード経由で転送、とか。
(Copy メソッド & Paster メソッド)


> NumberFormatLocal
個人的には、NumberFormat の方が好みですが、どちらでも良いと思います。

.Range("A1").NumberFormat = "[DBNum2]ggge年m月d日"
.Range("A1").NumberFormatLocal = "[DBNum2]ggge年m月d日"
.Range("A1").NumberFormat = "[Red][<10]#0.00;[Blue][<=50]#0.00;[Green]0.00"
.Range("A1").NumberFormatLocal = "[赤][<10]#0.00;[青][<=50]#0.00;[緑]0.00"

> 一発で日付だと分かる方法はないでしょうか。
厳密判定ではありませんが、簡易的に、下記でどうでしょう。

Dim v As Variant
v = .Range("A1").Value
Debug.Print VarType(v) = vbDate
Debug.Print TypeName(v) = "Date"


> あと、DAOを使って書式を取得する方法はありますでしょうか?
無いと思います。

編集 削除
かんとく  2008-04-01 18:29:22  No: 100512  IP: 192.*.*.*

ありがとうございました。

簡易的なものでも、ユーザー定義による日付
[$-411]ge.m.d;@
を日付として認識してもらえたので、充分です。

Microsoft Office Web Components 9.0
はすごいですね。
そのまんまエクセルですね。
このコントロールを使ったプログラムを配布しても大丈夫なんでしょうか。
(大丈夫なんだろうと思いますけど)

DAOは、スピードアップできるかなと思って聞いてみました。
無いなら仕方がないと思います。

ありがとうございました。

編集 削除