Descrobrir formato da data

25 respostas
eberson_oliveira

Bom dia a todos,

Queria fazer um método que permitisse incrementar dias ou meses ou anos em uma data. Para isso usei a seguinte estrutura:

GregorianCalendar gc = new GregorianCalendar( Integer.parseInt( sdate.substring( 6, sdate.length() ).trim().replace( ' ', '0' ), Integer.parseInt( sdate.substring( 3, 5 ).trim().replace( ' ', '0' ) ) - 1, Integer.parseInt( sdate.substring( 0, 2 ).trim().replace( ' ', '0' ) ) );

if ( DAY.equals( stype ) ) {
   gc.add( Calendar.DAY_OF_MONTH, iamount );
}
else if ( MONTH.equals( stype ) ) {
   gc.add( Calendar.MONTH, iamount );
}
else if( YEAR.equals( stype ) ) {
   gc.add( Calendar.YEAR, iamount );
}

Esse método recebe como parâmetros uma data (String... motivo do meu problema), um inteiro que representa o incremento (ou decremento) e uma outra que define se o processamento ocorrerá sobre o dia, mês ou ano.
O meu problema está no momento em que eu gero o GregorianCalendar, ali eu tive que fazer um substring para obter as partes da data, no entanto, não tem como eu garantir que a data estará sempre nesse formato (dd/MM/yyyy).
Queria saber se tem alguma forma de descobrir o formato que está sendo utilizado para formatar a data na máquina do cliente? Ou, seria melhor ainda, se tem como eu obter as partes da data (dia, mês e ano) de uma String independentemente do formato em que ela se encontre?

Desde já agradeço pela atenção

[]s

25 Respostas

Vini_Fernandes

Cara, para formatar datas costumo utilizar a SimpleDateFormat:

SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
Date suaData = // colocar sua data
String dataFormatada = dateFormat.format(suaData);

Mais detalhes voce conseguira nma APi, tem muitos recursos lá!
ate mais

rissato

pq vc nao usa o método add() da classe Calendar?

Calendar c = Calendar.getInstance();
//Adicionar um dia...
c.add(Calendar.DAY_OF_MONTH, 1)
g4j

Sem chance! Você só consegue quando o dia do mês for maior que 12. Imagine a data 12/12/2008. Impossível saber qual é o dia pra poder pegar o próximo.

eberson_oliveira

Vini Fernandes:
Cara, para formatar datas costumo utilizar a SimpleDateFormat:

SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
Date suaData = // colocar sua data
String dataFormatada = dateFormat.format(suaData);

Mais detalhes voce conseguira nma APi, tem muitos recursos lá!
ate mais

Olá Vini Fernandes,

O meu problema está no fato de não saber em que formato a data virá… pode ser uma string qualquer, inclusive inválida, eu queria identificar as partes adicionar dias, meses, anos, conforme a necessidade e retornar no mesmo formato que me foi enviada.

[]s

eberson_oliveira

rissato:
pq vc nao usa o método add() da classe Calendar?

Calendar c = Calendar.getInstance(); //Adicionar um dia... c.add(Calendar.DAY_OF_MONTH, 1)

Ola rissato,

Eu pretendo usar sim o método add, só que não sei como informar a data para ele… eu estou utilzando o GregorianCalendar e não encontrei um construtor onde pudesse informar uma string contendo uma data qualquer… Eu preciso receber essa data e manipulá-la, da forma como mencionou, porém não sei como passar a data para ele…

alguma idéia?

[]s

eberson_oliveira

g4j:
eberson_oliveira:

Queria saber se tem alguma forma de descobrir o formato que está sendo utilizado para formatar a data na máquina do cliente? Ou, seria melhor ainda, se tem como eu obter as partes da data (dia, mês e ano) de uma String independentemente do formato em que ela se encontre?

Sem chance! Você só consegue quando o dia do mês for maior que 12. Imagine a data 12/12/2008. Impossível saber qual é o dia pra poder pegar o próximo.

Olá g4j,

Por isso mesmo eu queria descobrir uma forma de descobrir uma forma de identificar o formato ou passá-lo a algum objeto que identifique automaticamente… Imaginei que tivesse alguma api que tivesse acesso a esse tipo de informação, mas não estou encontrando nada… Pensei em procurar, inicialmente, no Locale, mas não achei nada que eu pudesse e/ou soubesse usar…

Tem alguma solução/idéia?

[]s

T

GregorianCalendar não tem um construtor que recebe uma string. Em vez disso, normalmente se faz algo parecido com o seguinte:

Calendar cal = Calendar.getInstance();
DateFormat df = new SimpleDateFormat ("dd/MM/yyyy");
Date dt = df.parse ("12/12/2008");
cal.setTime (dt);
rissato

eberson_oliveira:
rissato:
pq vc nao usa o método add() da classe Calendar?

Calendar c = Calendar.getInstance(); //Adicionar um dia... c.add(Calendar.DAY_OF_MONTH, 1)

Ola rissato,

Eu pretendo usar sim o método add, só que não sei como informar a data para ele… eu estou utilzando o GregorianCalendar e não encontrei um construtor onde pudesse informar uma string contendo uma data qualquer… Eu preciso receber essa data e manipulá-la, da forma como mencionou, porém não sei como passar a data para ele…

alguma idéia?

[]s

Calendar c = Calendar.getInstance();
//Setar a data com a data atual...
c.setTime(new Date());
//Adicionar um dia...
c.add(Calendar.DAY_OF_MONTH, 1)
eberson_oliveira

thingol:
GregorianCalendar não tem um construtor que recebe uma string. Em vez disso, normalmente se faz algo parecido com o seguinte:

Calendar cal = Calendar.getInstance();
DateFormat df = new SimpleDateFormat ("dd/MM/yyyy");
Date dt = df.parse ("12/12/2008");
cal.setTime (dt);
[/code]</blockquote>

Olá thingol,

Entendi o seu exemplo.... acho que não estou conseguindo me expressar...
Eu pretendo receber uma data num formato qualquer ("dd/MM/yyyy", "d/M/yy", etc ), adicionar um mês, por exemplo, e retorná-la no mesmo formato em que recebi (para não alterar o formato de quem invocou o meu método)
 fiz vários testes, mas não obtive sucesso...

Entendeu o que estou tentando fazer? Não sei se é possível...

grato pela atenção,

[]s
eberson_oliveira

rissato:
eberson_oliveira:
rissato:
pq vc nao usa o método add() da classe Calendar?

Calendar c = Calendar.getInstance(); //Adicionar um dia... c.add(Calendar.DAY_OF_MONTH, 1)

Ola rissato,

Eu pretendo usar sim o método add, só que não sei como informar a data para ele… eu estou utilzando o GregorianCalendar e não encontrei um construtor onde pudesse informar uma string contendo uma data qualquer… Eu preciso receber essa data e manipulá-la, da forma como mencionou, porém não sei como passar a data para ele…

alguma idéia?

[]s

Calendar c = Calendar.getInstance(); //Setar a data com a data atual... c.setTime(new Date()); //Adicionar um dia... c.add(Calendar.DAY_OF_MONTH, 1)

Olá rissato,

Isso funciona com a data atual… mas se for uma data qualquer, num formato qualquer e string ainda…
como faço para manipulá-la e retornar o resultado no mesmo formato que recebi?

[]s

T
Eu pretendo receber uma data num formato qualquer ("dd/MM/yyyy", "d/M/yy", etc ), adicionar um mês, por exemplo, e retorná-la no mesmo formato em que recebi (para não alterar o formato de quem invocou o meu método)

Você pode então fazer o seguinte: digamos que existam 3 formatos que você aceite (afinal de contas, seu programa não usa inteligência artificial, ou usa?). Então crie 3 DateFormat, um para cada formato aceito.
Use setLenient(false) para que o método parse gere uma exceção se não estiver no formato aceito.
Se você conseguir ler o dado, então use o formato para formatar o resultado na volta.

eberson_oliveira

thingol:
Eu pretendo receber uma data num formato qualquer ("dd/MM/yyyy", "d/M/yy", etc ), adicionar um mês, por exemplo, e retorná-la no mesmo formato em que recebi (para não alterar o formato de quem invocou o meu método)

Você pode então fazer o seguinte: digamos que existam 3 formatos que você aceite (afinal de contas, seu programa não usa inteligência artificial, ou usa?). Então crie 3 DateFormat, um para cada formato aceito.
Use setLenient(false) para que o método parse gere uma exceção se não estiver no formato aceito.
Se você conseguir ler o dado, então use o formato para formatar o resultado na volta.

Entendi… vou adotar a sua solução… farei alguns testes e depois coloco o resultado. Sobre a inteligência artificial, só não uso porque não sei… :cry: mas quando aprender… volto aqui e coloco a solução usando esse conceito :smiley:

Muito grato pela ajuda

[]s

rissato

Olá rissato,

Isso funciona com a data atual… mas se for uma data qualquer, num formato qualquer e string ainda…
como faço para manipulá-la e retornar o resultado no mesmo formato que recebi?

[]s

Só vc substituir o “new Date()” pela data que vc quer… e pra isso vc nao precisa nem pensar em formato…

eberson_oliveira

Olá a todos,

Montei o código da seguinte maneira:

String[] formatos = new String[] { "dd/MM/yyyy", "dd/MM/yy" };

SimpleDateFormat df = null;
Date date = null;

for ( int i = 0; i < formatos.length; i++ ) {
    df = new SimpleDateFormat( formatos[ i ] );
    df.setLenient( false );

     try {
        date = df.parse( sdate );
        break;
     }
     catch ( ParseException e ) {}
}

if ( date == null || df == null ) {
    throw new IllegalArgumentException( "Formato inválido!!!" );
}

GregorianCalendar gc = new GregorianCalendar();
gc.setTime( date );

if ( "DAY".equals( stype ) ) {
    gc.add( Calendar.DAY_OF_MONTH, iamount );
}
else if ( "MONTH".equals( stype ) ) {
    gc.add( Calendar.MONTH, iamount );
}
else if ( "YEAR".equals( stype ) ) {
    gc.add( Calendar.YEAR, iamount );
}
      
return df.format( gc.getTime() );

Coloquei apenas dois tipos (só para ver se funcionaria), e fiz o seguinte teste:

System.out.println( Teste.calculateDate( "01/12/2008", 1, "DAY"   ) ); //deveria retornar 02/12/2008
System.out.println( Teste.calculateDate( "01/12/08"    , 1, "DAY"   ) ); //02/12/08
System.out.println( Teste.calculateDate( "28/02/2008", 1, "DAY"   ) ); //29/02/2008
System.out.println( Teste.calculateDate( "01/03/08"   , 1, "DAY"   ) ); //01/04/08
System.out.println( Teste.calculateDate( "01/03/2004", 1, "MONTH" ) ); //01/04/2004
System.out.println( Teste.calculateDate( "01/05/2006", -1, "MONTH" ) ); //01/04/2006

obtive o seguinte resultado:

02/12/2008
02/12/0008
29/02/2008
02/03/0008
01/04/2004
01/04/2006

Como faço para que ele entender que deve retornar 02/12/08, por exemplo, ao invés de 02/12/0008?

Usei o setLenient( false )... mas quando tentou pegar uma data: "02/12/08" com formato "dd/MM/yyyy" não deu exception... alguma idéia?

Agradeço desde já,

[]s

T

Acho que você tem de testar primeiro o “dd/MM/yy” e depois o “dd/MM/yyyy”.

ramilani12

Uma opção crie uma expressão regular para validar se a data esta no formato requerido por exemplo:

Validar este formato: dd/MM/yyyy

Pattern patter =  Pattern.compile("(0[1-9]|[1-2][0-9]|3[0-1])/(0[1-9]|1[0-2])/\d{4}");
Matcher match = patter.matcher(periodo);

if (!match.matches())
 // o que fazer a data nao esta no formato requerido ...

Fica a seu critério …

eberson_oliveira
thingol:
Acho que você tem de testar primeiro o "dd/MM/yy" e depois o "dd/MM/yyyy".

Olá thingol,

Fiz o teste que vc sugeriu e funcionou... sabe dizer porque não lançou exception quando mandei a data no formato "errado"?

ramilani12:
Uma opção crie uma expressão regular para validar se a data esta no formato requerido por exemplo:

Validar este formato: dd/MM/yyyy

Pattern patter =  Pattern.compile("(0[1-9]|[1-2][0-9]|3[0-1])/(0[1-9]|1[0-2])/\d{4}");  
Matcher match = patter.matcher(periodo);  
  
if (!match.matches())  
// o que fazer a data nao esta no formato requerido ...

Olá ramilani12,

Gostei do formato por expressão regular.. no entanto, como faço para contemplar algo desse tipo: "MM/dd/yyyy" e "dd/MM/yyyy"?
tem alguma idéia?

[]s

ramilani12

Oras, é só inverter a expressão:

1º Exemplo: valida se o formato está dd/mm/yyyy

Pattern patter =  Pattern.compile("(0[1-9]|[1-2][0-9]|3[0-1])/(0[1-9]|1[0-2])/\d{4}");

2º Exemplo valida se está neste formato: mm/dd/yyyy

Pattern patter =  Pattern.compile("(0[1-9]|1[0-2])/(0[1-9]|[1-2][0-9]|3[0-1])/\d{4}");

(0[1-9]|[1-2][0-9]|3[0-1]) -> Aqui valida o dia com as seguintes ocorrências : 01 , 17 ou 31
(0[1-9]|1[0-2]) -> Aqui valida o mês com as seguintes ocorrências: 01 , 09 , 10 até 12
\d{4} -> Valida o ano 2009 , 2010 com tamanho limitado a 4, bom ira demorar um pouco até chegarmos no ano de 20001

eberson_oliveira
ramilani12:
Oras, é só inverter a expressão: 1º Exemplo: valida se o formato está dd/mm/yyyy
Pattern patter =  Pattern.compile("(0[1-9]|[1-2][0-9]|3[0-1])/(0[1-9]|1[0-2])/\d{4}");
2º Exemplo valida se está neste formato: mm/dd/yyyy
Pattern patter =  Pattern.compile("(0[1-9]|1[0-2])/(0[1-9]|[1-2][0-9]|3[0-1])/\d{4}");

(0[1-9]|[1-2][0-9]|3[0-1]) -> Aqui valida o dia com as seguintes ocorrências : 01 , 17 ou 31
(0[1-9]|1[0-2]) -> Aqui valida o mês com as seguintes ocorrências: 01 , 09 , 10 até 12
\\d{4} -> Valida o ano 2009 , 2010 com tamanho limitado a 4, bom ira demorar um pouco até chegarmos no ano de 20001

Entendi o que disse, mas como faço pra saber o formato da seguinte data: "12/12/2002", é "dd/MM/yyyy" ou é "MM/dd/yyyy"?

Vou colocar a classe... assim fica mais fácil de entender o meu contexto:

package testes;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TesteCalculaData {
   
   private Map getFormatosPermitidos() {
      Map mapa = new HashMap();
      
      mapa.put( Pattern.compile( "(0[1-9]|[1-2][0-9]|3[0-1])/(0[1-9]|1[0-2])/\d{4}" ), "dd/MM/yyyy" );
      mapa.put( Pattern.compile( "(0[1-9]|[1-2][0-9]|3[0-1])/(0[1-9]|1[0-2])/\d{2}" ), "dd/MM/yy"   );
      
      return mapa;
   }
   
   public String calculateDate( String sdate, int iamount, String stype ) {

      SimpleDateFormat df = null;
      Date date = null;
      Map formatosPermitidos = getFormatosPermitidos();
      Iterator iterator = formatosPermitidos.keySet().iterator();
      Matcher match;
      
      while( iterator.hasNext() ){
         Pattern pattern = ( Pattern ) iterator.next();
         
         match = pattern.matcher( sdate );
         
         if ( match.matches() ){
            df = new SimpleDateFormat( ( String ) formatosPermitidos.get( pattern ) );
            df.setLenient( false );
            try {
               date = df.parse( sdate );
            }
            catch ( ParseException e ) {
               //tratar depois...
               e.printStackTrace();
            }

            break;
         }
         
      }

      if ( date == null || df == null ) {
         return "Deu erro na data: " + sdate;
//         descomentar o codigo abaixo quando terminar a implementação
//         throw new IllegalArgumentException( "Formato inválido!!!" );
      }

      GregorianCalendar gc = new GregorianCalendar();
      gc.setTime( date );

      if ( "DAY".equals( stype ) ) {
         gc.add( Calendar.DAY_OF_MONTH, iamount );
      }
      else if ( "MONTH".equals( stype ) ) {
         gc.add( Calendar.MONTH, iamount );
      }
      else {
         gc.add( Calendar.YEAR, iamount );
      }
      
      String sformatDate =  df.format( gc.getTime() );

      return sformatDate;
   }
   
   public static void main( String[] args ) {
      
      TesteCalculaData calulaData = new TesteCalculaData();
      
      System.out.println( calulaData.calculateDate( "01/12/2008", 1, "DAY"   ) );
      System.out.println( calulaData.calculateDate( "01/12/08", 1, "DAY"   ) );
      System.out.println( calulaData.calculateDate( "28/02/2008", 1, "DAY"   ) );
      System.out.println( calulaData.calculateDate( "01/03/08", 1, "DAY"   ) );
      System.out.println( calulaData.calculateDate( "01/03/2004", 1, "MONTH" ) );
      System.out.println( calulaData.calculateDate( "01/05/2006", -1, "MONTH" ) );
      System.exit( 0 );
   }

}

Entende o que estou tentando explicar... não sei como fazer pra tratar essas situações...

[]s

L

Eu também estou com este mesmo problema. Não sei como identificar se o que está vindo é dia ou mês…Alguém tem alguma idéia???

Abs

T

12/11/2009 é 12 de novembro de 2009 ou 11 de dezembro de 2009?

eberson_oliveira

Depende do formato…

Eu estava seguindo o exemplo que me passou… depois resolvi fazer um teste com ER, mas acho que não vai funcionar, pois não tenho como responder a sua pergunta sem saber o formato da data e acho que não conseguirei descobrir pelas expressões… correto?

Sabe dizer pq o setLenient não lançou excessão quando testei “01/12/08” no formato “dd/MM/yyyy”?

Não sei se ajuda, mas o meu java é o 4, a minha solução precisa ser em java 4.

[]s

T

Em Java 1.4 é possível usar expressões regulares (ufa!). De fato, não tinha testado que mesmo com setLenient (false) o DateFormat aceita xx/xx/xx ou xx/xx/xxxx. Argh.

Bom, como há uma ambiguidade para várias datas - 11/12/2009 (11 de dezembro ou 12 de novembro?) nem sempre é possível determinar se o formato é dia/mês/ano ou mês/dia/ano, portanto é bom ver se você pode tratar isso de outra maneira.

ramilani12

De onde vem essas datas?, vc nao poderia padronizar estes dois formatos na origem.
Origem entenda onde é criada a data.

T

Outra coisa que é bem ambígua é você pegar um campo numérico e ver se o tal número representa um CPF ou CNPJ. Verifiquei que para 1/9 dos números, tanto os dígitos de verificação do CPF quanto os do CNPJ são compatíveis, então não é suficiente chutar que um número é um CPF se os dígitos de verificação do CPF baterem mas não os do CNPJ.

Criado 17 de março de 2009
Ultima resposta 19 de mar. de 2009
Respostas 25
Participantes 7