convertir calendario gregoriano a gps

Iniciado por rochro, 10 Febrero 2015, 17:34 PM

0 Miembros y 2 Visitantes están viendo este tema.

rochro

Hola a todos, quisiera que me ayuden en poder adaptar el código para lo siguiente:

simulación calendario

ver contenido:  http://gps.topografia.upm.es/www/calactal.htm

tengo este codigo:

Código (vbnet) [Seleccionar]

Private Sub DateTimePicker1_ValueChanged(sender As Object, e As EventArgs) Handles DateTimePicker1.ValueChanged

        Dim vDia As String = DateTimePicker1.Value.Day
        Dim vMes As String = DateTimePicker1.Value.Month
        Dim vAño As String = DateTimePicker1.Value.Year

        txtday.Text = Juliandate(DateTimePicker1.Value)

    End Sub

Public Function Juliandate(ByVal dtdate As Date) As Integer

        Dim dtfirstmonthDAY As Date
        Dim dttimepicker As Date

        dtfirstmonthDAY = DateSerial(Year(dtdate), 1, 1)
        dttimepicker = dtdate
        Return CInt(DateDiff(DateInterval.Day, dtfirstmonthDAY, dttimepicker)) + 1

    End Function

Friend ReadOnly GPSDictionary As Dictionary(Of Integer, Integer) = Me.GetGPSDictionary

    Private Function GetGPSDictionary() As Dictionary(Of Integer, Integer)

        Dim ThisYear As Integer = vAño
        Dim DaysInThisYear As Integer = (From month As Integer In Enumerable.Range(1, 12)
                                         Select DateTime.DaysInMonth(ThisYear, month)).Sum
        Dim GPSWeeks As IEnumerable(Of Integer) = Enumerable.Range(1773 - 1, 1825)
        Dim Result As New Dictionary(Of Integer, Integer)
        For Day As Integer = 1 To DaysInThisYear
            Result.Add(Day, GPSWeeks(DatePart(DateInterval.WeekOfYear,
                                              New DateTime(ThisYear, 1, 1).AddDays(Day - 1))))
        Next Day
        Return Result

    End Function


La observación está en la elección de años diferentes. Se que se le está poniendo un limite 1773 a 1825 que corresponde al 2014 pero que podria hacer en caso que quisiera otro año. Que otra lógica se podría pensar.

Gracias por su apoyo.


:-*
 

engel lex

hola,

Qué llevas hecho y qué no te permite resolverlo (que no sabes)

recuerda que el foro es para responder dudas pountuales, no entregar tareas hechas
El problema con la sociedad actualmente radica en que todos creen que tienen el derecho de tener una opinión, y que esa opinión sea validada por todos, cuando lo correcto es que todos tengan derecho a una opinión, siempre y cuando esa opinión pueda ser ignorada, cuestionada, e incluso ser sujeta a burla, particularmente cuando no tiene sentido alguno.

rochro

Cita de: engel lex en 10 Febrero 2015, 17:36 PM
hola,

Qué llevas hecho y qué no te permite resolverlo (que no sabes)

recuerda que el foro es para responder dudas pountuales, no entregar tareas hechas

Disculpa .. ya agregué el código.
Gracias por la atención prestada.

Eleкtro

#3
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:
Citar
Código (vbnet) [Seleccionar]
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:
Código (vbnet) [Seleccionar]
Enumerable.Range(1773 - 1, 53)


2)
Los indices en .Net empiezan por 0, no es correcto empezar por 1
Citar
Código (vbnet,1) [Seleccionar]
       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í:
Código (vbnet) [Seleccionar]
       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:
Código (vbnet) [Seleccionar]
   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:
Código (vbnet) [Seleccionar]

   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í:
Código (vbnet) [Seleccionar]
   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:

Código (vbnet) [Seleccionar]
   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

       result = New Dictionary(Of Integer, Integer)
       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:

Código (vbnet) [Seleccionar]
       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:

Código (vbnet) [Seleccionar]
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

       result = New Dictionary(Of Integer, Integer)
       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








rochro

Cita de: Eleкtro en 11 Febrero 2015, 13:33 PM
Saludos

Hola, habia dejado de lado este tema ya que me estaba dando por vencida pero ahora la idea la tengo algo más clara. Lo que pasa es que las semanas gps tienen una continuidad:

semana gps 1512 --> 28/12/08 al 3/1/09
semana gps 1513 --> 4/1/09 al 10/1/09 

Yo quisiera que el calendario inicie desde la semana 1512 pero no se como relacionarlo con la fecha del calendario gregoriano (el que todos sabemos) ya que se presentan intersecciones como:

semana gps 1564 --> 27/12/09 al 2/1/10
.
.
Lo que se me ocurre es empezar con el 1512 = 28/12/08 + 7 días y así sucesivamente pero no logro saber como hacerlo.

Espero su comprensión y gracias por la atención.