Trabalhando com TimeSpan em C#
Veja neste artigo como trabalhar com a estrutura TimeSpan para realizar cálculos de diferenças com datas e horas. Será utilizada a linguagem C#, mas os conceitos se aplicam igualmente à linguagem VB.NET.
O struct TimeSpan faz parte do namespace System. Ele realiza a representação de um intervalo de tempo, podendo ser positivo ou negativo (quando comparado entre menor e maior). O intervalo de tempo pode ser medido em Anos, Meses, Dias, Horas, Minutos, Segundos.
Observação: Deve-se utilizar o TimeSpan, quando sua intenção de negócio é realizar diferenças de horas entre pontos, caso a intenção seja transparecer a diferença entre duas datas, prefira a utilização do DateTime.
Observação: É recomendado que efetuem o download do código fonte para ter em mãos toda a solução realizada, o que facilitará o seu estudo.
Internamente ele apresenta tempo em milissegundos e seus métodos tornam esse tempo mais especifico e fácil para apresentação.
Instanciar o TimeSpan
O construtor do struct possui cinco sobrecargas, abaixo estão todas as possiblidades.
Listagem 1: Construtores do TimeSpan
TimeSpan tsInstance = new TimeSpan();
//Ticks == Cem Nanosegundos;
TimeSpan tsInstance1 = new TimeSpan(1);
TimeSpan tsInstance2 = new TimeSpan(7, 36, 10);
//dd-HH:mm:ss
TimeSpan tsInstance3 = new TimeSpan(8, 2, 50, 10);
//dd-HH:mm:ss.mmm (Milissegundos)
TimeSpan tsInstance4 = new TimeSpan(4, 7, 36, 10, 100);
Com as instâncias criadas, agora é a hora de utilizar as propriedades do struct. Todas as propriedades são apenas do tipo Get, portanto servirão apenas para apresentação da quantidade de tempo realizado. Para incrementar tempo é necessário utilizar o operador correto.
Listagem 2: Propriedades do struct TimeSpan
public static void ShowProprerties(TimeSpan timeZoneBR, TimeSpan timeZoneUS)
TimeSpan intervalo = timeZoneBR - timeZoneUS;
Console.WriteLine("Dias: " + intervalo.Days);
Console.WriteLine("Horas: " + intervalo.Hours);
Console.WriteLine("Minutos: " + intervalo.Minutes);
Console.WriteLine("Segundos: " + intervalo.Seconds);
Console.WriteLine("Milissegundos: " + intervalo.Milliseconds);
Console.WriteLine("Ticks: " + intervalo.Ticks);
Console.WriteLine("Total de Dias: " + intervalo.TotalDays);
Console.WriteLine("Total de Horas: " + intervalo.TotalHours);
Console.WriteLine("Total de Minutos: " + intervalo.TotalMinutes);
Console.WriteLine("Total de Segundos: " + intervalo.TotalSeconds);
Console.WriteLine("Total de Milissegundos: " + intervalo.TotalMilliseconds);
Listagem 3: Visualizando todas as propriedades
ShowProprerties(tsInstance3, tsInstance4);
Figura 1: Retorno das propriedades
Note que cada propriedade ajudará na apresentação de informações ou qualquer outra regra de negócio aplicada.
Os métodos do struct são os responsáveis por modificar as definições de tempo, conforme sua necessidade.
Então para realizar cálculos, diferenças, comparações, somas, cast, utilizaremos os métodos.
O método Add recebe outro struct TimeSpan e incrementa com os valores passados. No caso abaixo, adiciona uma hora.
Listagem 4: Método add
Console.WriteLine("Hora Atual  : " + timeZone.Hours);
var tsOneHour = new TimeSpan(1, 0, 0);
timeZone = timeZone.Add(tsOneHour);
Console.WriteLine("Hora após Add : " + timeZone.Hours);
Figura 2: Retorno do método Add
O Compare é um método estático e acessado diretamente pelo struct, ele realiza a comparação de dois intervalos. Ele retorna um inteiro na comparação, caso retorne 1, significa que o primeiro struct é maior que o segundo, caso retorne -1, significa que o segundo struct é maior e caso retorne 0, ambos são iguais.
Listagem 5: Método Compare
int compareTime = TimeSpan.Compare(timeZone, tsOneHour);
if (compareTime == 0) Console.WriteLine("Tempos Iguais.");
if (compareTime == 1) Console.WriteLine("Primeiro Tempo é maior.");
if (compareTime == 2) Console.WriteLine("Segundo Tempo é maior.");
Figura 3: Retorno do método Compare
O parse, como em grande parte das classes de tipo, efetua o 'cast' de um tipo de dado para outro. No caso do TimeSpan não é diferente, entretanto ele apenas recebe o tipo String. O mais legal é que você passa um valor como 8:20:59.999 e ele transforma tudo em um TimeSpan perfeitamente configurado.
Listagem 6: Método Parse
var parse = TimeSpan.Parse("23:59:59.999");
Console.WriteLine("O Parse Tranformou de String (23:59:59.999) para TimeSpan Ficando {0}:{1}:{2}.{3}", parse.Hours, parse.Minutes, parse.Seconds, parse.Milliseconds);
Figura 4: Resultado do Parse
A quantidade de métodos desse struct é um pouco extensa, portanto fica inviável descrever todas. Alguns exemplos foram passados para exemplificar e facilitar o entendimento.
Temos o cenário de empresa onde o empregado que chegou atrasado e deve cumprir a compensação de horas no mesmo dia ou pelo menos no próximo dia. Enquanto isso ele estará devendo horas para a empresa.
Supondo que o mesmo trabalhe oito horas por dia e entre no trabalho sempre às 8:30 e saía às 17:30.
Seguindo nosso caso, codifiquemos.
Primeiro as variáveis com o valor do horário comercial da empresa.
Listagem 7: Horário Comercial
static TimeSpan InicioExpediente = new TimeSpan(8, 30, 0);
static TimeSpan FinalExpediente = new TimeSpan(17, 30, 0);
static TimeSpan CompensarTempo = new TimeSpan();
Para informar o tempo de atraso que o funcionário teve no dia, precisamos primeiro verificar se realmente ele passou do horário de entrada e depois efetuar a subtração da hora de entrada do funcionário com o horário de entrada estabelecido pela empresa.
Listagem 8: Informar atraso
string horaDigitada = Console.ReadLine();
var HoraEntrada = TimeSpan.Parse(horaDigitada);
if (InicioExpediente.CompareTo(HoraEntrada) == -1)
CompensarTempo = HoraEntrada.Subtract(InicioExpediente);
Console.WriteLine("O Func. deverá compensar : {0}:{1}",
CompensarTempo.Hours.ToString().PadLeft(2, '0'),
CompensarTempo.Minutes.ToString().PadLeft(2, '0'));
Para informar o tempo a ser debitado, primeiro devemos verificar se o mesmo ainda deve alguma coisa, para que o débito não seja feito em zero.
Listagem 9: Informar o débito
if (CompensarTempo.Equals(TimeSpan.Zero))
Console.WriteLine("O Func. já compensou todo o seu débito.");
Após digitado o tempo de compensação, devemos abater do total o valor, caso o usuário passe para credor, o sistema irá informar uma mensagem. Caso o mesmo ainda esteja em débito aberto, o sistema irá informar o saldo resultante.
Listagem 10: Informar o débito
string tempoDebitado = Console.ReadLine();
var TempoCompensado = TimeSpan.Parse(tempoDebitado);
CompensarTempo = CompensarTempo.Subtract(TempoCompensado);
if (CompensarTempo.TotalSeconds < 0)
CompensarTempo = TimeSpan.Zero;
Console.WriteLine("O Func. Compensou todo o seu débito e agora possuí horas em aberto no total de : {0}:{1}", CompensarTempo.Hours, CompensarTempo.Minutes);
Console.WriteLine("O Func. precisa compensar: {0}:{1}", CompensarTempo.Hours, CompensarTempo.Minutes);
O struct TimeSpan é uma excelente ferramenta, perfeita para esses e outros casos. Lembre-se que, quando houver a necessidade de trabalhar juntamente com datas, prefira a classe DateTime, por ser mais robusta e pronta para isso.