Cuenta regresiva a partir de una fecha (VB.Net)

Iniciado por #Aitor, 23 Septiembre 2015, 16:26 PM

0 Miembros y 1 Visitante están viendo este tema.

#Aitor

Código (vbnet) [Seleccionar]

   Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
       '  Dim Año As Integer = Microsoft.VisualBasic.DateAndTime.Year(Now) '2015

       Dim Mes As Integer = Microsoft.VisualBasic.DateAndTime.Month(Now) ' Mes 9
       Dim Dia As Integer = Microsoft.VisualBasic.DateAndTime.Day(Now)
       Dim Hora As Integer = Microsoft.VisualBasic.DateAndTime.Hour(Now)
       Dim Minuto As Integer = Microsoft.VisualBasic.DateAndTime.Minute(Now)
       Dim Segundo As Integer = Microsoft.VisualBasic.DateAndTime.Second(Now)


       Dim MesAni As Integer = 10
       Dim DiaAni As Integer = 5
       Dim HoraAni As Integer = 23
       Dim MinutoAni As Integer = 59
       Dim SegundoAni As Integer = 59

       Dim Mesrestante As Integer = MesAni - Mes
       Dim Diarestante As Integer = DiaAni - Dia
       Dim Horarestante As Integer = HoraAni - Hora
       Dim Minutorestante As Integer = MinutoAni - Minuto
       Dim Segundorestante As Integer = SegundoAni - Segundo

       Label1.Text = "Dias: " & Diarestante & " Horas: " & Horarestante & " Minutos " & Minutorestante & " Segundos: " & Segundorestante
       Label1.Show()

   End Sub



La idea es hacer una cuenta regresiva que este en una continua actualización, a partir de una fecha clave, y la fecha base del ordenador.

El problema aquí está en que el mes no es el mismo, y por lo tanto la variable Diarestante da un valor negativo. ¿Cómo solucionar eso? O en su defecto alguna forma mejor de hacerlo.

La idea principal es que no se muestre lo que contiene el programa hasta ese día, supongo que para saber si se ha pasado el día basta con comprobar que el díaActual sea mayor que el diaAni.


Edito:

Para arreglarlo de una forma cutre:

Código (vbnet) [Seleccionar]
        Dim Mes As Integer = Microsoft.VisualBasic.DateAndTime.Month(Now) ' Mes 9
        Dim Dia As Integer = Microsoft.VisualBasic.DateAndTime.Day(Now)
        Dim Hora As Integer = Microsoft.VisualBasic.DateAndTime.Hour(Now)
        Dim Minuto As Integer = Microsoft.VisualBasic.DateAndTime.Minute(Now)
        Dim Segundo As Integer = Microsoft.VisualBasic.DateAndTime.Second(Now)


        Dim MesAni As Integer = 10
        Dim DiaAni As Integer = 278
        Dim HoraAni As Integer = 23
        Dim MinutoAni As Integer = 59
        Dim SegundoAni As Integer = 59

        Select Case Dia
            Case 23
                Dia = 266
            Case 24
                Dia = 267
            Case 25
                Dia = 268
            Case 26
                Dia = 269
            Case 27
                Dia = 270
            Case 28
                Dia = 271
            Case 29
                Dia = 272
            Case 30
                Dia = 273
            Case 1
                Dia = 274
            Case 2
                Dia = 275
            Case 3
                Dia = 276
            Case 4
                Dia = 277
            Case 5
                Dia = 278
        End Select

        Dim Mesrestante As Integer = MesAni - Mes
        Dim Diarestante As Integer = DiaAni - Dia
        Dim Horarestante As Integer = HoraAni - Hora
        Dim Minutorestante As Integer = MinutoAni - Minuto
        Dim Segundorestante As Integer = SegundoAni - Segundo


        Label1.Text = "Dias: " & Diarestante & " Horas: " & Horarestante & " Minutos " & Minutorestante & " Segundos: " & Segundorestante
        Label1.Show()


De esta forma con los casos me aseguro de que tengan el dia correspondiente a su dia en base a los 365 dias posibles...

Pero claro, esto solo sirve como un apaño para solucionar mi problema suponiendo que la cuenta regresiva es de máximo 1 mes. Sigo sin saber como solucionar el problema en sí.
Mi algoritmo en PHP (estupideces y más).
Código (php) [Seleccionar]
while($Se_feliz){
  Piensa_un_OBJETIVO(); // Sin excusas!
  if($Tienes_un_objetivo){
    Suspira(); // Sé paciente.
    if($Consigues_el_objetivo){ echo "¡Felicidades #Aitor!";return;
      //RETURN; ¿O volvemos a empezar?
    }else{
      Inténtalo_de_nuevo();
    }
  }
}

Eleкtro

#1
Cita de: #Aitor en 23 Septiembre 2015, 16:26 PM¿Cómo solucionar eso? O en su defecto alguna forma mejor de hacerlo.

Estás siguiendo el camino equivocado.

Usa un TimeSpan.




Tenia un viejo código que desarrollé el año pasado para medir el tiempo de forma amistosa, para usar un cronómetro o un temporizador/cuenta atrás de forma sencilla. He refactorizado un poco el código (por eso he tardado en responderte).

Para tus necesidades, podrías utilizarlo de la siguiente manera:
Código (vbnet) [Seleccionar]
Public NotInheritable Class Form1 : Inherits Form

   ''' <summary>
   ''' The <see cref="TimeMeasurer"/> instance that measure time intervals.
   ''' </summary>
   Private WithEvents countDown As New TimeMeasurer With {.UpdateInterval = 100}

   Private Shadows Sub Load() Handles MyBase.Load

       ' Medir el lapso de 1 mes desde la fecha y hora actual.
       Me.countDown.Start(DateTime.Now, DateTime.Now.AddMonths(1))

   End Sub

   ''' <summary>
   ''' Handles the TimeUpdated event of the countdown instance.
   ''' </summary>
   ''' <param name="sender">The source of the event.</param>
   ''' <param name="e">The <see cref="TimeMeasurer.TimeUpdatedEventArgs"/> instance containing the event data.</param>
   Private Sub Countdown_TimeUpdated(ByVal sender As Object, ByVal e As TimeMeasurer.TimeUpdatedEventArgs) _
   Handles countDown.TimeUpdated

       Me.lblCountDown.Text = String.Format("Days:{0:00} Hours:{1:00} Minutes:{2:00} Seconds:{3:00}",
                                           e.Remaining.Days, e.Remaining.Hours, e.Remaining.Minutes, e.Remaining.Seconds)

   End Sub

End Class



El código fuente (version actualizada y mejor refactorizada):
Código (vbnet) [Seleccionar]
' ***********************************************************************
' Author           : Elektro
' Last Modified On : 26-September-2015
' ***********************************************************************
' <copyright file="TimeMeasurer.vb" company="Elektro Studios">
'     Copyright (c) Elektro Studios. All rights reserved.
' </copyright>
' ***********************************************************************

#Region " Usage Examples "

#End Region

#Region " Option Statements "

Option Strict On
Option Explicit On
Option Infer Off

#End Region

#Region " Imports "

Imports System
Imports System.Diagnostics
Imports System.Linq
Imports System.Windows.Forms

#End Region

''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Measures the elapsed and/or remaining time of a time interval.
''' The time measurer can be used as a chronometer or a countdown.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
Public NotInheritable Class TimeMeasurer : Implements IDisposable

#Region " Objects "

   ''' ----------------------------------------------------------------------------------------------------
   ''' <summary>
   ''' An <see cref="Stopwatch"/> instance to retrieve the elapsed time. (chronometer)
   ''' </summary>
   ''' ----------------------------------------------------------------------------------------------------
   Private timeElapsed As Stopwatch

   ''' ----------------------------------------------------------------------------------------------------
   ''' <summary>
   ''' A <see cref="TimeSpan"/> instance to retrieve the remaining time. (countdown)
   ''' </summary>
   ''' ----------------------------------------------------------------------------------------------------
   Private timeRemaining As TimeSpan

   ''' ----------------------------------------------------------------------------------------------------
   ''' <summary>
   ''' A <see cref="Timer"/> instance that updates the elapsed and remaining time, and also raise <see cref="TimeMeasurer"/> events.
   ''' </summary>
   ''' ----------------------------------------------------------------------------------------------------
   Private WithEvents measureTimer As Timer

   ''' ----------------------------------------------------------------------------------------------------
   ''' <summary>
   ''' Flag that indicates wheter this <see cref="TimeMeasurer"/> instance has finished to measure time interval.
   ''' </summary>
   ''' ----------------------------------------------------------------------------------------------------
   Private isFinished As Boolean

#End Region

#Region " Properties "

   ''' ----------------------------------------------------------------------------------------------------
   ''' <summary>
   ''' Gets the maximum time that the <see cref="TimeMeasurer"/> can measure, in milliseconds.
   ''' </summary>
   ''' ----------------------------------------------------------------------------------------------------
   ''' <value>
   ''' The maximum time that the <see cref="TimeMeasurer"/> can measure, in milliseconds.
   ''' </value>
   ''' ----------------------------------------------------------------------------------------------------
   Public Shared ReadOnly Property MaxValue As Double
       Get
           Return (TimeSpan.MaxValue.TotalMilliseconds - 1001.0R)
       End Get
   End Property

   ''' ----------------------------------------------------------------------------------------------------
   ''' <summary>
   ''' Gets the current state of this <see cref="TimeMeasurer"/> instance.
   ''' </summary>
   ''' ----------------------------------------------------------------------------------------------------
   ''' <value>
   ''' The update interval.
   ''' </value>
   ''' ----------------------------------------------------------------------------------------------------
   Public ReadOnly Property State As TimeMeasurerState
       Get
           If (Me.timeElapsed Is Nothing) OrElse (Me.isFinished) Then
               Return TimeMeasurerState.Disabled

           ElseIf Not Me.timeElapsed.IsRunning Then
               Return TimeMeasurerState.Paused

           Else
               Return TimeMeasurerState.Enabled

           End If
       End Get
   End Property

   ''' ----------------------------------------------------------------------------------------------------
   ''' <summary>
   ''' Gets or sets the update interval.
   ''' Maximum value is 1000 (1 second).
   ''' </summary>
   ''' ----------------------------------------------------------------------------------------------------
   ''' <value>
   ''' The update interval.
   ''' </value>
   ''' ----------------------------------------------------------------------------------------------------
   ''' <exception cref="ArgumentException">
   ''' A value smaller than 1000 is required.;value
   ''' </exception>
   Public Property UpdateInterval As Integer
       Get
           Return Me.updateIntervalB
       End Get
       <DebuggerHidden>
       <DebuggerStepThrough>
       Set(ByVal value As Integer)
           If (value > 1000) Then
               Throw New ArgumentException(message:="A value smaller than 1000 is required.", paramName:="value")
           Else
               Me.updateIntervalB = value
               If (Me.measureTimer IsNot Nothing) Then
                   Me.measureTimer.Interval = value
               End If
           End If
       End Set
   End Property
   ''' <summary>
   ''' The update interval.
   ''' </summary>
   Private updateIntervalB As Integer = 100I

#End Region

#Region " Enumerations "

   ''' ----------------------------------------------------------------------------------------------------
   ''' <summary>
   ''' Specifies the current state of a <see cref="TimeMeasurer"/> instance.
   ''' </summary>
   ''' ----------------------------------------------------------------------------------------------------
   Public Enum TimeMeasurerState As Integer

       ''' <summary>
       ''' The <see cref="TimeMeasurer"/> is running.
       ''' </summary>
       Enabled = &H0I

       ''' <summary>
       ''' The <see cref="TimeMeasurer"/> is paused.
       ''' </summary>
       Paused = &H1I

       ''' <summary>
       ''' The <see cref="TimeMeasurer"/> is fully stopped, it cannot be resumed.
       ''' </summary>
       Disabled = &H2I

   End Enum

#End Region

#Region " Events "

   ''' ----------------------------------------------------------------------------------------------------
   ''' <summary>
   ''' Occurs when the elapsed/remaining time updates.
   ''' </summary>
   ''' ----------------------------------------------------------------------------------------------------
   Public Event TimeUpdated(ByVal sender As Object, ByVal e As TimeUpdatedEventArgs)

#Region " Time Updated EventArgs "

   ''' ----------------------------------------------------------------------------------------------------
   ''' <summary>
   ''' Defines the <see cref="TimeUpdated"/> event arguments.
   ''' </summary>
   ''' ----------------------------------------------------------------------------------------------------
   Public NotInheritable Class TimeUpdatedEventArgs : Inherits EventArgs

#Region " Properties "

       ''' ----------------------------------------------------------------------------------------------------
       ''' <summary>
       ''' Gets the elapsed time.
       ''' </summary>
       ''' ----------------------------------------------------------------------------------------------------
       ''' <value>
       ''' The elapsed time.
       ''' </value>
       ''' ----------------------------------------------------------------------------------------------------
       Public ReadOnly Property Elapsed As TimeSpan
           Get
               Return Me.elapsedB
           End Get
       End Property
       ''' ----------------------------------------------------------------------------------------------------
       ''' <summary>
       ''' ( Baking Field )
       ''' The elapsed time.
       ''' </summary>
       ''' ----------------------------------------------------------------------------------------------------
       Private ReadOnly elapsedB As TimeSpan

       ''' ----------------------------------------------------------------------------------------------------
       ''' <summary>
       ''' Gets the remaining time.
       ''' </summary>
       ''' ----------------------------------------------------------------------------------------------------
       ''' <value>
       ''' The remaining time.
       ''' </value>
       ''' ----------------------------------------------------------------------------------------------------
       Public ReadOnly Property Remaining As TimeSpan
           Get
               Return Me.remainingB
           End Get
       End Property
       ''' ----------------------------------------------------------------------------------------------------
       ''' <summary>
       ''' ( Baking Field )
       ''' The remaining time.
       ''' </summary>
       ''' ----------------------------------------------------------------------------------------------------
       Private ReadOnly remainingB As TimeSpan

       ''' ----------------------------------------------------------------------------------------------------
       ''' <summary>
       ''' Gets the goal time.
       ''' </summary>
       ''' ----------------------------------------------------------------------------------------------------
       ''' <value>
       ''' The goal time.
       ''' </value>
       ''' ----------------------------------------------------------------------------------------------------
       Public ReadOnly Property Goal As TimeSpan
           Get
               Return Me.goalB
           End Get
       End Property
       ''' ----------------------------------------------------------------------------------------------------
       ''' <summary>
       ''' ( Baking Field )
       ''' The goal time.
       ''' </summary>
       ''' ----------------------------------------------------------------------------------------------------
       Private ReadOnly goalB As TimeSpan

#End Region

#Region " Constructors "

       ''' ----------------------------------------------------------------------------------------------------
       ''' <summary>
       ''' Prevents a default instance of the <see cref="TimeUpdatedEventArgs"/> class from being created.
       ''' </summary>
       ''' ----------------------------------------------------------------------------------------------------
       Private Sub New()
       End Sub

       ''' ----------------------------------------------------------------------------------------------------
       ''' <summary>
       ''' Initializes a new instance of the <see cref="TimeUpdatedEventArgs"/> class.
       ''' </summary>
       ''' ----------------------------------------------------------------------------------------------------
       ''' <param name="elapsed">
       ''' The elapsed time.
       ''' </param>
       '''
       ''' <param name="remaining">
       ''' The remaining time.
       ''' </param>
       '''
       ''' <param name="goal">
       ''' The goal time.
       ''' </param>
       ''' ----------------------------------------------------------------------------------------------------
       Public Sub New(ByVal elapsed As TimeSpan,
                      ByVal remaining As TimeSpan,
                      ByVal goal As TimeSpan)

           Me.elapsedB = elapsed
           Me.remainingB = remaining
           Me.goalB = goal

       End Sub

#End Region

   End Class

#End Region

#End Region

#Region " Public Methods "

   ''' ----------------------------------------------------------------------------------------------------
   ''' <summary>
   ''' Starts the time interval measurement.
   ''' </summary>
   ''' ----------------------------------------------------------------------------------------------------
   ''' <param name="milliseconds">
   ''' The time interval to measure, in milliseconds.
   ''' </param>
   ''' ----------------------------------------------------------------------------------------------------
   ''' <exception cref="ArgumentOutOfRangeException">
   ''' milliseconds;A value smaller than <see cref="TimeMeasurer.MaxValue"/> is required.
   ''' </exception>
   '''
   ''' <exception cref="ArgumentOutOfRangeException">
   ''' milliseconds;A value greater than 0 is required.
   ''' </exception>
   ''' ----------------------------------------------------------------------------------------------------
   <DebuggerHidden>
   <DebuggerStepThrough>
   Public Sub Start(ByVal milliseconds As Double)

       If (milliseconds > TimeMeasurer.MaxValue) Then
           Throw New ArgumentOutOfRangeException(paramName:="milliseconds",
                                                 message:=String.Format("A value smaller than {0} is required.", TimeMeasurer.MaxValue))

       ElseIf (milliseconds <= 0) Then
           Throw New ArgumentOutOfRangeException(paramName:="milliseconds",
                                                 message:="A value greater than 0 is required.")

       Else
           Me.timeElapsed = New Stopwatch
           Me.timeRemaining = TimeSpan.FromMilliseconds(milliseconds)
           Me.measureTimer = New Timer With
              {
                .Tag = milliseconds,
                .Interval = Me.updateIntervalB,
                .Enabled = True
              }

           Me.isFinished = False
           Me.timeElapsed.Start()
           Me.measureTimer.Start()

       End If

   End Sub

   ''' ----------------------------------------------------------------------------------------------------
   ''' <summary>
   ''' Starts a time interval measurement given a difference between two dates.
   ''' </summary>
   ''' ----------------------------------------------------------------------------------------------------
   ''' <param name="startDate">
   ''' The starting date.
   ''' </param>
   '''
   ''' <param name="endDate">
   ''' The ending date.
   ''' </param>
   ''' ----------------------------------------------------------------------------------------------------
   <DebuggerHidden>
   <DebuggerStepThrough>
   Public Sub Start(ByVal startDate As Date,
                    ByVal endDate As Date)

       Me.Start(endDate.Subtract(startDate).TotalMilliseconds)

   End Sub

   ''' ----------------------------------------------------------------------------------------------------
   ''' <summary>
   ''' Starts a time interval measurement given a <see cref="TimeSpan"/>.
   ''' </summary>
   ''' ----------------------------------------------------------------------------------------------------
   ''' <param name="time">
   ''' A <see cref="TimeSpan"/> instance that contains the time interval.
   ''' </param>
   ''' ----------------------------------------------------------------------------------------------------
   <DebuggerHidden>
   <DebuggerStepThrough>
   Public Sub Start(ByVal time As TimeSpan)

       Me.Start(time.TotalMilliseconds)

   End Sub

   ''' ----------------------------------------------------------------------------------------------------
   ''' <summary>
   ''' Pauses the time interval measurement.
   ''' </summary>
   ''' ----------------------------------------------------------------------------------------------------
   ''' <exception cref="Exception">
   ''' TimeMeasurer is not running.
   ''' </exception>
   ''' ----------------------------------------------------------------------------------------------------
   <DebuggerHidden>
   <DebuggerStepThrough>
   Public Sub Pause()

       If (Me.State <> TimeMeasurerState.Enabled) Then
           Throw New Exception("TimeMeasurer is not running.")

       Else
           Me.measureTimer.Stop()
           Me.timeElapsed.Stop()

       End If

   End Sub

   ''' ----------------------------------------------------------------------------------------------------
   ''' <summary>
   ''' Resumes the time interval measurement.
   ''' </summary>
   ''' ----------------------------------------------------------------------------------------------------
   ''' <exception cref="Exception">
   ''' TimeMeasurer is not paused.
   ''' </exception>
   ''' ----------------------------------------------------------------------------------------------------
   <DebuggerHidden>
   <DebuggerStepThrough>
   Public Sub [Resume]()

       If (Me.State <> TimeMeasurerState.Paused) Then
           Throw New Exception("TimeMeasurer is not paused.")

       Else
           Me.measureTimer.Start()
           Me.timeElapsed.Start()

       End If

   End Sub

   ''' <summary>
   ''' Stops the time interval measurement.
   ''' </summary>
   ''' ----------------------------------------------------------------------------------------------------
   ''' <exception cref="Exception">
   ''' TimeMeasurer is not running.
   ''' </exception>
   ''' ----------------------------------------------------------------------------------------------------
   <DebuggerHidden>
   <DebuggerStepThrough>
   Public Sub [Stop]()

       If (Me.State = TimeMeasurerState.Disabled) Then
           Throw New Exception("TimeMeasurer is not running.")

       Else
           Me.Reset()
           Me.isFinished = True

           Me.measureTimer.Stop()
           Me.timeElapsed.Stop()

       End If

   End Sub

#End Region

#Region " Private Methods "

   ''' ----------------------------------------------------------------------------------------------------
   ''' <summary>
   ''' Stops Time intervals and resets the elapsed and remaining time to zero.
   ''' </summary>
   ''' ----------------------------------------------------------------------------------------------------
   Private Sub Reset()

       Me.measureTimer.Stop()
       Me.timeElapsed.Reset()

   End Sub

#End Region

#Region " Event Handlers "

   ''' ----------------------------------------------------------------------------------------------------
   ''' <summary>
   ''' Handles the <see cref="Timer.Tick"/> event of the <see cref="MeasureTimer"/> timer.
   ''' </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 MeasureTimer_Tick(ByVal sender As Object, ByVal e As EventArgs) _
   Handles measureTimer.Tick

       Dim timeDiff As TimeSpan = (Me.timeRemaining - Me.timeElapsed.Elapsed)

       ' If finished...
       If (timeDiff.TotalMilliseconds <= 0.0R) _
       OrElse (Me.timeElapsed.ElapsedMilliseconds > DirectCast(Me.measureTimer.Tag, Double)) Then

           Me.Reset()
           Me.isFinished = True

           If (Me.TimeUpdatedEvent IsNot Nothing) Then
               Dim goal As TimeSpan = TimeSpan.FromMilliseconds(DirectCast(Me.measureTimer.Tag, Double))
               RaiseEvent TimeUpdated(sender, New TimeUpdatedEventArgs(goal, TimeSpan.FromMilliseconds(0.0R), goal))
           End If

       Else ' If not finished...
           If (Me.TimeUpdatedEvent IsNot Nothing) Then
               RaiseEvent TimeUpdated(sender, New TimeUpdatedEventArgs(Me.timeElapsed.Elapsed,
                                                                       timeDiff,
                                                                       TimeSpan.FromMilliseconds(DirectCast(Me.measureTimer.Tag, Double))))
           End If

       End If

   End Sub

#End Region

#Region " IDisposable Support "

   ''' ----------------------------------------------------------------------------------------------------
   ''' <summary>
   ''' To detect redundant calls when disposing.
   ''' </summary>
   ''' ----------------------------------------------------------------------------------------------------
   Private isDisposed As Boolean = False

   ''' ----------------------------------------------------------------------------------------------------
   ''' <summary>
   ''' Releases all the resources used by this instance.
   ''' </summary>
   ''' ----------------------------------------------------------------------------------------------------
   <DebuggerStepThrough>
   Public Sub Dispose() Implements IDisposable.Dispose
       Me.Dispose(isDisposing:=True)
       GC.SuppressFinalize(obj:=Me)
   End Sub

   ''' ----------------------------------------------------------------------------------------------------
   ''' <summary>
   ''' Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
   ''' Releases unmanaged and - optionally - managed resources.
   ''' </summary>
   ''' ----------------------------------------------------------------------------------------------------
   ''' <param name="isDisposing">
   ''' <see langword="True"/> to release both managed and unmanaged resources;
   ''' <see langword="False"/> to release only unmanaged resources.
   ''' </param>
   ''' ----------------------------------------------------------------------------------------------------
   <DebuggerStepThrough>
   Private Sub Dispose(ByVal isDisposing As Boolean)

       If (Not Me.isDisposed) AndAlso (isDisposing) Then

           If (Me.measureTimer IsNot Nothing) Then
               Me.measureTimer.Stop()
               Me.measureTimer.Dispose()
           End If

           If (Me.TimeUpdatedEvent IsNot Nothing) Then
               RemoveHandler Me.TimeUpdated, Me.TimeUpdatedEvent
           End If

       End If

       Me.isDisposed = True

   End Sub

#End Region

End Class









#Aitor

Siento haberte hecho modificar parte de tu código, pero mi nivel de programación es pésimo y no entiendo nada...

Estoy en shock (?)
Mi algoritmo en PHP (estupideces y más).
Código (php) [Seleccionar]
while($Se_feliz){
  Piensa_un_OBJETIVO(); // Sin excusas!
  if($Tienes_un_objetivo){
    Suspira(); // Sé paciente.
    if($Consigues_el_objetivo){ echo "¡Felicidades #Aitor!";return;
      //RETURN; ¿O volvemos a empezar?
    }else{
      Inténtalo_de_nuevo();
    }
  }
}

Eleкtro

Cita de: #Aitor en 23 Septiembre 2015, 18:53 PM
Siento haberte hecho modificar parte de tu código, pero mi nivel de programación es pésimo y no entiendo nada...

Estoy en shock (?)

La class TimeMeasurer que compartí, solo tienes que copiarla y pegarla en un nuevo archivo.vb, el archivo lo creas desde Visual Studio, Add Item -> Class, y ahí pegas todo el código tal cual lo puse.

La class expone varios eventos, los que te interesan son TimeMeasurer.RemainingTimeUpdated y TimeMeasurer.RemainingTimeFinished, el primer evento se dispara al mismo tiempo que el Timer interno de la class tickea (el intervalo de actualización lo puedes modificar usando la propiedad TimeMeasurer.UpdateInterval), y el otro evento se dispara cuando la cuenta atrás llega a cero.

Arriba te mostré un ejemplo de lo que acabo de mencionar respecto a cómo suscribirte a esos eventos y cómo usar la class en general, ¿hay algo que sigas sin entender?.

Saludos!








Lekim

#4
Hola Aitor

Te explico, respondí a tu pregunta en el foro de VisualBasic, de hecho al final te decía que eso no era para .Net.  así que he copiado la respuesta y ahora la pongo aquí (añadiendo alguna cosa).

Veo que ya te ha respondido Elektro, pero él es un programador muy avanzado y a veces su código puede ser un poco difícil de entender como ya has mencionado. Yo soy más como tu así que no creo que tengas problemas para entender el mío.





Código (vbnet) [Seleccionar]
   Label1.Text = "Dias: " & (-1 * Diarestante) & " Horas: " & Horarestante & " Minutos " & Minutorestante & " Segundos: " & Segundorestante




No soy profesional pero sabía un poco sobre el tema porque hice un programa en el que tenía que ir restando días a partir de una determinada fecha.  Así que he hecho esta otra forma. Creo que se puede simplificar más o hacer de otra manera.


Ejemplo, la línea siguiente resta 3 días a la fecha 5/8/2015 y se obtiene 3/12/2015:
Código (vbnet) [Seleccionar]

       Dim Fecha As Date = "#5/12/2015#"
       Me.Text = DateAdd(DateInterval.Day, -2, Fecha)


Esta otra obtiene la diferéncia en días, meses, años, horas, etc te sadrá valor negativo o postitivo dependiendo de si Date1 es anterior o posterior a Date2. En este caso obtiene días porque he puesto DateInterval.Day, si quieres meses tienes que poner DateInterval.Month, y así sucesivamente:
Código (vbnet) [Seleccionar]

DateAndTime.DateDiff(DateInterval.Day, Date1, Date2)


Espero que te sirva, sino para lo que quieres que sirva como ejemplo.

Código (vbnet) [Seleccionar]

'//////////////////
'////Por Lekim ////
'///29/09/2015/////
'//////////////////
Option Explicit On
Option Infer Off
Option Strict On
Public Class Form1

   Dim DiaMenos As Integer
   Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
       '  Dim Año As Integer = Microsoft.VisualBasic.DateAndTime.Year(Now) '2015

       Dim FechaLim As Object = "#5/10/2015#" 'Fecha futura límite
       Dim Reloj24h As Object = "#23:59:59#" '24 horas del día a restar
       Dim RelojNow As Object = DateAndTime.TimeValue(CStr(Date.Now))
       Dim TotalDias As Integer = CInt(DateAndTime.DateDiff(DateInterval.Day, CDate(Date.Now), CDate(FechaLim))) 'Días hasta la fecha límite
       Dim DiasRestantes As Integer 'Dias restante que quedan
       Dim CronoTime As Date 'Nueva tiempo resultado de ir restandos segundos
       Dim CronoFecha As Object = String.Empty 'Nueva fecha resultado de ir restando días

       Dim m As Integer : Dim h As Integer : Dim s As Integer
       h = CInt((DateDiff(DateInterval.Minute, CDate(RelojNow), CDate(Reloj24h)) / 60))  'Obtiene las horas
       m = CInt(DateDiff(DateInterval.Minute, CDate(RelojNow), CDate(Reloj24h)) - (h * 60)) 'Obtiene los minutos
       s = CInt(DateDiff(DateInterval.Second, CDate(RelojNow), CDate(Reloj24h)) - ((h * 3600) + (m * 60)))

       'Resta un segundo
       If h < 0 Then h = h * (-1)
       If m < 0 Then m = m * (-1)
       If s < 0 Then s = s * (-1)
       CronoTime = CDate((h & ":" & m & ":" & s).ToString)

       'Si el cronómentro llega a cero resta un día
       If Hour(CronoTime) = 0 And Minute(CronoTime) = 0 And Second(CronoTime) = 0 Then DiaMenos -= 1

       CronoFecha = DateAdd(DateInterval.Day, DiaMenos, CDate(FechaLim)) 'Obtiene una fecha resultado de restar x días a la fecha límite

       'Convierte las fechas a DATE y obtiene la diferencia de días
       Dim datTim1 As Date = CDate(FechaLim) : Dim datTim2 As Date = CDate(CronoFecha)
       DiasRestantes = CInt(TotalDias - DateAndTime.DateDiff(DateInterval.Day, CDate(datTim2), CDate(datTim1)))

       Label1.Text = _
       "Fecha Actual: " & Strings.FormatDateTime(Date.Now, DateFormat.LongDate) & ControlChars.CrLf & _
       "Fecha Límite: " & Strings.FormatDateTime(CDate(Replace(CStr(CDate(FechaLim)), "#", "", 1)), DateFormat.LongDate) & ControlChars.CrLf &
       "Quedan: " & DiasRestantes & " días " & "y " & Strings.Format(CronoTime, "HH:mm:ss")

   End Sub
End Class


más info:
https://msdn.microsoft.com/es-es/library/b5xbyt6f%28v=vs.90%29.aspx

Saludos





Otra cosa, si quieres saber cuantos días tiene un mes de un determinado año usa:

Código (vbnet) [Seleccionar]

'devuelve 28
Date.DaysInMonth(2015, 2)




Eleкtro

#5
Por si sirve de algo, he vuelto a refactorizar el código fuente para que se entienda mejor, ahora solo expongo UN solo evento al que podemos suscribirnos para obtener el tiempo transcurrido, el tiempo restante, y el tiempo límite o meta.

El ejemplo de arriba también lo he modificado, más simple que esto es imposible ya:

Cita de: http://foro.elhacker.net/net/cuenta_regresiva_a_partir_de_una_fecha_vbnet-t441934.0.html;msg2040412#msg2040412
Código (vbnet) [Seleccionar]
   Public NotInheritable Class Form1 : Inherits Form
   
       Private WithEvents countdown As New TimeMeasurer With {.UpdateInterval = 100}
   
       Private Shadows Sub Load() Handles MyBase.Load
   
           ' Medir el lapso de 1 mes desde la fecha y hora actual.
           Me.countdown.Start(DateTime.Now, DateTime.Now.AddMonths(1))
   
       End Sub
   
       Private Sub Countdown_TimeUpdated(ByVal sender As Object, ByVal e As TimeMeasurer.TimeUpdatedEventArgs) _
       Handles countDown.TimeUpdated
   
           Me.lblCountDown.Text = String.Format("Days:{0:00} Hours:{1:00} Minutes:{2:00} Seconds:{3:00}",
                                                e.Remaining.Days, e.Remaining.Hours, e.Remaining.Minutes, e.Remaining.Seconds)
   
       End Sub
   
   End Class

Basicamente el código fuente que compartí encapsula todos los miembros necesarios para resolver el problema que tienes de una forma amistosa orientada a eventos xD.

De todas formas si aun sigues sin saber cómo utilizarlo a pesar del ejemplo, o si por algún motivo prefieres no usar mi solución entonces ahí tienes la alternativa de @Lekim, aunque os aconsejo a los dos que cambieis los hábitos que están siguiendo ya que son perjudiciales para el aprendizaje, por ejemplo no es necesario la aplicación de operaciones aritméticas para calcular manualmente las horas, dias, minutos y demás, pueden usar las propiedades que expone un objeto TimeSpan o un objeto Date cómo mencioné al principìo!, con eso lo resolverían TODO sin complicarse.




@Lekim, con tu permiso, te muestro como podrías simplificar para mejorar el código que compartiste:

Código (vbnet) [Seleccionar]
Public Class Form1

   Dim culture As CultureInfo = CultureInfo.GetCultureInfo("es-ES")
   Dim fechaLimite As Date = Date.ParseExact("01/10/2015 00:00:00", "dd/MM/yyyy hh:mm:ss", culture, DateTimeStyles.None)

   Private Sub Form1_Shown() Handles MyBase.Shown
       Timer1.Enabled = True
   End Sub

   Private Sub Timer1_Tick() Handles Timer1.Tick

       Dim dateDiff As TimeSpan = fechaLimite.Subtract(Date.Now)
       Dim dateFormat As String = "dddd dd, MMMM, yyyy"

       Dim sb As New StringBuilder
       With sb
           .AppendFormat("Fecha Actual: {0}", Date.Today.ToString(dateFormat, culture))
           .AppendLine()
           .AppendFormat("Fecha Límite: {0}", fechaLimite.ToString(dateFormat, culture))
           .AppendLine()
           .AppendFormat("Quedan: {0}", String.Format("{0:0}d. {1:00}h. {2:00}m. {3:00}s.",
                                                      dateDiff.TotalDays, dateDiff.Hours,
                                                      dateDiff.Minutes, dateDiff.Seconds))
       End With

       Me.Label1.Text = sb.ToString

   End Sub

End Class




También te recomiendo activar las declaraciones "Option" cuando programes bajo VB.Net, verias las decenas de fallos que cometiste en aquél código sin darte cuenta, sobre todo de casting.

Otra recomendación que les hago, eviten CUALQUIER uso de los miembros expuestos en el namespace Microsoft.VisualBasic, cómo por ejemplo DateDiff, DateAdd, FormatDateTime, Len, Mid, etc, evitenlo todo sin excepción, todo eso es morralla rescatada de VisualBasic 6 para familiarizar a los que migran a VB.Net, aunque es puro código .Net pero no tan optimizado, así que deberían usar los equivalentes del resto de la librería de classes de .Net.

Saludos!








Lekim

#6
Hola Elektro. Gracias por el comentario

CitarTambién te recomiendo activar las declaraciones "Option" cuando programes bajo VB.Net

He puesto Option Explicit On a principio de código pero no me muestra ningún fallo. Si que es cierto que hay variables sin uso pero es porque en un principio lo hice de una manera y luego lo cambié, porque en un prinicipio usaba la variable Dim Reloj24h As Object = "#23:59:59#"  y lo le iba restando los segundos con Segundos -=1 y DateAdd pero caí en que no sería correcto decir que desde ahora hasta pasado mañana quedan 1 día y 23:59:59 a no ser que ahora mismo sean  justo las 00:00:00 de la noche. Habría que descontar las horas desde las doce hasta la hora actual. Por eso anulé 'Dim SegundoMenos As Integer, pero aunque estaba, no se usaba. Simplemente lo dejé para que se viera esa opción de hacerlo así.

Bueno, he corregido un poco el código ya que según la hora dabe error en CronoTime (línea 29) y he puesto Option Explicit On. Ejecuto el código y me va perfecto.


En cuanto a la librería de classes de .Net me gustaría que me dijeras como encontrar lo que busco cuando quiero hacer algo porque con los miembros Microsoft.VisualBasic es fácil intuir como contruir el código, además que es muy directo. Es decir, quiero saber la diferencia de fecha lo puedo hacer sólo con una línea de código , pero NO con con las clases de .Net. que son mucho más rebuscadas, como su puede ver en tu conversión. Voy a analizar tu código a ver como se usan esas clases que pones. No hace falta que me las expliques ya experimento yo  ;)

También he visto que usas Shown en lugar de Load, ¿Cuál es la diferencia?


saludos


 




Eleкtro

#7
Cita de: Lekim en 27 Septiembre 2015, 14:30 PM
He puesto Option Explicit On a principio de código pero no me muestra ningún fallo.

Pero no estás activando la opción de los casteos ni desactivando la inferencia de types, solamente activaste la declaración explícita de variables.

Código (vbnet) [Seleccionar]
Option Explicit On
' +
Option Strict On
Option Infer Off


Pruébalo de nuevo y verás de lo que te hablaba. :P

PD: Puedes activar por edefecto esas opciones para todos los proyectos/classes nuevos, en el menú Tools -> Options -> Projects and Solutions -> VB Defaults de Visual Studio.




Cita de: Lekim en 27 Septiembre 2015, 14:30 PMTambién he visto que usas Shown en lugar de Load, ¿Cuál es la diferencia?

El evento Form.Shown se dispara cuando la ventana del Form se muestra.

El evento Form.Load se dispara cuando el Form se carga (esto ocurre antes de mostrar la ventana).

En el ejemplo de arriba lo usé por costumbre, nada relevante.




Cita de: Lekim en 27 Septiembre 2015, 14:30 PMEn cuanto a la librería de classes de .Net me gustaría que me dijeras como encontrar lo que busco cuando quiero hacer algo

Creo que no existe un artículo que especifique esos miembros equivalentes en la documentación de la MSDN, pero si que podemos encontrar esa tabla de miembros equivalentes en otras fuentes:
Visual Basic 6 to .NET Function Equivalents

Si lo que buscas no está ahí entonces siempre puedes formular una pregunta en el foro y con gusto te ayudaré. (pero en otro post. No hagamos demasiado offtopic en este hilo)




Cita de: Lekim en 27 Septiembre 2015, 14:30 PMcon los miembros Microsoft.VisualBasic es fácil intuir como contruir el código, además que es muy directo.

Nombres intuitivos si, pero solo eso. De todas formas los miembros que están fuera de ese namespace también son intuitivos, simplemente los desconocerás, pero intuitivos te aseguro que si lo son.

La gente suele pensar que me quejo demasiado de este asunto en concreto, que no me tengo que obsesionar con tanta "perfección" en el rendimiento por que da igual usar un método u otro con argumentos como los que has expuesto de que "es más intuitivo" o etc, así que despues de esto no se ya que pensarán, pero bueno, supongo que es mi deber intentar defender los buenos hábitos de programación .Net xD.

Para empezar, si aprendes a usar Microsoft.VisualBasic y te acostumbras a ello, en realidad no estás aprendiendo a usar .Net. Digamos que el Namespace Microsoft.VisualBasic es cómo el lenguaje Batch en programación, algo que está ahí, se le llama lenguaje, pero no se puede clasificar cómo lenguaje de programación realmente, pues eso mismo es el namespace Microsoft.VisualBasic, está ahí por cuestiones de compatibilidad, se puede usar siempre que lo necesites, pero lo mejor sería no utilizarlo por que no lo necesitas.

Todo lo que existe en Microsoft.VisualBasic es un código menos optimizado y son miembros con menos overloads (sustitutos). En resumen, la funcionalidad es más limitada.

Aparte, si vieras el código fuente (mediante reflection) verías que no es tan "directo" internamente hablando, hacen muchas vueltas y la mayoría de los métodos no se valen por si mismos así que en realidad son simples wrappers (gracias a dios) de los métodos optimizados de .Net, por ejemplo la función Microsoft.VisualBasic.Strings.Mid() (entre otras) en realidad se limitan a hacer unas evaluaciones irrelevantes del argumento y seguidamente llama a System.String.Substring(), vuelve a hacer las mismas evaluaciones del argumento (si. esto quiere decir que cuando llamas a Mid y a toda esa otra morralla, trabajan innecesareamente x2) y por último devuelve el valor que tenga que devolver, es quien hace el trabajo de verdad.

Aquí puedes ver una referencia del código fuente de la librería de classes de .Net Framework:
http://referencesource.microsoft.com/
(creo que es una referencia parcial)

Saludos








Lekim

Gracias por la ayuda Elektro

He vuelto a retocar mi código y ahora creo que no tiene ningún error, excepto los del uso de los miembros de VisualBasic. Aunque no se puede considerar error, si no como dices una forma poco eficiente de programar en .NET.

Tu información me va de perlas, de nuevo gracias  ;-)