Trabalhando com datas, armazenamento e manipulação.
Antes de qualquer coisa, gostaria de explicar o que é Unix Timestamp:
É uma data em segundo de 32 bits que tem o limite mínimo(valor 0) em January 1 1970 00:00:00 GMT, que é a data marco unix(UNIX EPOCH) até
Tue, 19 Jan 2038 03:14:07 GMT. Para saber a Unix Timestamp de uma data é só contar quantos segundos se passou da data 0 até a data desejada.
Exemplos:
No meu servidor, porque estamos falando de uma data GMT, e meu fuso-horário é o de Brasília, a data UNIX EPOCH padrão será
1969-12-31 21:00:00, três horas a menos do que o GMT
04/02/2002 --> 1012788000
08/05/2003 --> 1052362800
25/10/2004 --> 1098669600
Voltemos ao assunto:
Ao pesquisar mais a fundo esses sistemas que a galera estava(e está) desenvolvendo, percebi que o bonitão socava um INT no campo de data. No primeiro momento isso parece meio estranho, mas se você for pensar melhor:
* O valor do inteiro, era um UNIX TIMESTAMP;
* Inteiros são mais rápidos de se retornar ou pesquisar do que um campo DATE/TIME TIMESTAMP, não vou discutir isso, beleza, isso é lógico;
* Notou que o Unix Timestamp é justamente valor do argumento que as funções de formatação de datas do PHP precisa?;
* Para saber a distancia entre uma data e outra você é só fazer DATA_A - DATA_B, e você tem a distância (em segundos, lembrando que um minuto tem 60 segundos, uma hora 360 segundo e assim vai ... deu pra sacar!?)
* Para campatibilidade entre bancos, isso é ótimo, executamos o select cruzão, e depois fazemos as transformações no script PHP;
* Entre outras vantagens... você vai descrobir uma a cada dia.
Guardando as datas nesse formato, teremos um script mais rápido (notaremos isso quando trabalharmos com grandes volumes de dados), e deixaremos o script mais simples(vejo isso como vantagem, tem gente que não, hehehe).
Mas nem tudo é maravilha, quando precisarmos fazer uma operação mais detalhada, com meses por exemplo, precisaremos fazer um conversão direta no sql.
Por exemplo:
Todas as datas do mês de abril:
Para bancos como o mysql isso não tem muito problema:
*lembrando que o CAMPO_DATA está em unix timestamp
SELECT * FROM TABELA WHERE FROM_UNIXTIME( CAMPO_DATA ,'%m') = 4
Com mysql temos funções que convertem para unix timestamp, mas no MS SQL Server como fica?
SELECT * FROM TABELA WHERE CONVERT(INT,MONTH( DATEADD(second, CAMPO_DATA ,'1969-12-31 22:00:00'))) = 4
Vamos mais devagar com essa aqui:
Passo 1: DATEADD(second, CAMPO_DATA ,'1969-12-31 22:00:00')
Porque eu usei 22:00:00 horas em vez de 21:00:00!? Porque se não daria uma hora de diferença, só fiz uma correção, pronto está implementado o FROM_UNIXTIME do MSSQL
Passo 2: MONTH( DATEADD(second, CAMPO_DATA ,'1969-12-31 22:00:00'))
Depois eu peguei o mês da data, beleza?
Passo 3: CONVERT(INT,MONTH( DATEADD(second, CAMPO_DATA ,'1969-12-31 22:00:00')))
Transformei o valor em inteiro.
Ou seja, quando temos esse tipo de situação, existirá uma solução para cada banco, o que não é o fim do mundo.
É uma data em segundo de 32 bits que tem o limite mínimo(valor 0) em January 1 1970 00:00:00 GMT, que é a data marco unix(UNIX EPOCH) até
Tue, 19 Jan 2038 03:14:07 GMT. Para saber a Unix Timestamp de uma data é só contar quantos segundos se passou da data 0 até a data desejada.
Exemplos:
No meu servidor, porque estamos falando de uma data GMT, e meu fuso-horário é o de Brasília, a data UNIX EPOCH padrão será
1969-12-31 21:00:00, três horas a menos do que o GMT
04/02/2002 --> 1012788000
08/05/2003 --> 1052362800
25/10/2004 --> 1098669600
Voltemos ao assunto:
Ao pesquisar mais a fundo esses sistemas que a galera estava(e está) desenvolvendo, percebi que o bonitão socava um INT no campo de data. No primeiro momento isso parece meio estranho, mas se você for pensar melhor:
* O valor do inteiro, era um UNIX TIMESTAMP;
* Inteiros são mais rápidos de se retornar ou pesquisar do que um campo DATE/TIME TIMESTAMP, não vou discutir isso, beleza, isso é lógico;
* Notou que o Unix Timestamp é justamente valor do argumento que as funções de formatação de datas do PHP precisa?;
* Para saber a distancia entre uma data e outra você é só fazer DATA_A - DATA_B, e você tem a distância (em segundos, lembrando que um minuto tem 60 segundos, uma hora 360 segundo e assim vai ... deu pra sacar!?)
* Para campatibilidade entre bancos, isso é ótimo, executamos o select cruzão, e depois fazemos as transformações no script PHP;
* Entre outras vantagens... você vai descrobir uma a cada dia.
Guardando as datas nesse formato, teremos um script mais rápido (notaremos isso quando trabalharmos com grandes volumes de dados), e deixaremos o script mais simples(vejo isso como vantagem, tem gente que não, hehehe).
Mas nem tudo é maravilha, quando precisarmos fazer uma operação mais detalhada, com meses por exemplo, precisaremos fazer um conversão direta no sql.
Por exemplo:
Todas as datas do mês de abril:
Para bancos como o mysql isso não tem muito problema:
*lembrando que o CAMPO_DATA está em unix timestamp
SELECT * FROM TABELA WHERE FROM_UNIXTIME( CAMPO_DATA ,'%m') = 4
Com mysql temos funções que convertem para unix timestamp, mas no MS SQL Server como fica?
SELECT * FROM TABELA WHERE CONVERT(INT,MONTH( DATEADD(second, CAMPO_DATA ,'1969-12-31 22:00:00'))) = 4
Vamos mais devagar com essa aqui:
Passo 1: DATEADD(second, CAMPO_DATA ,'1969-12-31 22:00:00')
Porque eu usei 22:00:00 horas em vez de 21:00:00!? Porque se não daria uma hora de diferença, só fiz uma correção, pronto está implementado o FROM_UNIXTIME do MSSQL
Passo 2: MONTH( DATEADD(second, CAMPO_DATA ,'1969-12-31 22:00:00'))
Depois eu peguei o mês da data, beleza?
Passo 3: CONVERT(INT,MONTH( DATEADD(second, CAMPO_DATA ,'1969-12-31 22:00:00')))
Transformei o valor em inteiro.
Ou seja, quando temos esse tipo de situação, existirá uma solução para cada banco, o que não é o fim do mundo.
Bom artigo.
20/11/2008 4:25am
(~16 anos atrás)
Não sei se vc. percebeu mas com a sua dica, vc. abre o alerta para o problema que os sistemas onde o banco de dados foram construidos usando DATE/TIME terão em 2038, é um problema muito parecido com o tão EX-TEMIDO BUG DO MILÊNIO. Os programadores que leram esse artigo alertem para esse fato, se mês passado vc. modelou um banco de dados para uma grande empresa onde o volume de dados já é absurdamente grande, e o sistema já foi modificado por inumeros programadores, às vésperas de 2038, será um "corre corre" para reconfigurar os BDs e as Bilhares de Linhas de Códigos....
Sem Desesperos pessoal ainda temos 30 anos, mas por mim começo apartir de hj, a usar INT nos meus BD.
[]s e Parabéns mais uma vez pelo ótimo artigo.
Sem Desesperos pessoal ainda temos 30 anos, mas por mim começo apartir de hj, a usar INT nos meus BD.
[]s e Parabéns mais uma vez pelo ótimo artigo.
19/06/2006 4:39pm
(~18 anos atrás)
eu tava com um problema na hora de gerar relatorios!
muito util mesmo!!
usando a função strtotime consigo converter um data no formato ingles para segundo do TimeStamp.!
Muito bom mesmo.
Thiago
muito util mesmo!!
usando a função strtotime consigo converter um data no formato ingles para segundo do TimeStamp.!
Muito bom mesmo.
Thiago
27/03/2006 7:59am
(~19 anos atrás)
Flávio, valeu pela ajuda. eu estava precisando exatamente disso... deu uma ajuda e tanto...
flw!
flw!
18/11/2005 2:49pm
(~19 anos atrás)
Por exemplo pra uma tabela com noticias, onde vc tem muito select em cima desse campo da data, ou por periodo "(campo >= x and campo <= x)", ou principalmente utilizando num order by.
Ao criar um índice pra este campo, vc vai ter uma entrada pra cada registro no arquivo de indice, tornando lenta a inserção,exclusão e atualização de registros, quando esta tabela atingir um certo numero de registro, e se tratando de mysql, esse certo numero é baixo comparado ao outros banco de dados, até pq o mysql é um bando de dados, pq pra vc ter um banco consistente vc tem muito trabalho na sua aplicação.
Enfim neste exemplo de noticia a melhor saída seria um campo de data(date) e outro de hora, criando o inidice no campo de data.
Realmente trabalhando com mysql em pequenos projetos, utilizar a data em um campo int ou bigint é muito fácil. Mas para projetos que exijam uma maior segurança nos dados utilize um postgres, que é um banco de verdade e open source a altura dos comerciais, e utilizem para datas o date ou timestamp.
Ao criar um índice pra este campo, vc vai ter uma entrada pra cada registro no arquivo de indice, tornando lenta a inserção,exclusão e atualização de registros, quando esta tabela atingir um certo numero de registro, e se tratando de mysql, esse certo numero é baixo comparado ao outros banco de dados, até pq o mysql é um bando de dados, pq pra vc ter um banco consistente vc tem muito trabalho na sua aplicação.
Enfim neste exemplo de noticia a melhor saída seria um campo de data(date) e outro de hora, criando o inidice no campo de data.
Realmente trabalhando com mysql em pequenos projetos, utilizar a data em um campo int ou bigint é muito fácil. Mas para projetos que exijam uma maior segurança nos dados utilize um postgres, que é um banco de verdade e open source a altura dos comerciais, e utilizem para datas o date ou timestamp.
14/07/2005 4:29pm
(~19 anos atrás)
Colocando a data no formato para insercao no banco interbase/firebird/mysql:
Resolvido:
Com ajuda dos amigos:
Primeiro eu pego a data do form chamo a funcao converteData que transformará para data do banco interbase assim como: 2004-Nov-28
agora quando o usario entra com a data no form 28/11/2004 a funcao transforma na data para o banco interbase ou firebird e mysql, armazenando realmente a data digitada no form 28/11/2004.
antes ele invertia na hora de inserir no banco ficando 11/28/2004 só que nem chegava de armazenar dava um erro.
sigua os passos abaixo:
<?
$thisDATANASCIMENTO = converteData($thisDATANASCIMENTO);
function converteData($data){
if ($data == "")
return "";
if (substr($data,3,2) == "01"){
$mes = "Jan";
};
if (substr($data,3,2) == "02"){
$mes = "Feb";
};
if (substr($data,3,2) == "03"){
$mes = "Mar";
};
if (substr($data,3,2) == "04"){
$mes = "Apr";
};
if (substr($data,3,2) == "05"){
$mes = "May";
};
if (substr($data,3,2) == "06"){
$mes = "Jun";
};
if (substr($data,3,2) == "07"){
$mes = "Jul";
};
if (substr($data,3,2) == "08"){
$mes = "Aug";
};
if (substr($data,3,2) == "09"){
$mes = "Sep";
};
if (substr($data,3,2) == "10"){
$mes = "Oct";
};
if (substr($data,3,2) == "11"){
$mes = "Nov";
};
if (substr($data,3,2) == "12"){
$mes = "Dec";
};
$diavenc = substr($data,0,2);
$mesvenc = $mes;
$anovenc = substr($data,6,4);
$dataConvertida = $anovenc."-".$mesvenc."-".$diavenc;
return $dataConvertida;
}
?>
Resolvido:
Com ajuda dos amigos:
Primeiro eu pego a data do form chamo a funcao converteData que transformará para data do banco interbase assim como: 2004-Nov-28
agora quando o usario entra com a data no form 28/11/2004 a funcao transforma na data para o banco interbase ou firebird e mysql, armazenando realmente a data digitada no form 28/11/2004.
antes ele invertia na hora de inserir no banco ficando 11/28/2004 só que nem chegava de armazenar dava um erro.
sigua os passos abaixo:
<?
$thisDATANASCIMENTO = converteData($thisDATANASCIMENTO);
function converteData($data){
if ($data == "")
return "";
if (substr($data,3,2) == "01"){
$mes = "Jan";
};
if (substr($data,3,2) == "02"){
$mes = "Feb";
};
if (substr($data,3,2) == "03"){
$mes = "Mar";
};
if (substr($data,3,2) == "04"){
$mes = "Apr";
};
if (substr($data,3,2) == "05"){
$mes = "May";
};
if (substr($data,3,2) == "06"){
$mes = "Jun";
};
if (substr($data,3,2) == "07"){
$mes = "Jul";
};
if (substr($data,3,2) == "08"){
$mes = "Aug";
};
if (substr($data,3,2) == "09"){
$mes = "Sep";
};
if (substr($data,3,2) == "10"){
$mes = "Oct";
};
if (substr($data,3,2) == "11"){
$mes = "Nov";
};
if (substr($data,3,2) == "12"){
$mes = "Dec";
};
$diavenc = substr($data,0,2);
$mesvenc = $mes;
$anovenc = substr($data,6,4);
$dataConvertida = $anovenc."-".$mesvenc."-".$diavenc;
return $dataConvertida;
}
?>
07/12/2004 9:00am
(~20 anos atrás)
Tenho um sério problema.
Existe no php alguma função que converta do formato unix para o formato de data normal?
E gostaria de saber se também tem como separar, após a conversão, o dia, o mês, o ano, a hora etc.
Grato,
Mailson (mailson@gmail.com)
Existe no php alguma função que converta do formato unix para o formato de data normal?
E gostaria de saber se também tem como separar, após a conversão, o dia, o mês, o ano, a hora etc.
Grato,
Mailson (mailson@gmail.com)
19/11/2004 4:28pm
(~20 anos atrás)
Comentei isso pq tenho certa experiência em desenvolvimento OO e também de desenvolvimento de SGDB (meu tcc foi fazer um SGDB)
trabalho em uma instituição financeira com oracle e mysql, existem tableas com 20 milhoes de registros no oracle e uma mega velocidade. Trabalhei tb em uma empresa de radares de transito... imagina qtos carros passam por dia em um radar e depois pense em um ano, e eh registrado data e hora de qdo eles passam eh muita coisa mas enfim
bom mas tirar as coisas do banco em OO está certo... pq OO existe para você reusar as coisas, e de certa forma ter independencia.
se você faz algumas coisas no banco e amanha muda a camada de persistencia para XML... e ae como fica?
se vc muda o banco as funcoes mudam e ae? vai mudar o seu código tb? ou entao mudar todas as sua selects?
tá certo que devemos ver a perfomance das coisas, mas hj em um mundo onde existem coisas novas a todo dia devemos tb prever mudanças
nao critico o modo de gravar em int, vai da sua experiencia, facilidade com o uso e capacidade de adapta-lo a outras situacoes
eu até ja usei esse método, mas todo o meu trabalho era feito em classes que aceitavam timestamp como parametro, e constantes que definiam meu formatos, mesmo q muda a camada de persistencia ou mude o pais eh mudar constante e tá feito :-)
trabalho em uma instituição financeira com oracle e mysql, existem tableas com 20 milhoes de registros no oracle e uma mega velocidade. Trabalhei tb em uma empresa de radares de transito... imagina qtos carros passam por dia em um radar e depois pense em um ano, e eh registrado data e hora de qdo eles passam eh muita coisa mas enfim
bom mas tirar as coisas do banco em OO está certo... pq OO existe para você reusar as coisas, e de certa forma ter independencia.
se você faz algumas coisas no banco e amanha muda a camada de persistencia para XML... e ae como fica?
se vc muda o banco as funcoes mudam e ae? vai mudar o seu código tb? ou entao mudar todas as sua selects?
tá certo que devemos ver a perfomance das coisas, mas hj em um mundo onde existem coisas novas a todo dia devemos tb prever mudanças
nao critico o modo de gravar em int, vai da sua experiencia, facilidade com o uso e capacidade de adapta-lo a outras situacoes
eu até ja usei esse método, mas todo o meu trabalho era feito em classes que aceitavam timestamp como parametro, e constantes que definiam meu formatos, mesmo q muda a camada de persistencia ou mude o pais eh mudar constante e tá feito :-)
09/08/2004 11:56am
(~20 anos atrás)
E aí leassis,
Concordo que os SGBD tenham boas funções para trabalhar com datas, eu não estou defedendo o método(trabalhar com int), estou só mostrando que ele existe, que eu uso, e gosto.
Pelo fato de ser deselegante, cara eu já vi cada algorítimo OO, que fala sério, lembrando que eu sempre procuro fazer meus projetos, como máximo possível de OO.
Como você deve saber, o paradigma da programação (seja OO, seja estruturado, seja int, seja date), se aplica a necessidade.
Ao fazer um sistema operacional, você usa C, ao fazer um SGBD, ou um servidor web você usaria C++, mas ficaria mais lento do que o seu concorrente em C(msysql é c, apache é c, php é c), se você quer guardar uma data em banco e retornar ela MAIS RÁPIDO, guarde em int; cara quem é maior? um campo int ou um campo string que ainda por cima tem validação em algoríto pre-definido(como um date ou timestamp)? Isso não se descute. Eu não estou falando de 6000 registros eu estou falando de 4.000.000, que é o caso de uma base de log de transação de um servidor movimentado. Tá etendendo? Número x String?
Se você quer ser elegnte, use padrões e procedimentos de programações profissionais, não sei onde você leu que devemos tirar as operações do banco e colocar nas classes, mas se o banco faz pra você pra que tirar dele?
A minha proposta é: vc tem um log, ou data de insrição no site?
O que você faz no log retorna as datas e coloca-o legível, no máximo faz cruzamento de datas; mas a base é grande; armazene em int e converta na aplicação pq o PHP tem toda uma otimização para trabalhar assim...
O que vc faz em uma data de inscrição? É uma base menor mas pode crescer, mas você só faz verificar a quanto tempo o cara tá inscrito, se não expirou a senha(tipo de 3 em três meses troca-se a senha), cara isso é conta de menos com int, usando date é no mínimo datediff, e olhe lá.
Agora se você vai trabalhar com data de nascimento, data de criaçõa da ponte, beleza trabalhe com o date, pouco dado, pouco processamento, essa foi a linha de raciocínio do artigo.
Mas mesmo assim muito obrigado pelo interesse no artigo, gosto de uma boa discursão, você não está errado, acho você não está invalidando o artigo, só contribuindo para o conhecimento.
Um abraço,
Piraz
Concordo que os SGBD tenham boas funções para trabalhar com datas, eu não estou defedendo o método(trabalhar com int), estou só mostrando que ele existe, que eu uso, e gosto.
Pelo fato de ser deselegante, cara eu já vi cada algorítimo OO, que fala sério, lembrando que eu sempre procuro fazer meus projetos, como máximo possível de OO.
Como você deve saber, o paradigma da programação (seja OO, seja estruturado, seja int, seja date), se aplica a necessidade.
Ao fazer um sistema operacional, você usa C, ao fazer um SGBD, ou um servidor web você usaria C++, mas ficaria mais lento do que o seu concorrente em C(msysql é c, apache é c, php é c), se você quer guardar uma data em banco e retornar ela MAIS RÁPIDO, guarde em int; cara quem é maior? um campo int ou um campo string que ainda por cima tem validação em algoríto pre-definido(como um date ou timestamp)? Isso não se descute. Eu não estou falando de 6000 registros eu estou falando de 4.000.000, que é o caso de uma base de log de transação de um servidor movimentado. Tá etendendo? Número x String?
Se você quer ser elegnte, use padrões e procedimentos de programações profissionais, não sei onde você leu que devemos tirar as operações do banco e colocar nas classes, mas se o banco faz pra você pra que tirar dele?
A minha proposta é: vc tem um log, ou data de insrição no site?
O que você faz no log retorna as datas e coloca-o legível, no máximo faz cruzamento de datas; mas a base é grande; armazene em int e converta na aplicação pq o PHP tem toda uma otimização para trabalhar assim...
O que vc faz em uma data de inscrição? É uma base menor mas pode crescer, mas você só faz verificar a quanto tempo o cara tá inscrito, se não expirou a senha(tipo de 3 em três meses troca-se a senha), cara isso é conta de menos com int, usando date é no mínimo datediff, e olhe lá.
Agora se você vai trabalhar com data de nascimento, data de criaçõa da ponte, beleza trabalhe com o date, pouco dado, pouco processamento, essa foi a linha de raciocínio do artigo.
Mas mesmo assim muito obrigado pelo interesse no artigo, gosto de uma boa discursão, você não está errado, acho você não está invalidando o artigo, só contribuindo para o conhecimento.
Um abraço,
Piraz
09/08/2004 9:21am
(~20 anos atrás)
Eu tenho minhas duvidas se se int eh mais rapido que date mas enfim
gravar data em int no banco nao parece ser muito elegante...
os SGDB oferecem boas funcoes para se trabalhar com datas eh soh usar
em OO devemos tirar algumas operacoes do banco e fazer nas nossas classes de negócio o ideal seria fazer uma classe para tratamentos de datas, com uma constante no padrão da data do pais e outra constante com o formato do banco... acho q mata todos os problemas
gravar data em int no banco nao parece ser muito elegante...
os SGDB oferecem boas funcoes para se trabalhar com datas eh soh usar
em OO devemos tirar algumas operacoes do banco e fazer nas nossas classes de negócio o ideal seria fazer uma classe para tratamentos de datas, com uma constante no padrão da data do pais e outra constante com o formato do banco... acho q mata todos os problemas
08/08/2004 8:58pm
(~20 anos atrás)