Versões comparadas
Chave
- Esta linha foi adicionada.
- Esta linha foi removida.
- A formatação mudou.
Introdução
Trabalhar com data e hora em sistemas modernos requer entender completamente o uso de fuso horários. Uma aplicação web ou mobile é composta, em sua maioria das vezes, de banco de dados, servidor e cliente (navegador web ou aplicativo). É necessário entender bem que o fuso de cada uma dessas camadas pode ter especificações diferentes que podem gerar confusões ao implementar seu sistema.
Banco de dados
A maioria dos bancos de dados fornecem alguns tipos de dados para armazenamento de data (tipo DATE), data e hora (tipo DATETIME) ou apenas hora (tipo TIME). Tais tipos podem considerar as informações de fuso ou não. A grande confusão ocorre quando tais tipos não levam em consideração o fuso, o que acabam ficando dependente de uma configuração correta do servidor e cliente para que não haja diferença de horários. Falaremos disso mais na frente.
Os tipos mais comuns são:
- DATE: armazena apenas a data sem informações do fuso. Contém apenas uma data civil, sem qualquer consideração de fuso horário. Por exemplo, data de nascimento, ou a data de vencimento de uma conta, ou um prazo legal, é DATE;
- DATETIME: armazena data e hora sem informações de fuso. Contém data e hora civis, novamente sem considerar o fuso horário. Se por exemplo o prazo de pagamento é "dia tal até 13:00", é responsabilidade do pagador saber se estamos no horário de verão ou não, qual o fuso horário do local em que ele se encontra, etc.
- TIME: armazena apenas hora sem informações de fuso. É o mesmo que os campos acima, porém não específica a data;
- TIMESTAMP: armazena informações de data e hora levando em consideração o fuso horário. É um número que determina um momento específico. Tipicamente é expresso como o "número de segundos desde 1/1/1970 00:00 em Londres", mas poderia ser qualquer outra base. A ideia do timestamp é que ele vale no mundo todo, ou seja, ele identifica o momento exato em que algo aconteceu. Um acontecimento com timestamp "0" aconteceu em 31/12/1969 às 21:00 no Brasil e 1/1/1970 00:00 em Londres.
O timestamp é útil para registrar log, e para determinar se A aconteceu antes ou depois de B, mesmo que A e B tenham acontecido em lados opostos do planeta. Por outro lado, o timestamp é inadequado para registrar datas e horas "civis" porque a hora e até a data muda conforme o fuso horário em que o timestamp é interpretado.
Nem sempre a melhor opção é óbvia. Por exemplo, registrar a data de nascimento com DATETIME ou TIMESTAMP? De um ponto de vista matemático, o TIMESTAMP seria ideal porque um bebê nasce num momento bem determinado. Por outro lado, a data e hora de nascimento têm efeitos civis - colocar a data de nascimento diferente da Carteira de Identidade pode causar um monte de aborrecimentos - então é melhor usar DATETIME e o local de nascimento, já que o fuso horário é de conhecimento público.
Resumindo, ao usar DATE, DATETIME ou TIME, seu servidor tem que conhecer em qual fuso horário você deseja obter e gravar esses valores, para esses casos, recomendamos que o Banco e o Servidor estejam no mesmo fuso horário.
Servidor
O servidor normalmente tem apenas uma configuração global de fuso horário. Ao gravar ou obter campos do tipo DATE, DATETIME ou TIME, ele vai usar a informação de fuso configurada para suas conversões internas. Ao gravar ou obter campos do tipo TIMESTAMP, ele vai simplesmente respeitar o que está informado no valor, ou seja, as informações do fuso horário do servidor não interferem. O Cronapp usa o JAVA como plataforma base do servidor e o tipo java.util.Date para representação de todos os tipos internos: data, data e hora, hora e timestamp. O uso de um único tipo é um padrão especificado pela Java Persistence Interface (JPA). Para "entender" o que significa cada tipo, o JPA exige anotações acima da declaração do tipo do atributo na classe que representa a tabela do banco. Não vamos entrar em detalhes, viso que é um assunto mais High-Code que fica abstraído para quem usa o Cronapp apenas como Low-Code.
Cliente (Navegador ou Aplicativo)
O fuso horário do aplicativo é o que pode sofrer mais variações. Nos sistemas modernos, na maioria das vezes, os usuários estão ao redor do mundo. Sendo assim, na maioria dos casos, precisamos aceitar entradas e exibições de datas e horas, considerando o fuso horário de quem está digitando ou lendo.
Exemplo: Imagine um sistema de cadastro de eventos. Nesse sistema, usuários do mundo inteiro poderão cadastrar eventos que devem acontecer segundo o contexto de fuso de quem cadastra, porém, para outros usuários ao redor do mundo, tais horários podem ser exibidos com diferenças. Um evento às 10:00 de Londres ocorre às 07:00 do Brasil. Ou um evento 00:00 de Londres do dia 10/11/2019 ocorre às 21:00 do dia 09/11/2019 no Brasil.
Como o Cronapp trata Data e Hora
O Cronapp procurou deixar tudo mais simples para seus usuários, inclusive aqueles que não têm pretensão de que seus sistemas funcionem em diferentes fusos horários. Para isso, vale a pena entender bem os recursos e configurações que o Cronapp oferece, para que não haja desperdício de tempo com tentativas, erros ou suporte. Então, vamos as configurações:
Configurando o fuso horário no Cronapp
Através do menu Projeto > Configurações e depois na aba Configurações de Projeto (Figura 1), existem dois campos importantes:
- Converter Fuso Horário do Cliente: marcando essa opção o Cronapp se comportará de forma bem simples. Independente do fuso que o cliente (navegador web ou aplicativo) estiver ele será desconsiderado e será utilizado o fuso informado na opção Fuso Horário.
- Fuso horário: configura o fuso horário do servidor (da aplicação). Os campos DATE, DATETIME e TIME terão o fuso da opção selecionada. O campo TIMESTAMP não é afetado por essa opção (a não ser no formato textual). O valor padrão para esse campo é (GMT00:00) UTC.
Figura 1 - Campos de configuração de fuso horário no Cronapp
Os formatos usados no diagrama de dados
O diagrama de dados oferece os 4 tipos mais comuns de data de bancos de dados:
- Data: criará ou considerará o campo do banco como DATE. O fuso será considerado como informado nas configurações do projeto;
- Data e Hora: criará ou considerará o campo do banco como DATETIME. O fuso será considerado como informado nas configurações do projeto;
- Hora: criará ou considerará o campo do banco como TIME. O fuso será considerado como informado nas configurações do projeto;
- Date e Hora com Fuso: criará ou considerará o campo do banco como TIMESTAMP.
Cliente (Editor HTML)
Cada campo que é capaz de exibir ou editar uma data, data e hora ou hora possui alguns tipos a serem considerados. Eles terão comportamentos diferentes a depender da configuração feita nas configurações do projeto (mostrado na Figura 1). Vários campos podem receber datas. Exemplos:
- Entradas: entrada de texto, listas etc. Para esses casos, usam-se as propriedades Tipo e Máscara do componente (Figura 2.1);
Figura 2.1 - Campos Tipo e Máscara nas propriedades de uma entrada de texto
- Qualquer texto da Tela: grade, títulos etc. Para esses casos usa-se o "..." ao lado da propriedade (Figura 2.2);
Figura 2.2 - Abrir janela de conteúdo do componente texto
- Qualquer propriedade Textual de qualquer componente: rótulos, conteúdos etc. Para esses casos, o ícone para editar expressão (Figura 2.3) que aparece ao passar o mouse sobre a propriedade é usado para abrir a mesma janela da Figura 2.2.
Figura 2.3 - Editar expressão do conteúdo do componente texto
A exibição desses campos será influenciada pelo Tipo e pela Máscara que serão escolhidas. As opções para o Tipo podem ter os seguintes valores para uma data, data e hora ou hora:
- Data (Date): exibe a data desconsiderando a hora, mesmo que no diagrama tenha sido usado algum tipo que considere a hora. Se o tipo no diagrama tiver hora, ela será armazenada como 00:00:00. Se a opção Converter Fuso Horário do Cliente estiver marcada, esse campo irá exibir o fuso da opção, caso contrário usará o fuso do navegador web ou aplicativo;
- Data e Hora (Date and Time): exibe a data e hora. Se a opção Converter Fuso Horário do Cliente estiver marcada, esse campo irá exibir o fuso da opção, caso contrário usará o fuso do navegador web ou aplicativo;
- Data e Hora Locais (Date and Time Local): exibe a data e hora. Será exibido no fuso local do navegador/aplicativo;
- Hora (Time): exibe apenas a hora. Se o tipo no diagrama tiver data, ela será armazenada como 01/01/1970;
- Hora Local (Time Local): exibe apenas a hora. Se o tipo no diagrama tiver data, ela será armazenada como 01/01/1970. Será exibido no fuso local do navegador/aplicativo;
- Mês (Month): exibe apenas o mês da data (Janeiro, Fevereiro etc). Ao entrar uma nova data, usará dia, ano e hora atuais;
- Semana (Week): exibe apenas o dia da semana da data (Segunda-Feira, Terça-Feira etc). Ao entrar uma nova data, usará mês, ano e hora atuais.
Exemplo: Um campo com a data 22/11/2000 10:00:00 UTC (00:00). Se estivermos com a opção Converter Fuso Horário do Cliente e o fuso escolhido tiver sido UTC (00:00) e o fuso do cliente seja America/Sao_Paulo (-03:00), teremos os valores para os diferentes tipos:
- Date: 22/11/2000;
- Date and Time 22/11/2000 10:00:00;
- Date and Time Local: 22/11/2000 07:00:00;
- Time: 10:00:00;
- Time Local: 07:00:00. Será exibido no fuso local do navegador/aplicativo;
- Month: Novembro;
- Week: Quarta-Feira;
A máscara irá determinar o padrão da janela de escolha rápida de datas, horas, meses, semanas, dias etc. Exemplos:
- DD/MM/YYYY: sobe um seletor apenas de data;
- MM: sobe um seletor de mês em texto e exibe o mês em número (Figura 3.1);
- MMMM, MMM: sobe um seletor de mês em texto e exibe o mês também em texto;
- DD/MM/YYYY HH:mm:ss: sobe um seletor com data e hora;
- DD/MM/YYYY HH:mm:ss A: sobe um seletor com data e hora com seleção e AM e PM;
- HH:mm:ss: sobe um seletor com hora, minuto e segundo;
- HH:mm: sobe um seletor com hora e minuto (Figura 3.2);
- dddd: sobe um seletor de data, mas exibe apenas o nome da semana no campo.
Para entender mais sobre máscaras no cliente, leia o documento Formatação de máscaras para campos de texto.
Nessa página
Índice | ||||
---|---|---|---|---|
|
Figura 3.1 - Utilizando a máscara MM e o seu comportamento no browser
Figura 3.2 - Utilizando a máscara HH:mm e o seu comportamento no browser
Bloco de Programação
O bloco de programação fornece algumas funções para tratamento de datas. Algumas das mais importantes são:
Camada Servidor:
- Obter valor do campo: obtém o valor de qualquer campo da tela cliente no servidor. Todos os campos data e hora trafegam entre o cliente e servidor no formato ISO 8601 que inclui todas as informações de data, hora com minutos, segundos, milissegundos e fuso. Ao trafegar do cliente para o servidor, ele leva as devidas conversões de fuso;
- Obter campo (Banco de Dados): essa função obtém o campo do banco de dados que sempre estará no fuso especificado para a aplicação;
- Exibir Notificação: essa função bem comum merece uma observação importante, ao exibir uma data. Caso você não formate a data, ela será exibida no fuso horário do cliente;
- Imprimir: essa função bem comum merece uma observação importante, ao imprimir uma data. Caso você não formate a data, ela será exibida no formato ISO 8601 no fuso horário do servidor;
- Converter Texto para Data: essa função converterá um texto (representação textual de uma data) para um objeto data. Caso uma máscara seja informada, ela a usará para tentar fazer a conversão, caso contrário, algumas máscaras predefinidas serão usadas - levando em consideração o idioma do cliente. Caso o formato textual não considere o fuso na sua escrita (ex: 12/03/1910), o fuso padrão do servidor será usado. Caso o fuso tenha sido especificado (ex: 2019-09-22T02:30Z), ele será usado;
- Converter Texto para Data com Fuso Horário: tem o mesmo comportamento da função acima, porém, quando o fuso não está discriminado, ele usa o especificado pelo parâmetro de fuso da função;
- Formatar Data: formata uma data para um formato textual. Caso a máscara seja informada, ele a usará (Figura 4), caso contrário, usará o padrão de máscara do idioma escolhido pelo cliente. Ao formatar para um texto, o Cronapp irá usar o fuso especificado para a aplicação;
- Formatar Data com Fuso Horário: tem o mesmo comportamento da função acima, porém o fuso pode ser especificado através do parâmetro da função.
Figura 4 - Utilizando máscara no bloco e exibindo no componente
Observações:
- Caso um Objeto Data seja enviado para qualquer função que espere um texto, ele será representado pelo formado ISO 8601 no fuso horário especificado para a aplicação. Ex: JSON enviado para um serviço REST;
- Tenham atenção ao visualizar o formato ISO 8601 das datas. Datas com textos diferentes podem representar o mesmo valor, pois o fuso pode estar escrito de forma diferente: Ex: 2019-09-22T00:00:00Z é igual a 2019-09-21T09:00:00-03:00;
- A especificação de máscaras no servidor é diferente do cliente. Seguem alguns exemplos de máscaras no servidor:
dd-MM-yy | 31-01-12 |
dd-MM-yyyy | 31-01-2012 |
MM-dd-yyyy | 01-31-2012 |
yyyy-MM-dd | 2012-01-31 |
yyyy-MM-dd HH:mm:ss | 2012-01-31 23:59:59 |
yyyy-MM-dd HH:mm:ss.SSS | 2012-01-31 23:59:59.999 |
yyyy-MM-dd HH:mm:ss.SSSZ | 2012-01-31 23:59:59.999+0100 |
EEEEE MMMMM yyyy HH:mm:ss.SSSZ | Saturday November 2012 10:45:42.720+0100 |
dd/MM/yyyy | 31/01/2012 |
dd/MM/yyyy HH:mm:ss | 31/01/2012 23:59:59 |
Para o cliente, leia o documento Formatação de máscaras para campos de texto.