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:
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í.
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:
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):
' ***********************************************************************
' 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
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 (?)
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!
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.
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:
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:
DateAndTime.DateDiff(DateInterval.Day, Date1, Date2)
Espero que te sirva, sino para lo que quieres que sirva como ejemplo.
'//////////////////
'////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 (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:
'devuelve 28
Date.DaysInMonth(2015, 2)
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 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:
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
(http://i.imgur.com/L61wEGC.png)
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!
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
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.
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 (http://en.wikibooks.org/wiki/Visual_Basic_.NET/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
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 ;-)