我更改了日期时间转换方法,使用TimeZoneInfo.ConvertTimeBySystemTimeZoneId https://learn.microsoft.com/en-us/dotnet/api/system.timezoneinfo.converttimebysystemtimezoneid,经过我的本地时区.Id https://learn.microsoft.com/en-us/dotnet/api/system.timezoneinfo.local and "Tokyo Standard Time"
作为参数,生成日期时间偏移量 https://learn.microsoft.com/en-us/dotnet/api/system.datetimeoffset代表当前的东京日期时间。
使用计时器,从计算出的 DateTimeOffset 中减去 4 秒(DateTimeOffset.AddSeconds(-4)
),图像加载正确。
► 请注意,系统时钟必须与NTP服务器 http://support.ntp.org/bin/view/Servers/WebHome. 4
秒是一个相对宽松的间隙,但不同步的时钟当然会损害结果。
EDIT:
改变了System.Windows.Forms.Timer
to System.Timers.Timer
,因为这里需要更多时间的是图像下载。
Using BeginInvoke()
设置PictureBox.Image
,几乎不需要任何东西,可以防止 UI口吃当表单移动时。
Private tokyoTimer As System.Timers.Timer = Nothing
Private tokyoClient As WebClient
Private Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click
tokyoTimer = New System.Timers.Timer() With {.Interval = 1000}
tokyoClient = New WebClient()
AddHandler tokyoTimer.Elapsed,
Sub()
Dim TokyoOffset = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(Date.Now, TimeZoneInfo.Local.Id, "Tokyo Standard Time")
Dim currentImage As String = TokyoOffset.AddSeconds(-4).ToString("yyyyMMdd/yyyyMMddHHmmss") & ".jma_s.gif"
Try
Dim data = tokyoClient.DownloadData(New Uri($"http://www.kmoni.bosai.go.jp/data/map_img/RealTimeImg/jma_s/{currentImage}"))
BeginInvoke(New MethodInvoker(
Sub()
PictureBox1.Image?.Dispose()
PictureBox1.Image = Image.FromStream(New MemoryStream(data))
End Sub))
Catch ex As Exception
' The exception hadling can be quite extensive here, since many factor can cause it:
' No server response, no Internet connection, internal server (500+) faults etc.
Console.WriteLine(ex.Message)
End Try
End Sub
tokyoTimer.Enabled = True
End Sub
Private Sub btnStop_Click(sender As Object, e As EventArgs) Handles btnStop.Click
tokyoTimer.Enabled = False
tokyoTimer.Dispose()
tokyoClient?.Dispose()
End Sub
同一过程的异步版本,全部包含在一个类对象中。
The TokyoImagesDownloader
类公开了两个公共方法:
▶ StartDownload()
期望作为参数:
- PictureBox控件用于显示下载的图像
- 下载之间的时间间隔(以秒为单位)。
- 延迟值(以秒为单位)减去当前东京当地时间,以防止服务器返回
404 - Not found
因为请求的图像尚未准备好。
A StopWatch
用于同步下载之间请求的间隔,考虑到下载和显示图像所需的时间,因此图像本身显示的时钟应反映请求的间隔。
▶ StopDownload()
可以随时调用来停止图像的下载。
With:
StartDownload(PictureBox1, 1, 8)
班级被要求展示图像PictureBox1
,每秒下载一张图像,并将当前东京时间延迟 8 秒。
Dim imageDonwloder As TokyoImagesDownloader = Nothing
Private Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click
imageDonwloder = New TokyoImagesDownloader()
imageDonwloder.StartDownload(PictureBox1, 1, 8)
End Sub
Private Sub btnStop_Click(sender As Object, e As EventArgs) Handles btnStop.Click
imageDonwloder.StopDownload()
End Sub
Imports System.IO
Imports System.Net
Public Class TokyoImagesDownloader
Private tokyoClient As WebClient
Private cts As CancellationTokenSource = Nothing
Public Sub StartDownload(canvas As PictureBox, intervalSeconds As Integer, serverTimeDelaySeconds As Integer)
cts = New CancellationTokenSource()
tokyoClient = New WebClient()
Task.Run(Function() DownloadAsync(canvas, intervalSeconds, serverTimeDelaySeconds))
End Sub
Private Async Function DownloadAsync(canvas As PictureBox, intervalSeconds As Integer, serverTimeDelaySeconds As Integer) As Task
Dim downloadTimeWatch As Stopwatch = New Stopwatch()
downloadTimeWatch.Start()
Do
If cts.IsCancellationRequested Then Return
Dim TokyoOffset = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(Date.Now, TimeZoneInfo.Local.Id, "Tokyo Standard Time")
Dim currentImage As String = TokyoOffset.AddSeconds(-serverTimeDelaySeconds).ToString("yyyyMMdd/yyyyMMddHHmmss")
Dim url = New Uri($"http://www.kmoni.bosai.go.jp/data/map_img/RealTimeImg/jma_s/{currentImage}.jma_s.gif")
Try
Dim data = Await tokyoClient.DownloadDataTaskAsync(url)
canvas.BeginInvoke(New MethodInvoker(
Sub()
canvas.Image?.Dispose()
canvas.Image = Image.FromStream(New MemoryStream(data))
End Sub))
Await Task.Delay((intervalSeconds * 1000) - CInt(downloadTimeWatch.ElapsedMilliseconds))
downloadTimeWatch.Restart()
Catch wEx As WebException
Console.WriteLine(wEx.Message)
End Try
Loop
End Function
Public Sub StopDownload()
cts.Cancel()
tokyoClient?.CancelAsync()
tokyoClient?.Dispose()
cts?.Dispose()
End Sub
End Class