如何验证正确的日期格式模式?格式化格式,而不是字符串中的日期

时间:2019-02-28 03:55:26

标签: java

我在项目中使用Spring,属性文件如下所示。

reportPRM.field=\
TrxDateTime   |6    |yyMMdd;\
TrxDateTime   |6    |HHmmss;\
MerchantID    |16   |Space;\

我有一个带有多行的属性。用户可以更改TrxDateTime的日期格式模式。我需要验证模式的正确性。怎么做?

我尝试了下面的代码。

public static boolean validatePattern(String template) {
    try {
        new SimpleDateFormat(template);

        return true;
    } catch (IllegalArgumentException e) {
        logger.error(ThrowableHelper.getMessage(e));
    }

    return false;
}

但是事实证明,输入“ 0”为true。

编辑。添加了单元测试。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
@TestPropertySource(properties = "scheduler.enable=false")
public class DateFormatTest {

    @Test
    public void testDateFormat() {
        assertTrue(StringHelper.validatePattern("0"));
        assertTrue(StringHelper.validatePattern("abcde"));

        assertTrue(StringHelper.validatePattern("yyyyMMdd"));
        assertTrue(StringHelper.validatePattern("HHmmss"));
    }

}

对于输入“ 0”,“ yyyyMMdd”,“ HHmmss”返回true,对于“ abcde”返回false。但是我认为这还不够。日期格式模式必须符合通用标准模式。

编辑2。这是完整的属性。

reportPRM.field=\
TrxDateTime                                     |6  |yyMMdd;\
TrxDateTime                                     |6  |HHmmss;\
MerchantID                                      |16 |Space;\
CompanyName                                     |25 |Space;\
                                                |2  |ID;\
CardNo                                          |19 |0;\
                                                |4  |CPAY;\
Amount                                          |15 |0;\
{P: RespDesc, R: RespDescReversal}              |6  |0;\
{P: DSPRetCodePayment, R: DSPRetCodeReversal}   |3  |0;

我需要遍历每一行,并检查第3列中的值是否为日期格式的模式。但是上面的函数将true设为“ 0”。

4 个答案:

答案 0 :(得分:2)

SimpleDateFormat API说:

  

日期和时间格式由日期和时间模式字符串指定。在日期和时间模式字符串中,从“ A”到“ Z”以及从“ a”到“ z”的未加引号的字母被解释为表示日期或时间字符串的组成部分的模式字母。文本可以使用单引号(')进行引用以避免解释。 “”表示单引号。 所有其他字符均不解释;它们会在格式化过程中简单地复制到输出字符串中,或​​者在解析过程中会与输入字符串匹配。

     

定义了以下模式字母(保留了从'A'到'Z'以及从'a'到'z'的所有其他字符

(被我大胆)

因此,如果您只想在输入字符串中允许使用日期和时间模式字母,则构建一个包含要允许的字母的正则表达式(作为上面给出的已定义模式表的[A-Za-z]的子集)链接),并按照kosmo所指出的将输入字符串与正则表达式进行匹配。

要允许使用两种定义的格式,则需要使用正则表达式yyMMdd|HHmmss进行完全匹配;如果允许所有这些字母以任何组合使用,则需要[msdyHM]+

示例:

public class Main {
    public static void main(String args[]) {
        String[] patterns = { "[msdyHM]+", "yyMMdd|HHmmss" };
        String[] input = { "yyMMdd", "HHmmss", "yyyyMMdd", "0", "mm", "abcd" };
        for (String pattern : patterns) {
            for (String str : input) {
                System.out.println(pattern + " match " + str + " " + str.matches(pattern) );
            }
        }
    }
}

输出:

[msdyHM]+ match yyMMdd true
[msdyHM]+ match HHmmss true
[msdyHM]+ match yyyyMMdd true
[msdyHM]+ match 0 false
[msdyHM]+ match mm true
[msdyHM]+ match abcd false
yyMMdd|HHmmss match yyMMdd true
yyMMdd|HHmmss match HHmmss true
yyMMdd|HHmmss match yyyyMMdd false
yyMMdd|HHmmss match 0 false
yyMMdd|HHmmss match mm false
yyMMdd|HHmmss match abcd false

答案 1 :(得分:1)

解决方案1(正则表达式)

String datePattern = "\\d{2}-\\d{2}-\\d{4}";

String date1 = "200000-05-16";
String date2 = "05-16-2000";

Boolean isDate1 = date1.matches(datePattern);
Boolean isDate2 = date2.matches(datePattern);

System.out.println(isDate1);
System.out.println(isDate2);

输出:

false
true

解决方案2(SimpleDateFormat)

此解决方案采用SimpleDateFormat来检查其是否有效。请检查此链接以获取完整且出色的解决方案:http://www.mkyong.com/java/how-to-check-if-date-is-valid-in-java/

答案 2 :(得分:1)

如果您查看format symbols,则可能只想提供一个子集-太多的地方可能出问题-未被发现。

  • HH = 24小时,hh = 12小时(与PM不同)
  • yyyy =年。 YYYY =周年(当周重叠两年时会有所不同)

日期时间格式化程序接受的模式太多。

这意味着一些措施/努力:

  • 理想情况下,提供GUI来创建模式(即带有12 | 24的组合小时)。
  • 提供备忘单。
  • 允许使用某些模式,仅在后接(AM / PM)时才允许使用hh;提供热线电子邮件。
  • 具有图案的白名单。
  • 采用您的自定义模式;以Excel .xlsx模式为例,并将其转换为Java模式。

答案 3 :(得分:1)

跳过SimpleDateFormat类及其朋友,例如Date。这些类的设计不佳,现在已经过时了。而是使用DateTimeFormatter和java.time(现代Java日期和时间API)中的其他类。

您的确切要求不清楚。我提供以下要求的代码。 date 模式应该是带有DateTimeFormatter的有效模式,并且至少应包含一个用于日期的模式字母,例如yyMMdd或仅包含d。仅仅时代(BC / AD)还不够。单引号中的字母不算在内,因为它们不能用作图案字母,而可以用作文字。类似地, time 模式对于一天中的时间(而不是时区)应至少包含一个模式字母,并且不足一秒或几分之一秒的时间。

对于检查有效性,您可以使用try / catch块。唯一的问题是,例如0可以很好地用作有效模式,但是您要拒绝它。因此,此外,我使用正则表达式检查单引号之外是否存在至少一个相关的模式字母。正则表达式接受字母前面和后面带有偶数单引号的任何字符。

private static final String DATE_PATTERN_LETTERS = "uyDMLdgQqYwWEecF";
private static final Pattern DATE_PATTERN_PATTERN = requireAtLeastOne(DATE_PATTERN_LETTERS);
private static final String TIME_PATTERN_LETTERS = "ahKkHmsAN";
private static final Pattern TIME_PATTERN_PATTERN = requireAtLeastOne(TIME_PATTERN_LETTERS);

/**
 * @return a pattern that matches a string that contains
 *          at least one of the letters in {@code requiredLetters} not within single quotes
 */
private static Pattern requireAtLeastOne(String requiredLetters) {
    return Pattern.compile("[^']*(?:'[^']*'[^']*)*[" + requiredLetters + "][^']*(?:'[^']*'[^']*)*");
}

public static boolean validateDatePattern(String template) {
    if (! isValidPattern(template)) {
        return false;
    }
    return DATE_PATTERN_PATTERN.matcher(template).matches();
}

public static boolean validateTimePattern(String template) {
    if (! isValidPattern(template)) {
        return false;
    }
    return TIME_PATTERN_PATTERN.matcher(template).matches();
}

private static boolean isValidPattern(String template) {
    try {
        DateTimeFormatter.ofPattern(template);
        return true;
    } catch (IllegalArgumentException iae) {
        return false;
    }
}

让我们尝试一些日期模式:

    System.out.println(validateDatePattern("0"));
    System.out.println(validateDatePattern("abcde"));
    System.out.println(validateDatePattern("yyyyMMdd"));
    System.out.println(validateDatePattern("HHmmss"));
    System.out.println(validateDatePattern("'yMd in quotes'"));
    System.out.println(validateDatePattern("yMd 'outside quotes'"));

输出为,带有我的评论:

false  // 0 fails because it doesn’t contain a pattern letters for a date
false  // abcde fails because b is not a valid pattern letter
true   // yyyyMMdd is fine
false  // HHmmss fails because it’s for times, not dates
false  // 'yMd in quotes' fails because yMd are in quotes
true   // yMd 'outside quotes' is fine

我们还要看看一些时间模式字符串:

    System.out.println(validateTimePattern("0"));
    System.out.println(validateTimePattern("yyyyMMdd"));
    System.out.println(validateTimePattern("HHmmss"));

输出:

false
false
true
  

您能否简要说明所提供的正则表达式?

好的。 [^']*匹配0个或多个不是'的字符(单引号)。下一个(?:'[^']*'[^']*)*匹配0个或更多序列,其中每个序列是一个单引号,0个或多个非单引号,一个单引号和0个或多个非单引号。这样可以确保单引号的数量是偶数(并且由于它们成对出现,因此又可以确保以下模式字母不在单引号内)。它也根本不匹配单引号,因为这样的序列可能有0个。接下来,我将所需的字母放入[]内,以仅要求其中一个。最后,我重复[^']*(?:'[^']*'[^']*)*,与字母前相同。

链接: Oracle tutorial: Date Time解释了如何使用java.time。