Я изменил метод преобразования DateTime, используя TimeZoneInfo.ConvertTimeBySystemTimeZoneId , передав мои Local TimeZone.Id и "Tokyo Standard Time"
в качестве параметров, чтобы сгенерировать DateTimeOffset это представляет текущий Токио DateTime.
Используя таймер, вычитая 4 секунды из вычисленного DateTimeOffset (DateTimeOffset.AddSeconds(-4)
), изображения загружаются правильно.
► Обратите внимание, что системные часы должны быть синхронизированы с NTP-сервером . 4
секунд - это относительно слабая пропасть, но несинхронизированные часы, конечно, все равно скомпрометируют результат.
РЕДАКТИРОВАТЬ :
Изменено System.Windows.Forms.Timer
на System.Timers.Timer
, поскольку здесь требуется больше времени для загрузки изображения.
Использование BeginInvoke()
для установки PictureBox.Image
, которое почти ничего не требует, препятствует тому, чтобы пользовательский интерфейс заикался при перемещении формы.
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
Асинхронная версия одной и той же процедуры, все содержатся в объекте класса .
Класс TokyoImagesDownloader
предоставляет два открытых метода c:
► StartDownload()
ожидает в качестве аргументов:
1. Элемент управления PicureBox, используемый для отображения загруженного images
2. Интервал в секундах между загрузками.
3. Значение задержки в секундах для вычитания из текущего Токийского местного времени, чтобы предотвратить возврат сервером 404 - Not found
, поскольку запрашиваемое изображение еще не готов.
A StopWatch
используется для синхронизации запрошенного интервала между загрузками с учетом времени, необходимого для загрузки и показа изображения, поэтому часы, показанные на самом изображении, должны отражать запрошенный интервал.
► StopDownload()
можно вызвать в любое время, чтобы остановить загрузку изображений.
С:
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