【问题标题】:converting all possible string dates to date objects将所有可能的字符串日期转换为日期对象
【发布时间】:2013-07-16 13:41:52
【问题描述】:

我需要能够将日期的所有可能字符串表示形式转换为 Date 对象。我知道这不是一项微不足道的任务,我主要寻求指导,因为我相信没有“单线”解决方案。

只有一个可能的输入类的当前示例:return new SimpleDateFormat("dd-MM-yyyy", Locale.ENGLISH).parse(input);

为了澄清我的问题,这里有一些可能的字符串输入:

  • 30-08-2011
  • 25.06.2011
  • 2011 年 6 月 15 日
  • 01-07-11
  • 19-9-2011

数据是由第三方提供的,所以我对此无能为力。我有一些关于检查分隔符是什么并据此选择正确格式的想法。

感谢任何帮助。

问候。

编辑:我可以访问用户的区域设置,这样我实际上可以区分日期和月份部分。或者更确切地说,我可以访问日期的语言环境。

【问题讨论】:

  • 您在某种程度上陷入了不确定的解决方案中。例如 05-06-2011 2011 年 5 月 6 日或 2011 年 6 月 5 日。对不起,伙计。
  • 我可以访问用户的语言环境,我会用这个更新 OP。
  • 你可以一个接一个地尝试,直到你得到一个日期(并希望它是正确的,正如@Pete 指出的那样)或定义一个清晰的第三方接口。还有一个问题,为什么发送不同的日期格式。
  • 不可取但仍然是解决方案:将所有可能的格式放入字符串数组中,并尝试解析日期字符串,直到成功或用完数据格式(在这种情况下重新抛出异常)。
  • @UwePlonus 它们是经过 OCR 的发票。并且尝试多种格式不会导致 ParseExceptions 形式的开销吗?

标签: java string date


【解决方案1】:

比我想象的更丑的代码。所以我会给它。 拆分令牌,填充 3 个日期组件。 对于给定的语言环境,仍然需要找到这些组件的顺序:Mdy、dMy。

public class DateIn {

    public static void main(String[] args) {
        String[] dates = {
            "30-08-2011",
            "25.06.2011",
            "15 Juni 2011",
            "01-07-11",
            "19-9-2011",
        };
        DateIn in = new DateIn();
        Locale locale = Locale.US;
        for (String date : dates) {
            try {
                Date d = in.read(date, locale);
                System.out.printf("%s -> %s%n", date,
                    new SimpleDateFormat("yyyy-MM-dd").format(d));
            } catch (IllegalArgumentException e) {
                System.out.println(e.getMessage());
            }
        }
    }

    private Date read(String date, Locale locale)
            throws IllegalArgumentException {
        final String[] ymdFormatters = { "y", "M", "d" };
        final int[] ymdGetters = { Calendar.YEAR, Calendar.MONTH,
            Calendar.DAY_OF_MONTH };
        String[] tokens = date.split("\\W+");
        final int Y = 0;
        final int M = 1;
        final int D = 2;
        int[] ymdValues = new int[3];
        for (String token : tokens) {
            if (token.matches("\\d+\\pL+")) { // 1st, 2nd, 3rd, 4th, 1e, ...
                token = token.replaceAll("\\pL+", "");
                ymdValues[D] = Integer.parseInt(token);
            } else if (token.matches("\\d+")) {
                int n = Integer.parseInt(token);
                if (n > 31) {
                    ymdValues[Y] = n;
                } else if (n > 12) {
                    ymdValues[D] = n;
                } else {
                    // Locale dependent order.
                    if (ymdValues[M] == 0) {
                        ymdValues[M] = n;
                    } else if (ymdValues[D] == 0) {
                        ymdValues[D] = n;
                    } else if (ymdValues[Y] == 0) {
                        ymdValues[Y] = n;
                    }
                }
            } else if (!token.isEmpty()) {
                for (int md = M; md <= D; ++md) {
                    String fmt = "";
                    for (int i = 0; i < 4; ++i) {
                        fmt += ymdFormatters[md];
                        SimpleDateFormat sdf = new SimpleDateFormat(fmt);
                        sdf.setLenient(true);
                        try {
                            Date dt = sdf.parse(token);
                            Calendar cal = Calendar.getInstance(locale);
                            cal.setTime(dt);
                            int n = cal.get(ymdGetters[md]);
                            if (md == M) {
                                ++n; // To 1-based
                            }
                            ymdValues[md] = n;
                            break;
                        } catch (ParseException e) {
                            //continue;
                        }
                    }
                }
            }
        }
        Calendar calendar = Calendar.getInstance(locale);
        for (int md = Y; md <= D; ++md) {
            int n = ymdValues[md];
            if (n == 0) {
                throw new IllegalArgumentException("Missing "
                    + ymdFormatters[md] + " part in " + date);
            }
            if (md == Y) {
                if (n < 100)
                    n += (calendar.get(Calendar.YEAR) / 100) * 100;
            } else if (md == M) {
                --n; // Calendar's month is 0-based.
            }
            calendar.set(ymdGetters[md], n);
        }
        return calendar.getTime();
    }
}

【讨论】:

    【解决方案2】:

    第一个想法可能是检测非数字和非字母字符。这些字符在日期中分隔月、日和年。在您的示例中,这些是“-”、“”和“。”。

    接下来根据检测到的分隔符拆分字符串。

    这给你: ["30","08","2011] 在第一种情况下。

    然后我们可以检查年份是第一年还是最后一年。这可以通过检查位数来完成。如果 numDigits==4 那么你知道哪一年是年份。否则,您可以检查范围,是否不在 [1,31] 中,然后又是一年。如果他们都在 [1,31] 中,那么我看不出有明确的决定方式。 (也许您对这一年的可能性了解更多?)

    最后是中间的字符串。在那里您只需检查它是否包含字母字符或数字。

    【讨论】:

    • 我认为可以从语言环境中推断出日/月 cq 月/日。所以这个解决方案似乎是一个不错的解决方案。
    • 01-01-13 作为日期呢?
    • 这简直是模棱两可。如果你有更多关于你的数据的信息,你可以做一个专门的猜测。例如,如果值 > 13,则很可能是这一天。如果您正在使用的日期在某个时间跨度内,例如 [2010,2013],这也可以为您提供线索,但 12-01-13 仍然几乎不可能解决。
    【解决方案3】:

    您可以尝试将字符串拆分为其组成部分(天、月、年)并单独解析它们。

    例如:

    String input = 30-08-2011;
    if (input.indexOf("-") == -1)
    return;
    else    
       String day = index.substring(0, selected.indexOf("-"));
    

    那么一天,可以单独解析。然后对月份和年份重复该过程。这样您就不必担心日期组件之间的格式。

    【讨论】:

      猜你喜欢
      • 2020-05-21
      • 2020-11-30
      • 2012-01-28
      • 1970-01-01
      • 1970-01-01
      • 2011-03-07
      • 1970-01-01
      • 2011-10-25
      相关资源
      最近更新 更多