验证包含&的日期或$ in Java

时间:2015-09-08 18:36:34

标签: java parsing date-formatting

我很惊讶地发现,在DateFormat.parse()使用DateFormat.SHORT时,一年中嵌入的某些字符(例如$或&)会“成功”解析。例如,"08/01/20&&"将解析为"Sat Aug 01 00:00:00 EDT 2020"

我更加惊讶的是我找不到任何点击这个问题。

练习是解析和验证日期。我们可以扫描我们正在解析特殊字符的字符串,但这看起来很无聊。

有人有任何建议吗?

public static void main(String[] args) {
    String s = "08/01/20&&";
    Date value = null;
    try {
        value = getDateFormat().parse(s);
    } catch (ParseException pe) {
        System.out.println("' must be a valid date in the form 'mm/dd/yyyy'");
    }
    System.out.println("Value:" + value);
}

public static DateFormat getDateFormat() {
    DateFormat formatDate = null;
    if (formatDate == null) {
        formatDate = DateFormat.getDateInstance(DateFormat.SHORT);
        //or at least in English locale
        //formatDate = DateFormat.getDateInstance(DateFormat.SHORT,Locale.ENGLISH);
        formatDate.setLenient(false);
    }
    return formatDate;
}

2 个答案:

答案 0 :(得分:4)

DateFormat返回的DateFormat.getDateInstanceSimpleDateFormat

formatDate instanceof SimpleDateFormat => true

根据Locale.US中的M/d/yy方法,模式(toPattern())为SimpleDateFormat

parse方法似乎不会考虑超出日期模式的尾随文本。 s的以下值将生成Sat Aug 01 00:00:00 PDT 2020,而不会抛出异常。对于格式字符202020被解释为yy,并且后面的文字似乎被忽略。

"08/01/20"
"08/01/20&&"
"08/01/20**"
"08/01/20..."
"08/01/20ABCDEFGHIJKLMNOPQRSTUVWXYZ"

Javadocs for DateFormat.parse州:

  

从给定字符串的开头解析文本以生成日期。该方法可能不会使用给定字符串的整个文本。

当然不会解析整个字符串。此外,您使用的&字符没有什么特别之处,除了它们是无关紧要的事实。

您可以获取模式的长度,然后将其与输入字符串的长度进行比较,以查看是否存在无关字符。这适用于DateFormat.SHORT,因为预期的字符数最多为8。

答案 1 :(得分:1)

java.time

随着 2014 年 3 月 Java SE 8 的发布,过时且容易出错的旧日期时间 API(java.util 日期时间类型及其格式类型 SimpleDateFormat 等)被取代由 java.timemodern date-time API* 编写,强烈建议改用此新 API。

使用现代 API,您就不会遇到这个问题,例如

有效日期:

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String s = "08/01/20";
        DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).localizedBy(Locale.ENGLISH);
        System.out.println(LocalDate.parse(s, dtf));
    }
}

输出:

2020-08-01

日期无效:

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String s = "08/01/20&&";
        DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).localizedBy(Locale.ENGLISH);
        System.out.println(LocalDate.parse(s, dtf));
    }
}

输出:

Exception in thread "main" java.time.format.DateTimeParseException:
                    Text '08/01/20&&' could not be parsed, unparsed text found at index 8

如果我希望现代 API 的行为方式与 SimpleDateFormat 默认情况下的行为方式相同。 following rule

<块引用>

从给定字符串的开头解析文本以生成日期。 该方法可能不会使用给定字符串的整个文本

如果您需要,DateTimeFormatter#parse(CharSequence, ParsePosition) 随时为您服务:

import java.text.ParsePosition;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String s = "08/01/20&&";
        DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).localizedBy(Locale.ENGLISH);
        LocalDate date = LocalDate.from(dtf.parse(s, new ParsePosition(0)));
        System.out.println(date);
    }
}

输出:

2020-08-01

modern date-time API 中详细了解 java.timeTrail: Date Time*

只是为了完整性:

这是您可以使用旧 API 完成的工作。

import java.text.DateFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.util.Date;
import java.util.Locale;

public class Main {
    public static void main(String[] args) throws ParseException {
        String s = "08/01/20&&";
        ParsePosition pp = new ParsePosition(0);
        Date value = DateFormat.getDateInstance(DateFormat.SHORT, Locale.ENGLISH).parse(s, pp);
        if (value == null || pp.getIndex() != s.length()) {
            System.out.println("The input must be a valid date in the form MM/dd/yyyy");
        } else {
            System.out.println("Value: " + value);
        }
    }
}

输出:

The input must be a valid date in the form MM/dd/yyyy

ParsePosition#getIndex 返回解析的最后一个字符之后的字符索引,即字符串 & 中第一个 08/01/20&& 的索引。


* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 & 7. 如果您正在为 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project