Como converter e formatar a exibição de horas decimais com SQL Server - parte 1

Esta publicação demonstra como converter números decimais usados para armazenar duração de tempo para a representação no formato de horas e minutos usando as funções do SQL Server 2008.

O objetivo é permitir representar números armazenados no formato decimal no banco de dados para facilitar o cálculo usando-se o formato padrão para horas e minutos, HH:MM, assim, por exemplo, 1,5 que refere-se à duração de uma hora e meia poderá ser representado como 01:30.

Como a proposta deste blog é manter as coisas simples e principalmente, atender a um público que está iniciando na programação, não serão considerados nos cálculos a duração em segundos e centésimos para que os cálculos fiquem simples. A versão mínima do SQL Server para poder executar este exemplo é a 2008 R2 sendo que é possível usar a sua versão gratuita (SQL EXPRESS EDITION).

Nesta primeira parte serão demonstrados os passos necessários para realizar as conversões de base numérica. Na segunda, será dado o exemplo de uma função definida pelo usuário (UDF) no banco SQL Server para ser usada com as consultas.

Os códigos que estão demonstrados funcionam e foram testados apenas para o banco de dados SQL Server. Cada gerenciador de banco de dados possui uma maneira diferente para tratamento de armazenamento em variáveis e criação de funções do usuário.

Uma questão de base

É muito comum nas tarefas dos programadores ter de fazer cálculos com horas em algum momento. Pode ser para cálculo de valores em moeda baseado na quantidade do tempo trabalhado ou estimativas de custos baseados em horas, não importa. O que todos os cálculos envolvendo tempo corrido terão em comum é o fato de que as horas precisarão ser convertidas da base sexagimal para a decimal para que os cálculos sejam feitos.

É mais comum que todas as horas sejam representadas na base sexagimal. Os múltiplos e submúltiplos são obtidos multiplicando ou dividindo por sessenta. Assim, uma hora é igual a sessenta minutos e cada minuto corresponde à sessenta segundos. Se é necessário calcular-se o número total de minutos de uma hora, basta multiplicar o número por sessenta.

Porém para os cálculos de base financeira não é possível usar números com base sessenta diretamente. Se for necessário calcular o valor final de um serviço que durou, por exemplo, 01h30m, este número precisa ser convertido para a base decimal obtendo-se o valor 1,5 que pode então ser multiplicado pelo valor unitário.

Conversão de base sexagimal para base decimal

Esta conversão consiste em transformar o tempo representado no formato tradicional HH:MM para um número decimal para que possa ser armazenado e se façam cálculos.

Tomando o exemplo de 01:30 de duração deve-se armazenar cada parte do tempo em uma variável inteira em um primeiro passo, assim teremos uma variável inteira para hora e outra para os minutos, considerando o uso da linguagem SQL:

 declare @horas as decimal(6, 2) = 1;
 declare @minutos as decimal(6, 2) = 30;
Atenção
Um ponto importante que deve ser observado se ao desenvolver o exemplo se estiver usando o SQL Server é que as variáveis precisam ser declaradas do tipo DECIMAL com pelo menos duas casas após o ponto. O motivo disto é que se não for feito desta forma, a conversão não será feita corretamente.

Para se ter o número completo na base decimal deve se dividir os minutos por sessenta (60) e somar o valor encontrado com as horas, assim, obtendo-se a duração final em base decimal. Novamente, se for fazer este cálculo com a linguagem SQL teremos este código:

 declare @minutos_sexagimais as decimal(6,2) = @minutos / 60;
 declare @tempo as decimal(6,2) = @horas + @minutos_sexagimais;

Conversão de base decimal para base sexagimal

Esta tarefa consiste em obter o valor que está armazenado em base decimal e poder converter para a sua representação no formato sexagimal (HH:MM). Para fazer isto é necessário que alguns passos sejam seguidos, o primeiro é armazenar apenas o valor correspondente às horas Isto é feito lendo o valor do tempo e atribuindo para uma variável do tipo inteiro. O resultado é que a parte decimal será desprezada:

declare @h as int = 1.50;

O segundo passo é obter os minutos convertidos para a base sexagimal. Isto envolve dois passos:

  1. Multiplicar o valor total do tempo por sessenta para se obter o valor total em minutos.
  2. Armazenar em uma variável do tipo inteiro o resto da divisão do valor do tempo em minutos por sessenta usando o operador de resto de divisão (módulo)

O exemplo abaixo demonstra como isto pode ser feito.

declare @minutos as int = 1.50 * 60 % 60; -- resultado: 30

O operador de módulo no SQL Server é o sinal de percentagem "%" seguido do divisor.

Com os passos expostos até aqui já é possível considerar como fazer para se obter os valores. Falta agora fazer as formatações corretas e tornar tudo isto utilizável facilmente através da definição de uma UDF. Isto será tratado no próximo post. Até lá!