有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在导入数据期间解析日期格式的最佳方法

我创建了一个方法,用于在数据导入期间解析不同日期格式的视图(400K记录)。我的方法捕获ParseException,并尝试在日期不同时使用下一种格式解析日期

问题:在数据导入过程中设置正确的日期格式是否更好(更快)

private static final String DMY_DASH_FORMAT = "dd-MM-yyyy";
private static final String DMY_DOT_FORMAT = "dd.MM.yyyy";
private static final String YMD_DASH_FORMAT = "yyyy-MM-dd";
private static final String YMD_DOT_FORMAT = "yyyy.MM.dd";
private static final String SIMPLE_YEAR_FORMAT = "yyyy";
private final List<String> dateFormats = Arrays.asList(YMD_DASH_FORMAT, DMY_DASH_FORMAT,
        DMY_DOT_FORMAT, YMD_DOT_FORMAT);

private Date parseDateFromString(String date) throws ParseException {
    if (date.equals("0")) {
        return null;
    }
    if (date.length() == 4) {
        SimpleDateFormat simpleDF = new SimpleDateFormat(SIMPLE_YEAR_FORMAT);
        simpleDF.setLenient(false);
        return new Date(simpleDF.parse(date).getTime());
    }
    for (String format : dateFormats) {
        SimpleDateFormat simpleDF = new SimpleDateFormat(format);
        try {
            return new Date(simpleDF.parse(date).getTime());
        } catch (ParseException exception) {
        }
    }
    throw new ParseException("Unknown date format", 0);
} 

共 (3) 个答案

  1. # 1 楼答案

    说到40万条记录,在这里进行一些“徒手”优化可能是合理的

    例如:如果传入字符串的第5位有“-”,那么您知道只有匹配的格式是“yyyy-MM-dd”。如果是“.”;你知道另一种格式是从yyyy开始的

    所以,如果你真的想优化,你可以获取那个角色,看看它是什么。可以用错误的格式保存3次解析尝试

    除此之外:我不确定“dd”是否意味着你的其他日期以“01”开头。。。或者如果“1.1.2016”也有可能。如果你所有的日期都使用两位数字表示dd/mm;然后你可以重复这个游戏——就像你在第三位时一样——在“dd…”之间选择和“dd-…”

    当然;有一个缺点——如果你遵循这个想法,你在很大程度上“硬编码”了预期的格式到你的代码中;因此,添加其他格式将变得更加困难。另一方面你会省很多钱

    最后:另一个可能大大加快速度的方法是使用流操作来读取/解析这些信息;因为这样你就可以研究并行流,简单地利用现代硬件并行处理4、8、16个日期的能力

  2. # 2 楼答案

    对于一个类似的问题statemet,我过去使用过time4j库。下面是一个例子。这也使用了下面给出的依赖项

    import java.text.ParseException;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Locale;
    
    import net.time4j.PlainDate;
    import net.time4j.format.expert.ChronoFormatter;
    import net.time4j.format.expert.MultiFormatParser;
    import net.time4j.format.expert.ParseLog;
    import net.time4j.format.expert.PatternType;
    
    public class MultiDateParser {
    
        static final MultiFormatParser<PlainDate> MULTI_FORMAT_PARSER;
    
        static {
    
            ChronoFormatter<PlainDate> style1 = ChronoFormatter.ofDatePattern("dd-MM-yyyy", PatternType.CLDR,
                    Locale.GERMAN);
            ChronoFormatter<PlainDate> style2 = ChronoFormatter.ofDatePattern("dd.MM.yyyy", PatternType.CLDR, Locale.US);
    
            ChronoFormatter<PlainDate> style3 = ChronoFormatter.ofDatePattern("yyyy-MM-dd", PatternType.CLDR, Locale.US);
    
            ChronoFormatter<PlainDate> style4 = ChronoFormatter.ofDatePattern("yyyy.MM.dd", PatternType.CLDR, Locale.US);
    
            //this is not supported
            //ChronoFormatter<PlainDate> style5 = ChronoFormatter.ofDatePattern("yyyy", PatternType.CLDR, Locale.US);
    
            MULTI_FORMAT_PARSER = MultiFormatParser.of(style1, style2, style3, style4);
        }
    
        public List<PlainDate> parse() throws ParseException {
            String[] input = { "11-09-2001", "09.11.2001", "2011-11-01", "2011.11.01", "2012" };
            List<PlainDate> dates = new ArrayList<>();
            ParseLog plog = new ParseLog();
    
            for (String s : input) {
                plog.reset(); // initialization
                PlainDate date = MULTI_FORMAT_PARSER.parse(s, plog);
    
                if (date == null || plog.isError()) {
                    System.out.println("Wrong entry found: " + s + " at position " + dates.size() + ", error-message="
                            + plog.getErrorMessage());
                } else {
                    dates.add(date);
                }
            }
            System.out.println(dates);
            return dates;
        }
    
        public static void main(String[] args) throws ParseException {
            MultiDateParser mdp = new MultiDateParser();
            mdp.parse();
        }
    
    }
    
    <dependency>
                <groupId>net.time4j</groupId>
                <artifactId>time4j-core</artifactId>
                <version>4.19</version>
            </dependency>
    
            <dependency>
                <groupId>net.time4j</groupId>
                <artifactId>time4j-misc</artifactId>
                <version>4.19</version>
            </dependency>
    

    案件yyyy必须以不同的方式处理,因为这不是一个日期。可能与您使用的逻辑相似(长度=4)是一种选择

    上面的代码返回,您可以检查一次快速性能运行,看看它是否可以扩展到您拥有的400k记录

    Wrong entry found: 2012 at position 4, error-message=Not matched by any format: 2012
    [2001-09-11, 2001-11-09, 2011-11-01, 2011-11-01]
    
  3. # 3 楼答案

    如果运行单线程,一个明显的改进是只创建一次SimpleDateFormat对象。在多线程情况下,需要使用ThreadLocal<SimpleDateFormat>

    还要修复异常处理。看起来它是由不应该被信任导入任何数据的人编写的