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

VBでのファイル送受信について2

環境/言語:[OS : Windows XP / 言語 : Visual Basic .NET / .NET Framework : 2.0]
分類:[.NET]

以前↓もお世話になりましたが、よろしくお願いします。
http://dobon.net/vb/bbs/log3-41/25238.html

【解決したい問題】

以前、こちらの.NET Tipsおよび掲示板にお世話になり、Windowsアプリから
FTPサーバーにファイルをアップロード/ダウンロードする機能を作成しました。
・実行Buttonクリック
・送信ファイル作成
・FTPアップロード
・MessageBox.Show("ファイルの作成・送信が完了しました")
簡単ですが、以上のようなイメージです。


今回、別システムで似た機能を作成しているのですが、
上記イメージで言うと最後のMessageBoxの表示内容を
「?年?月?日 ?時?分付けでサーバーに登録されました」
といったように送信日時のメッセージ表示をしたいと考えています。

【解決するために何をしたか】

上記イメージで言うと、FTPアップロードの直後に連続処理で
FtpWebRequest等のオブジェクトをもう一つ用意して、こちらの.NET Tips
「FTPサーバーのファイルのファイルの更新日時を取得する」を参考に
アップロードした直後のファイルを指定して情報を得ようと考えました。


ここから質問ですが

まずそもそも今回私がやりたい事(送信日時のメッセージ表示)を行う上で
この方法は妥当(一般的?)でしょうか?
# そんな事しなくてもこうすれば…みたいな事があれば助言頂ければと。


とりあえず今はこの方法でテストしていますが、ftpRes.LastModifiedの時間が
現在(送信後)の時間が 2010/02/19 12:22 だとして
取得した日時が9時間後の "2010/02/19 21:22:38" となるのですが
この現象について何か助言頂けないでしょうか?(サーバ日付がおかしい?)
因みに、ftpRes.StatusDescriptionは、"FileStatus: 213 20100219122238"となります。

今回も乱文・長文ですが、よろしくお願いします。
■No26425に返信(リモーネさんの記事)
> 「?年?月?日 ?時?分付けでサーバーに登録されました」
> といったように送信日時のメッセージ表示をしたいと考えています。
具体的には、上記はどの時刻を指しているのでしょうか?
 ・送信を開始した時点での FTP クライアント側の時刻
 ・送信を開始した時点での FTP サーバー側の時刻
 ・送信が終了した時点での FTP クライアント側の時刻
 ・送信が終了した時点での FTP サーバー側の時刻
 ・FTP サーバー上に保存されたファイルの、ファイルシステム上の作成日時
 ・FTP サーバー上に保存されたファイルの、ファイルシステム上の更新日時
 ・その他


> まずそもそも今回私がやりたい事(送信日時のメッセージ表示)を行う上で
> この方法は妥当(一般的?)でしょうか?
上記いずれを求めているかによって異なると思います。


> 現在(送信後)の時間が 2010/02/19 12:22 だとして
> 取得した日時が9時間後の "2010/02/19 21:22:38" となるのですが
日本の時差は +9時間ですよね。

> この現象について何か助言頂けないでしょうか?
GMT とか UTC とか JST とか。

> サーバ日付がおかしい?
Sub Main()
    Dim dt0 As Date = #02/19/2010 12:22:38#

    Dim dt1 As New Date(2010, 2, 19, 21, 22, 38, 0, DateTimeKind.Local)
    Dim dt2 As New Date(2010, 2, 19, 12, 22, 38, 0, DateTimeKind.Utc)

    Console.WriteLine("元データ")           'Kind プロパティの違いに注意
    Console.WriteLine("dt0 => " & dt0.ToString("yyyy/MM/dd HH:mm:ss.fffffff K"))
    Console.WriteLine("dt1 => " & dt1.ToString("yyyy/MM/dd HH:mm:ss.fffffff K"))
    Console.WriteLine("dt2 => " & dt2.ToString("yyyy/MM/dd HH:mm:ss.fffffff K"))

    Console.WriteLine("UTC(世界協定時刻)")  'いずれも、12時22分になるはず
    Console.WriteLine("dt0 => " & ToStringByUTC(dt0))
    Console.WriteLine("dt1 => " & ToStringByUTC(dt1))
    Console.WriteLine("dt2 => " & ToStringByUTC(dt2))

    Console.WriteLine("現地時刻")            '日本なら、21時22分になるはず
    Console.WriteLine("dt0 => " & ToStringByLocal(dt0))
    Console.WriteLine("dt1 => " & ToStringByLocal(dt1))
    Console.WriteLine("dt2 => " & ToStringByLocal(dt2))
End Sub

Public Function ToStringByUTC(ByVal d As Date) As String
    If d.Kind = DateTimeKind.Unspecified Then
        Return d.ToString("yyyy/MM/dd HH:mm:ss.fffffff")
    Else
        Return d.ToUniversalTime().ToString("yyyy/MM/dd HH:mm:ss.fffffff")
    End If
End Function

Public Function ToStringByLocal(ByVal d As Date) As String
    If d.Kind = DateTimeKind.Local Then
        Return d.ToString("yyyy/MM/dd HH:mm:ss.fffffff")
    Else
        Return d.ToLocalTime().ToString("yyyy/MM/dd HH:mm:ss.fffffff")
    End If
End Function
魔界の仮面弁士さん、とてもご親切な回答ありがとうございます。

>>「?年?月?日 ?時?分付けでサーバーに登録されました」
>>といったように送信日時のメッセージ表示をしたいと考えています。
> 具体的には、上記はどの時刻を指しているのでしょうか?
>  ・送信を開始した時点での FTP クライアント側の時刻
>  ・送信を開始した時点での FTP サーバー側の時刻
>  ・送信が終了した時点での FTP クライアント側の時刻
>  ・送信が終了した時点での FTP サーバー側の時刻
>  ・FTP サーバー上に保存されたファイルの、ファイルシステム上の作成日時
>  ・FTP サーバー上に保存されたファイルの、ファイルシステム上の更新日時
>  ・その他

「何月何日の、何時何分に、たしかに届きました(受け取りました)よ」
といった意味合いで表示したいと思っていますので
>  ・送信が終了した時点での FTP サーバー側の時刻
になると思います。

>>まずそもそも今回私がやりたい事(送信日時のメッセージ表示)を行う上で
>>この方法は妥当(一般的?)でしょうか?
> 上記いずれを求めているかによって異なると思います。
以上を踏まえて、申し訳ありませんが再度助言頂けないでしょうか?


>>現在(送信後)の時間が 2010/02/19 12:22 だとして
>>取得した日時が9時間後の "2010/02/19 21:22:38" となるのですが
> 日本の時差は +9時間ですよね。
>
>>この現象について何か助言頂けないでしょうか?
> GMT とか UTC とか JST とか。
あーなるほど、こうゆう事も意識しないと…
私の浅い経験上では、こうゆう事を意識した開発は初なので勉強になります。


サンプルコードまで有難うございます。
たしかに以下の実行結果になりました。

元データ
dt0 => 2010/02/19 12:22:38.0000000
dt1 => 2010/02/19 21:22:38.0000000 +09:00
dt2 => 2010/02/19 12:22:38.0000000 Z
UTC(世界協定時刻)
dt0 => 2010/02/19 12:22:38.0000000
dt1 => 2010/02/19 12:22:38.0000000
dt2 => 2010/02/19 12:22:38.0000000
現地時刻
dt0 => 2010/02/19 21:22:38.0000000
dt1 => 2010/02/19 21:22:38.0000000
dt2 => 2010/02/19 21:22:38.0000000


という事は…ToStringByUTC(ftpRes.LastModified)になる…?
とりあえず、さっそく試してみます。
# ついでにちょっと混乱気味なので、頭の中でイメージを整理してきます^^;
すいません。なんか本当に混乱してきたようで…

> という事は…ToStringByUTC(ftpRes.LastModified)になる…?
> とりあえず、さっそく試してみます。
ToStringByUTCは、提示して頂いたサンプルのメソッドでしたね。
既存のメソッドとごっちゃになって考えてしまいました。
正確には「さっそく同様の編集・表示を試してみます」です。
■No26429に返信(リモーネさんの記事)
> といった意味合いで表示したいと思っていますので
>> ・送信が終了した時点での FTP サーバー側の時刻
> になると思います。
現状は、GetDateTimestamp(MDTM) で LastModified を得ているのでしょうか。
その場合は、
 ・FTP サーバー上に保存されたファイルの、ファイルシステム上の更新日時
に相当するかと思います。それで構わないのであれば、今の方向性で OK かと。


>> 上記いずれを求めているかによって異なると思います。
> 以上を踏まえて、申し訳ありませんが再度助言頂けないでしょうか?
一部のメソッドしかサポートしていない FTP サーバーも存在するため、
サーバー側の時刻を確実に得る方法は無いかも知れません。

先の MDTM にしても、たとえサーバーがサポートしていたとしても、その結果が
標準時で返されるサーバーもあれば、localtime で返してくるサーバーも存在しますので、
どうすべきかはケースバイケースです。

まぁ、通信相手のサーバーが固定的な場合は、事前に調査しておけば済みますけれどね。
(たとえば FFFTP などでは、ホストのタイムゾーンを設定できるようになっています)


>>GMT とか UTC とか JST とか。
> あーなるほど、こうゆう事も意識しないと…
ちなみに .NET 3.5 には、DateTime 型に『時差情報』を含ませた
DataTimeOffset 型が用意されています。今回は関係無いですけれども。


> という事は…ToStringByUTC(ftpRes.LastModified)になる…?
すみません。本来は下記のコードを掲載する予定でした。
先ほどのコードと差し替えて、結果の違いを確認してみてください。

Public Function ToStringByUTC(ByVal d As Date) As String
    If d.Kind = DateTimeKind.Utc Then
        Return d.ToString("yyyy/MM/dd HH:mm:ss.fffffff")
    Else
        Return d.ToUniversalTime().ToString("yyyy/MM/dd HH:mm:ss.fffffff")
    End If
End Function


dt1 と dt2 は同じ時刻ですが、タイムゾーンが異なります。

dt1 は、21:22:38 +09:00 (現地時間21時22分)で、
dt2 は、12:22:38 +00:00 (標準時 12時22分)です。

この場合の変換結果は
 dt1 は、標準時 で 12:22、現地時間で 21:22
 dt2 も、標準時 で 12:22、現地時間で 21:22
になると思います。(この点だけ見れば、元のソースでも同じ動きです)

問題は dt0 です。

これは Unspecified すなわち「日本時間か標準時か不明な状態」なので、
補正不要なのか、+09:00 すべきなのか、-09:00 すべきなのかは定めようが無く、
それぞれのアプリごとに、ケースバイケースで判断していただく必要があります。
(多くの場合、日付型の Kind プロパティは Unspecified の状態です)
魔界の仮面弁士さん、ご回答ありがとうございます。
頭の中で理解/整理するのが遅いため、お礼が送れて申し訳ありません。


> 現状は、GetDateTimestamp(MDTM) で LastModified を得ているのでしょうか。
はい。(こちらのTipsを参考にさせていただいています)

> その場合は、
>  ・FTP サーバー上に保存されたファイルの、ファイルシステム上の更新日時
> に相当するかと思います。それで構わないのであれば、今の方向性で OK かと。
よく考えてみると…
処理が終了した事を対象とするよりも、きちんと保存されたファイルを対象とした方が
> 「何月何日の、何時何分に、たしかに届きました(受け取りました)よ」
的な意味合いには適切かと思い至りまして、この方向性で行こうかと思います。


> 先の MDTM にしても、たとえサーバーがサポートしていたとしても、その結果が
> 標準時で返されるサーバーもあれば、localtime で返してくるサーバーも存在しますので、
> どうすべきかはケースバイケースです。
>
> まぁ、通信相手のサーバーが固定的な場合は、事前に調査しておけば済みますけれどね。
今回の場合はWindowsアプリから、こちらが管理しているサーバー固定で
一方通行的にデータが送信されて来る仕様ですので……事前調査ですね。

> (たとえば FFFTP などでは、ホストのタイムゾーンを設定できるようになっています)
私よりは詳しい(マシ)な者に調べて見てもらったところ
「GMT+9:00(日本)」と設定されている。との事でした。
# だから当初の書き込みのように+9時間後を取得するのかな?と…


>>という事は…ToStringByUTC(ftpRes.LastModified)になる…?
> すみません。本来は下記のコードを掲載する予定でした。
> 先ほどのコードと差し替えて、結果の違いを確認してみてください。
差替えサンプルまて提示して頂き、本当に恐れ入ります。

たしかに以下の実行結果になりました。
UTC(世界協定時刻)
dt0 => 2010/02/19 03:22:38.0000000
dt1 => 2010/02/19 12:22:38.0000000
dt2 => 2010/02/19 12:22:38.0000000

また、今回のftpRes.LastModifiedの取得値(+9時間)でも試したところ
新旧どちらのサンプルの場合でもElse側の処理が実行されメッセージ上では
どちらも正しい時間が表示されました。
(d.Kindは、DateTimeKind.Localと判断されるようです)


色々勉強させてもらい、だいぶ分かってきた感じなので
ほぼ解決に近づいたとは思ってますが、もし他にも何か
お気づきの点(勘違いしてそうとか)等ありましたらご指摘お願いします。
おかげさまで無事目的の処理を行う事ができるようになりました。
助言頂いた内容も大変勉強になりました。ありがとうございます。
解決済み!

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