如何在不知道格式的情况下将字符串转换为日期?

Posted

技术标签:

【中文标题】如何在不知道格式的情况下将字符串转换为日期?【英文标题】:How to convert String to Date without knowing the format? 【发布时间】:2011-04-12 01:43:01 【问题描述】:

我有问题。我正在尝试将一些字符串转换为日期,但我不知道日期到达的格式。

可能是yyyy.mm.dd hh:mm:ssMM.dd.yy hh:mm:ss 等等。

如何将这些字符串转换为日期? 我试过这个:

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,即至少可以说很奇怪。

任何想法如何正确格式化字符串?

【问题讨论】:

type: 代码中的日期格式与您接下来编写的不同 typo: "type" --> "typo" 在我的上一条评论中,当然 顺便说一句,你认为“Sat Jan 31 00:42:48 CET 11”是什么? 0000/01/31 ? 虽然不被接受,但***.com/questions/3389348/parse-any-date-in-java 的答案提供了一些与 OP 问题相关的选项 【参考方案1】:

你不能!

如果您有日期 2010-08-05,那么它可以是 2010 年 8 月 5 日或 2010 年 5 月 8 日 - 您需要知道日期格式(或至少优先考虑一种格式)将它们区分开来。

【讨论】:

嗯,从技术上讲他可以,但他不知道它是否正确。 @Pawel:“从技术上讲,我可以用一个整数值精确地表示 Pi,它就是不正确的。” @JoachimSauer:从技术上讲,您永远无法用任意位数精确表示 Pi;) 这可能很明显,但根据用例,只需标记不明确的日期格式并继续前进就足够了。 @mahieddine 实际上这是一个答案。它说你不能!【参考方案2】:

我同意 Kragen 的观点,一般情况下没有正确的解决方案。但是,如果满足以下条件,您可以使用以下解决方案:

    你有一组所有可能的格式

    格式之间没有歧义;其中两个都无法成功解析日期表达式。

考虑以下迭代可能格式列表的解决方案。此解决方案使用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;
           

【讨论】:

看来只有当一个FlexibleDateParser的实例可以被多个线程使用(例如作为一个静态或单例存在,或者线程创建中的依赖注入)时,才需要这个例子的线程安全。对吗? NickC,我相信这是正确的。仍然为每个请求创建大量 simpledateformats 可能会影响性能,因为这是一项昂贵的操作。【参考方案3】:

如前所述,您至少需要有一个有序的候选模式列表。一旦你有了它,Apache DateUtils 就有一个 parseDate(String dateString, String[] patterns) 方法,可以让你轻松地尝试日期字符串上的模式列表,并通过第一个匹配的模式对其进行解析:

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

通过尝试各种不同的解析器来解析表示日期的字符串。

解析将依次尝试每个解析模式。仅当解析整个输入字符串时,解析才被视为成功。如果没有匹配的解析模式,则抛出 ParseException。

解析器会对解析的日期宽容。

【讨论】:

【参考方案4】:

这是一个基于美国日期格式的快速而肮脏的解决方案。

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 + "'");

【讨论】:

【参考方案5】:

您的问题与国际化有关。正如 Kragen 回答的那样,您不能只解析未知格式的日期。虽然您可以扫描所有可能的语言环境并解析 something,但您不知道它是否被正确解析。

只是一点 i18n 背景:

问:你能告诉我这个日期是指什么月份和年份吗?

2010 年 9 月 11 日?

答:不知道语言环境,你不能。它可以是任何东西。 9 月 11 日在美国。 11 月 9 日在英国。以此类推。

【讨论】:

2009 年 11 月 10 日在日本 :)【参考方案6】:

此答案是我对另一个问题的答案的副本,该问题被标记为与此问题重复

我曾经有一个任务是编写一个代码来解析一个字符串到日期,而日期格式是事先不知道的。 IE。我必须解析任何有效的日期格式。我写了一个项目,之后我写了一篇文章,描述了我的实现背后的想法。这是文章的链接:Java 8 java.time package: parsing any string to date。一般的想法是将您希望支持的所有模式写入外部属性文件并从那里读取它们并尝试通过这些格式一一解析您的字符串,直到您成功或用完格式。请注意,顺序也很重要,因为某些字符串可能对多种格式有效(美国/欧洲差异)。优点是您可以在不更改代码的情况下继续向文件添加/删除格式。所以这样的项目也可以为不同的客户定制

【讨论】:

【参考方案7】:

如果它是一个协议;定义格式 - 也许 ISO 会激怒除我们瑞典以外的所有人...

如果是用户输入的;让他们设置他们的语言环境。如果可以,请以完整格式显示解析的日期,以便用户可以验证它,例如 2009 年 11 月 10 日。

【讨论】:

【参考方案8】:

我唯一的猜测是,您应该先收集一些统计数据来确定格式。

如果你幸运的话,你会得到像“2010/08/13”这样可以明确解析的日期

【讨论】:

【参考方案9】:

这是对我有用的简单解决方案。 这是解析日期、将字符串作为参数传递并以您想要的任何格式解析它的简单方法。

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;
    

【讨论】:

【参考方案10】:
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;
    

【讨论】:

以上是关于如何在不知道格式的情况下将字符串转换为日期?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不丢失小数的情况下将数据框中的字符转换为数字

如何在不丢失 swift 精度的情况下将 String 转换为 Double [重复]

我可以在不更改项目顺序的情况下将 JSON 字符串转换为 Flex ArrayCollection 吗?

如何在不使用 bin 方法的情况下将二进制转换为十进制

PHP:在不知道原始字符集的情况下将任何字符串转换为 UTF-8,或者至少尝试一下

如何在不使用 ToString() 的情况下将 Int 转换为 C# 中的字符串?