Vaya, recuerdo que estabas haciendo esa tarea en VBS y te ayudé a resolver el algoritmo y otras dudas que tenias, me alegra saber que has trasladado el trabajo a un lenguaje más óptimo como Vb.Net
Hay varias cosas muy incorrectas en el código que has mostrado.
1)
El segundo parámetro de la función "
Enumerable.Range" es un contador, no es el final del rango inicial.
Por lo tanto, en esta instrucción estás generando 1825 valores innecesarios, empezando desde el valor 1772 y acabando en el valor 3596:
Enumerable.Range(1773 - 1, 1825)
Cuando lo que deberías crear es un rango de 53 valores correspondientes a los 53 valores de las semanas GPS de ese año, de esta manera:
Enumerable.Range(1773 - 1, 53)
2)
Los indices en .Net empiezan por 0, no es correcto empezar por 1
For Day As Integer = 1 To DaysInThisYear
Result.Add(Day, GPSWeeks(DatePart(DateInterval.WeekOfYear,
New DateTime(ThisYear, 1, 1).AddDays(Day - 1))))
Next Day
Déjalo así:
For day As Integer = 0 To (totalDaysInYear - 1)
result.Add(day, gpsWeeks(DatePart(DateInterval.WeekOfYear,
New DateTime(year, 1, 1).AddDays(day))))
Next day
3)
A la función "
JulianDate" le das demasiadas vueltas utilizando wrappers de vb6, cuando puedes simplificarlo de esta manera:
Public Function JulianDate(ByVal [date] As Date) As Integer
Return [date].Subtract(New Date([date].Year, 1, 1)).Days + 1
End Function
4)
Las variables Día, Més, y Año (que por cierto, no deberías utilizar caracteres especiales en el nombramiento de las variables), yo las adaptaría en propiedades para añadirle mayor movilidad, y control de errores:
Friend ReadOnly Property GPSDictionary
(ByVal datePicker
As DateTimePicker
) As Dictionary(Of Integer,
Integer) Get
If datePicker IsNot Nothing Then
Return Me.GetGPSDictionary(datePicker)
Else
Throw New ArgumentNullException("datePicker")
Return Nothing
End If
End Get
End Property
Friend ReadOnly Property Day(ByVal datePicker As DateTimePicker) As Integer
Get
If datePicker IsNot Nothing Then
Return datePicker.Value.Day
Else
Throw New ArgumentNullException("datePicker")
Return -1
End If
End Get
End Property
Friend ReadOnly Property Month(ByVal datePicker As DateTimePicker) As Integer
Get
If datePicker IsNot Nothing Then
Return datePicker.Value.Month
Else
Throw New ArgumentNullException("datePicker")
Return -1
End If
End Get
End Property
Friend ReadOnly Property Year(ByVal datePicker As DateTimePicker) As Integer
Get
If datePicker IsNot Nothing Then
Return datePicker.Value.Year
Else
Throw New ArgumentNullException("datePicker")
Return -1
End If
End Get
End Property
5)
El event-handler "DateTimePicker1_ValueChanged" quedaría así:
Private Sub DateTimePicker1_ValueChanged(ByVal sender As Object, ByVal e As EventArgs) _
Handles DateTimePicker1.ValueChanged
Me.txtday.Text = CStr(Me.JulianDate(DirectCast(sender, DateTimePicker).Value))
End Sub
Respondiendo a tu pregunta principal, puedes hacer que la función pida una fecha como parámetro, para poder trabajar con el año de la fecha, y así puedes asignar el rango equivalente al año específico:
Private Function GetGPSDictionary(ByVal datePicker As DateTimePicker) As IDictionary(Of Integer, Integer)
Dim year As Integer = Me.Year(datePicker)
Dim totalDaysInYear As Integer = New Date(year, 1, 1).AddYears(1).Subtract(New Date(year, 1, 1)).Days
Dim gpsWeeks As IEnumerable(Of Integer)
Dim result As IDictionary(Of Integer, Integer)
Select Case year
Case 2014
gpsWeeks = Enumerable.Range(1773 - 1, 53)
Case 2015
gpsWeeks = Enumerable.Range(1825 - 1, 53)
Case 2016
gpsWeeks = Enumerable.Range(1877 - 1, 53)
Case Else ' Año desconocido, lanzar excepción.
Throw New NotImplementedException("En este ejemplo no se ha implementado el calendario GPS para el año especificado.")
End Select
For day As Integer = 0 To (totalDaysInYear - 1)
result.Add(day, gpsWeeks(DatePart(DateInterval.WeekOfYear,
New DateTime(year, 1, 1).AddDays(day))))
Next day
Return result
End Function
De todas formas, quizás podrías automatizar la tarea ya que en un principio y por lo que he visto cada rango parece constar de 53 valores correspondientes a las 53 semanas del calendario GPS en un año con 365 dias, así que yo habia pensado en algo así, el problema es que no da el resultado que debería dar (1820 en vez de 1825) pero si incremento el startingYear a 2010 y el startingGPSWeek al 1564 de ese año 2010 si que da el resultado esperado, así que algún detalle estoy omitiendo respecto a los calendarios y los días en los años, pero te dejo la idea por si quieres perfeccionarla:
Dim startingYear As Integer = 1994
Dim startingGPSWeek As Integer = 723
Dim a As Integer
For x As Integer = startingYear To (year - 1)
Select Case New Date(x, 1, 1).AddYears(1).Subtract(New Date(x, 1, 1)).Days
Case 365 ' days in year
startingGPSWeek += 52
Case 366 ' days in year
startingGPSWeek += 53
End Select
Next
MsgBox(startingGPSWeek)
...
gpsWeeks = Enumerable.Range(startingGPSWeek - 1, 53) ' ajustar el 53 al numero real de semanas GPS
...
EDITO: Por supuesto cabe mencionar que otra alternativa sería obtener el código fuente de la página del año en cuestión y parsearlo, pero me resulta innecesario.
Bueno, te dejo el código completo con las modificaciones que mencioné, no estoy seguro de haber comprobado correctamente que todos los días devuelvan el valor esperado:
Public Class TestForm
#Region " Properties "
''' <summary>
''' Gets the GPS dictionary according to the specified <see cref="DateTimePicker"/> current year.
''' </summary>
Friend ReadOnly Property GPSDictionary(ByVal datePicker As DateTimePicker) As IDictionary(Of Integer, Integer)
Get
If datePicker IsNot Nothing Then
Return Me.GetGPSDictionary(datePicker)
Else
Throw New ArgumentNullException("datePicker")
Return Nothing
End If
End Get
End Property
''' <summary>
''' Gets the day of the specified <see cref="DateTimePicker"/>.
''' </summary>
''' <value>The year.</value>
''' <exception cref="System.ArgumentNullException">datePicker</exception>
Friend ReadOnly Property Day(ByVal datePicker As DateTimePicker) As Integer
Get
If datePicker IsNot Nothing Then
Return datePicker.Value.Day
Else
Throw New ArgumentNullException("datePicker")
Return -1
End If
End Get
End Property
''' <summary>
''' Gets the month of the specified <see cref="DateTimePicker"/>.
''' </summary>
''' <value>The year.</value>
''' <exception cref="System.ArgumentNullException">datePicker</exception>
Friend ReadOnly Property Month(ByVal datePicker As DateTimePicker) As Integer
Get
If datePicker IsNot Nothing Then
Return datePicker.Value.Month
Else
Throw New ArgumentNullException("datePicker")
Return -1
End If
End Get
End Property
''' <summary>
''' Gets the year of the specified <see cref="DateTimePicker"/>.
''' </summary>
''' <value>The year.</value>
''' <exception cref="System.ArgumentNullException">datePicker</exception>
Friend ReadOnly Property Year(ByVal datePicker As DateTimePicker) As Integer
Get
If datePicker IsNot Nothing Then
Return datePicker.Value.Year
Else
Throw New ArgumentNullException("datePicker")
Return -1
End If
End Get
End Property
#End Region
#Region " Event-Handlers "
''' <summary>
''' Handles the ValueChanged event of the DateTimePicker1 control.
''' </summary>
''' <param name="sender">The source of the event.</param>
''' <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
Private Sub DateTimePicker1_ValueChanged(ByVal sender As Object, ByVal e As EventArgs) _
Handles DateTimePicker1.ValueChanged
Dim datePicker As DateTimePicker = DirectCast(sender, DateTimePicker)
Me.txtday.Text = CStr(Me.JulianDate(datePicker.Value))
'Try
' ' MsgBox(GPSDictionary(datePicker)(1))
' MsgBox(GPSDictionary(datePicker)(3))
'Catch ex As Exception
' MsgBox(ex.Message)
'End Try
End Sub
#End Region
#Region " Misc. Date Functions "
''' <summary>
''' Converts a date to the first day's date of the specified <see cref="Date"/> instance,
''' and returns the substracted date difference, in days.
''' Eg. 28/02/2015 > 01/01/2015 = 31 days in Jan + 28 days in Feb = 59 days
''' </summary>
''' <param name="date">The <see cref="Date"/> instance.</param>
''' <returns>The substracted date difference, in days.</returns>
Public Function JulianDate(ByVal [date] As Date) As Integer
' Set the passed date to: 01/01/YYYY (day/month/year)
Dim dateFirstDay As New Date([date].Year, 1, 1)
' Return the substracted date difference.
Return [date].Subtract(dateFirstDay).Days + 1
End Function
''' <summary>
''' Gets the GPS dictionary.
''' </summary>
''' <param name="datePicker">The <see cref="DateTimePicker"/> instance.</param>
''' <returns>IDictionary(Of System.Int32, System.Int32).</returns>
''' <exception cref="System.NotImplementedException">
''' En este ejemplo no se ha implementado el calendario GPS para el año especificado.
''' </exception>
Private Function GetGPSDictionary(ByVal datePicker As DateTimePicker) As IDictionary(Of Integer, Integer)
Dim year As Integer = Me.Year(datePicker)
Dim totalDaysInYear As Integer = New Date(year, 1, 1).AddYears(1).Subtract(New Date(year, 1, 1)).Days
Dim gpsWeeks As IEnumerable(Of Integer)
Dim result As IDictionary(Of Integer, Integer)
Select Case year
Case 2014
gpsWeeks = Enumerable.Range(1773 - 1, 53)
Case 2015
gpsWeeks = Enumerable.Range(1825 - 1, 53)
Case 2016
gpsWeeks = Enumerable.Range(1877 - 1, 53)
Case Else ' Año desconocido, lanzar excepción.
Throw New NotImplementedException("En este ejemplo no se ha implementado el calendario GPS para el año especificado.")
End Select
For day As Integer = 0 To (totalDaysInYear - 1)
result.Add(day, gpsWeeks(DatePart(DateInterval.WeekOfYear,
New DateTime(year, 1, 1).AddDays(day))))
Next day
Return result
End Function
#End Region
End Class
Saludos