Как преобразовать строку в дату, не зная формат? - PullRequest
40 голосов
/ 14 сентября 2010

У меня проблема. Я пытаюсь преобразовать некоторые строки в дату и не знаю, в каком формате она поступает.

Это может быть yyyy.mm.dd hh:mm:ss или MM.dd.yy hh:mm:ss и т. Д.

Как я могу преобразовать эти строки в Date? Я попробовал это:

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

Но когда я распечатал someDate, он распечатался следующим образом: 2010-08-05 12: 42: 48.638 CEST, что означает yyyy.mm.dd hh:mm:ss, однако, когда я запустил вышеуказанный код, объект даты теперь стал Sat Jan 31 00:42:48 CET 11, что по меньшей мере, странно.

Есть идеи, как правильно форматировать строки на сегодняшний день?

Ответы [ 10 ]

46 голосов
/ 14 сентября 2010

Вы не можете!

Если у вас есть дата 2010-08-05, то это может быть либо 5 августа 2010 г., либо 8 мая 2010 г. - вам нужно , чтобы узнать формат даты (или вкак минимум, отдавайте приоритет одному формату, а не разделяйте его.

11 голосов
/ 14 сентября 2010

Я согласен с Крагеном, что в общем случае нет правильного решения.Однако, если выполняются следующие условия, вы можете использовать приведенное ниже решение:

  1. У вас есть набор всех возможных форматов

  2. Нетнеоднозначность между форматами;никакое выражение даты не может быть успешно проанализировано двумя из них.

Рассмотрим следующее решение, которое перебирает список возможных форматов.Это решение использует ThreadLocal, чтобы сделать разбор дат эффективным в многопоточной среде (помните, что SimpleDateFormat не является поточно-ориентированным):

public class FlexibleDateParser {
    private List<ThreadLocal<SimpleDateFormat>> threadLocals = new  ArrayList<ThreadLocal<SimpleDateFormat>>();

    public FlexibleDateParser(List<String> formats, final TimeZone tz){
        threadLocals.clear();
        for (final String format : formats) {
            ThreadLocal<SimpleDateFormat> dateFormatTL = new ThreadLocal<SimpleDateFormat>() {
                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<SimpleDateFormat> 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;
    }       
}
7 голосов
/ 14 сентября 2010

Как отмечалось ранее, вам нужно как минимум иметь упорядоченный список кандидатов на шаблоны. Когда у вас есть это, Apache DateUtils имеет метод parseDate(String dateString, String[] patterns), который позволяет вам легко попробовать список шаблонов в вашей строке даты и проанализировать его по первому, который соответствует:

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

Анализирует строку, представляющую дату, пробуя различные парсеры.

Анализ будет пробовать каждый шаблон анализа по очереди. Анализ считается успешным, только если он анализирует всю входную строку. Если шаблоны разбора не совпадают, генерируется ParseException.

Анализатор будет снисходительным к анализируемой дате.

5 голосов
/ 27 февраля 2014

Вот быстрое и грязное решение, основанное на американских форматах даты.

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 + "'");
}
4 голосов
/ 14 сентября 2010

Ваша проблема связана с интернационализацией. Как ответил Краген, вы не можете просто разобрать дату в неизвестном формате. Хотя вы можете сканировать все возможные локали и анализировать что-то , но вы не узнаете, правильно ли он был проанализирован.

Небольшой фон i18n:

В: Можете ли вы сказать мне, какой день месяц и год относится к этой дате:

09/11/10

A: Не зная языка, вы не можете. Это может быть что угодно. 11 сентября в США. 9 ноября в Великобритании. И так далее.

1 голос
/ 14 сентября 2010

Если это протокол;определить формат - возможно, ISO, который будет раздражать всех, кроме нас в Швеции ...

Если это ввод от пользователей;Пусть они устанавливают свою локаль.Если вы можете это сделать, покажите проанализированную дату в полном формате, чтобы пользователь мог ее проверить, например, 10 ноября 2009 г.

0 голосов
/ 12 июня 2019

Этот ответ является копией моего ответа на другой вопрос, помеченный как дубликат этого

Однажды у меня была задача написать код, который будет анализировать строку с датой, где формат даты заранее неизвестен. То есть Я должен был разобрать любой допустимый формат даты. Я написал проект и после этого написал статью, в которой описана идея моей реализации. Вот ссылка на статью: Java 8 пакет java.time: парсинг любой строки на сегодняшний день . Общая идея заключается в том, чтобы записать все шаблоны, которые вы хотите поддерживать, во внешний файл свойств, прочитать их оттуда и попытаться анализировать вашу строку по этим форматам один за другим, пока вы не добьетесь успеха или не исчерпаете форматы. Обратите внимание, что порядок также будет важен, так как некоторые строки могут быть действительными для нескольких форматов (различия США / Европы). Преимущество заключается в том, что вы можете продолжать добавлять / удалять форматы в файл, не меняя код. Таким образом, такой проект также может быть настроен для разных клиентов

0 голосов
/ 27 ноября 2015

Вот простое решение, которое работает для меня.Это простой метод для анализа даты, передачи строки в качестве аргумента и анализа в любом формате, который вам нужен.

0 голосов
/ 23 февраля 2013
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;
    }
0 голосов
/ 14 сентября 2010

Мое единственное предположение, что вы должны сначала собрать статистику, чтобы выяснить формат.

Если вам повезет, у вас будет дата типа «2010/08/13», которую можно однозначно проанализировать

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...