Como converter String para Data sem saber o formato?

Eu tenho um problema. Eu estou tentando converter algumas seqüências de caracteres para data e não sei o formato que a data está chegando.

Pode vir como yyyy.mm.dd hh:mm:ss ou MM.dd.yy hh:mm:ss e assim por diante.

Como posso converter essas strings para Date? Eu tentei isso:

 DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss"); Date d = (Date)formatter.parse(someDate); 

Mas quando eu imprimi someDate ele imprimiu assim: 2010-08-05 12: 42: 48.638 CEST que significa yyyy.mm.dd hh:mm:ss , no entanto, quando eu corri o código acima, o object de data agora tornou-se Sat Jan 31 00:42:48 CET 11 que é estranho para dizer o mínimo.

Alguma idéia de como posso formatar corretamente as strings até hoje?

Você não pode!

Se você tiver a data 2010-08-05 então pode ser 5 de agosto de 2010 ou 8 de maio de 2010 – você precisa saber o formato de data (ou pelo menos priorizar um formato por cima) para diferenciá-los.

Concordo com Kragen que, no caso geral, não há solução correta. No entanto, se as seguintes condições persistirem, você poderá usar a solução abaixo:

  1. Você tem um conjunto de todos os formatos possíveis

  2. Não há ambiguidade entre os formatos; nenhuma expressão de data pode ser analisada com sucesso por dois deles.

Considere a seguinte solução que se repete em uma lista de possíveis formatos. Essa solução utiliza o ThreadLocal para tornar a análise de datas eficiente em um ambiente multi-thread (lembre-se que o SimpleDateFormat não é thread safe):

 public class FlexibleDateParser { private List> threadLocals = new ArrayList>(); public FlexibleDateParser(List formats, final TimeZone tz){ threadLocals.clear(); for (final String format : formats) { ThreadLocal dateFormatTL = new ThreadLocal() { protected SimpleDateFormat initialValue() { SimpleDateFormat sdf = new SimpleDateFormat(format); sdf.setTimeZone(tz); sdf.setLenient(false); return sdf; } }; threadLocals.add(dateFormatTL); } } public Date parseDate(String dateStr) throws ParseException { for (ThreadLocal tl : threadLocals) { SimpleDateFormat sdf = tl.get(); try { return sdf.parse(dateStr); } catch (ParseException e) { // Ignore and try next date parser } } // All parsers failed return null; } } 

Como mencionado anteriormente, você precisa pelo menos ter uma lista ordenada de candidatos padrão. Uma vez que você tenha feito isso, o Apache DateUtils possui um parseDate(String dateString, String[] patterns) que permite que você experimente facilmente uma lista de padrões em sua string de data e analise-a pelo primeiro que corresponder a:

 public static Date parseDate(String str, String[] parsePatterns) throws ParseException 

Analisa uma string representando uma data, tentando uma variedade de analisadores diferentes.

A análise tentará cada padrão de análise por vez. Uma análise só é considerada bem-sucedida se analisar toda a cadeia de input. Se nenhum padrão de análise corresponder, será executada uma ParseException.

O analisador será leniente em relação à data analisada.

Aqui está uma solução rápida e suja baseada em formatos de data americanos.

 public Date parseDate(String strDate) throws Exception { if (strDate != null && !strDate.isEmpty()) { SimpleDateFormat[] formats = new SimpleDateFormat[] {new SimpleDateFormat("MM-dd-yyyy"), new SimpleDateFormat("yyyyMMdd"), new SimpleDateFormat("MM/dd/yyyy")}; Date parsedDate = null; for (int i = 0; i < formats.length; i++) { try { parsedDate = formats[i].parse(strDate); return parsedDate; } catch (ParseException e) { continue; } } } throw new Exception("Unknown date format: '" + strDate + "'"); } 

Seu problema está relacionado à internacionalização. Como Kragen respondeu, você não pode simplesmente analisar a data em formato desconhecido. Embora você possa verificar todos os códigos de idioma possíveis e analisar algo , mas não saberia se ele foi analisado corretamente.

Apenas um pouco de fundo i18n:

P: Você pode me dizer em qual dia mês e ano essa data se refere:

09/11/10

R: Sem conhecer o local, você não pode. Pode ser qualquer coisa. 11 de setembro nos EUA. 9 de novembro na Grã-Bretanha. E assim por diante.

Se é um protocolo; defina o formato – talvez ISO que irrita todos, exceto nós na Suécia …

Se input de usuários; Deixe-os definir sua localidade. Se você puder, mostre a data analisada no formato completo para que o usuário possa verificá-la, como 10 de novembro de 2009.

Meu único palpite é que você deve coletar algumas statistics primeiro para descobrir o formato.

Se você tiver sorte, você terá data como “2010/08/13”, que pode ser analisada sem ambiguidade

Aqui está a solução simples, que é trabalhada para mim. Este é o método simples para analisar a data, passar o String como argumento e analisá-lo em qualquer formato que você quiser.

 String dateToConvert(String date) { String strDate = ""; try { //create SimpleDateFormat object with source string date format DateFormat sdfSource = new SimpleDateFormat("yyyy-MM-dd"); //parse the string into Date object Date d = sdfSource.parse(date); LocalLog.e(LOG_TAG, d.toString()); //create SimpleDateFormat object with desired date format SimpleDateFormat sdfDestination = new SimpleDateFormat(AppConstants.UNIVERSAL_DATE_FORMAT); //parse the date into another format strDate = sdfDestination.format(d); LocalLog.e(LOG_TAG, strDate); } catch (ParseException pe) { System.out.println("Parse Exception : " + pe); } return strDate; } 
 public String compareDate( PaymentTxnRequest request ) throws ParseException { Date debitDate= request.getPaymentTxn().getCrValDt(); Date now = new Date(); String response=""; SimpleDateFormat sdfDate = new SimpleDateFormat("dd/MM/yyyy"); String strCurrDate = sdfDate.format(now); String strDebitDate = sdfDate.format(debitDate); System.out.println("Current Date: " + strCurrDate); Date currentDate = new SimpleDateFormat("dd/MM/yyyy").parse(strCurrDate); Date txnDate = new SimpleDateFormat("dd/MM/yyyy").parse(strDebitDate); System.out.println("C -> "+currentDate); System.out.println("C -> "+txnDate); if (txnDate!=null){ if (currentDate.equals(txnDate)) { System.out.println("Valid Txn"); response="valid"; } if (currentDate.after(txnDate)) { System.out.println("--> Not Valid TXN Past"); response="notValid"; } if (currentDateenter code here.before(txnDate)){ System.out.println("Future Valid TXn"); response="future"; } } return response; }