Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Java中检查日期的完整性_Java_Validation_Calendar_Date - Fatal编程技术网

如何在Java中检查日期的完整性

如何在Java中检查日期的完整性,java,validation,calendar,date,Java,Validation,Calendar,Date,我觉得奇怪的是,在Java中创建Date对象的最明显的方法已经被弃用,并且似乎已经被一个不太明显的“使用宽松日历”所“替代” 如何检查以日、月和年的组合形式给出的日期是否有效 例如,2008-02-31(在yyyy-mm-dd中)将是无效日期。当前的方法是使用calendar类。它的方法将验证日期,并在超出范围时抛出异常,如示例中所示 忘记添加: 如果您获得一个日历实例,并使用日期设置时间,那么这就是获得验证的方式 Calendar cal = Calendar.getInstance(); c

我觉得奇怪的是,在Java中创建
Date
对象的最明显的方法已经被弃用,并且似乎已经被一个不太明显的“使用宽松日历”所“替代”

如何检查以日、月和年的组合形式给出的日期是否有效


例如,2008-02-31(在yyyy-mm-dd中)将是无效日期。

当前的方法是使用calendar类。它的方法将验证日期,并在超出范围时抛出异常,如示例中所示

忘记添加: 如果您获得一个日历实例,并使用日期设置时间,那么这就是获得验证的方式

Calendar cal = Calendar.getInstance();
cal.setLenient(false);
cal.setTime(yourDate);
try {
    cal.getTime();
}
catch (Exception e) {
  System.out.println("Invalid date");
}
你可以用

例如:

boolean isLegalDate(String s) {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    sdf.setLenient(false);
    return sdf.parse(s, new ParsePosition(0)) != null;
}

如@Maglob所示,基本方法是使用测试从字符串到日期的转换。这将捕获无效的日/月组合,如2008-02-31

然而,在实践中,这还远远不够,因为SimpleDataFormat.parse非常自由。您可能会关注两种行为:

日期字符串中的无效字符 令人惊讶的是,2008-02-2x将作为有效日期“通过”,例如locale format=“yyyy-MM-dd”。即使isLenient==false

年份:2、3或4位数? 您可能还希望强制执行4位年份,而不是允许默认的SimpleDataFormat行为(这将根据您的格式是“yyy-MM-dd”还是“yy-MM-dd”对“12-02-31”进行不同的解释)

标准库的严格解决方案 所以一个完整的字符串到日期的测试可以如下所示:一个正则表达式匹配的组合,然后是一个强制的日期转换。正则表达式的诀窍是使其对区域设置友好

  Date parseDate(String maybeDate, String format, boolean lenient) {
    Date date = null;

    // test date string matches format structure using regex
    // - weed out illegal characters and enforce 4-digit year
    // - create the regex based on the local format string
    String reFormat = Pattern.compile("d+|M+").matcher(Matcher.quoteReplacement(format)).replaceAll("\\\\d{1,2}");
    reFormat = Pattern.compile("y+").matcher(reFormat).replaceAll("\\\\d{4}");
    if ( Pattern.compile(reFormat).matcher(maybeDate).matches() ) {

      // date string matches format structure, 
      // - now test it can be converted to a valid date
      SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance();
      sdf.applyPattern(format);
      sdf.setLenient(lenient);
      try { date = sdf.parse(maybeDate); } catch (ParseException e) { }
    } 
    return date;
  } 

  // used like this:
  Date date = parseDate( "21/5/2009", "d/M/yyyy", false);
请注意,正则表达式假定格式字符串仅包含日、月、年和分隔符。除此之外,格式可以是任何语言环境格式:“d/MM/yy”、“yyy-MM-dd”等等。当前区域设置的格式字符串可以如下获得:

Locale locale = Locale.getDefault();
SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance(DateFormat.SHORT, locale );
String format = sdf.toPattern();
乔达时间-更好的选择? 我最近听说了,我想比较一下。两点:

  • 与SimpleDateFormat不同,似乎更擅长于严格处理日期字符串中的无效字符
  • 目前还看不到用它强制执行4位数年份的方法(但我想你可以为此创建自己的)
  • 使用起来非常简单:

    import org.joda.time.format.*;
    import org.joda.time.DateTime;
    
    org.joda.time.DateTime parseDate(String maybeDate, String format) {
      org.joda.time.DateTime date = null;
      try {
        DateTimeFormatter fmt = DateTimeFormat.forPattern(format);
        date =  fmt.parseDateTime(maybeDate);
      } catch (Exception e) { }
      return date;
    }
    

    关于SimpleDataFormat使用的两条评论

    它应该声明为静态实例 如果声明为静态访问,则应同步访问,因为它不是线程安全的


    IME这比为每个日期解析实例化一个实例更好。

    使用标准库的另一种严格解决方案是执行以下操作:

    1) 使用您的模式创建严格的SimpleDataFormat

    2) 尝试使用format对象分析用户输入的值

    3) 如果成功,请使用相同的日期格式(从(1))重新格式化从(2)产生的日期

    4) 将重新格式化的日期与用户输入的原始值进行比较。如果它们相等,则输入的值严格匹配您的模式


    这样,您就不需要创建复杂的正则表达式——在我的例子中,我需要支持SimpleDataFormat的所有模式语法,而不是仅限于某些类型,如天、月和年。

    假设这两种类型都是字符串(否则它们已经是有效日期),这里有一种方法:

    package cruft;
    
    import java.text.DateFormat;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class DateValidator
    {
        private static final DateFormat DEFAULT_FORMATTER;
    
        static
        {
            DEFAULT_FORMATTER = new SimpleDateFormat("dd-MM-yyyy");
            DEFAULT_FORMATTER.setLenient(false);
        }
    
        public static void main(String[] args)
        {
            for (String dateString : args)
            {
                try
                {
                    System.out.println("arg: " + dateString + " date: " + convertDateString(dateString));
                }
                catch (ParseException e)
                {
                    System.out.println("could not parse " + dateString);
                }
            }
        }
    
        public static Date convertDateString(String dateString) throws ParseException
        {
            return DEFAULT_FORMATTER.parse(dateString);
        }
    }
    
    以下是我得到的输出:

    java cruft.DateValidator 32-11-2010 31-02-2010 04-01-2011
    could not parse 32-11-2010
    could not parse 31-02-2010
    arg: 04-01-2011 date: Tue Jan 04 00:00:00 EST 2011
    
    Process finished with exit code 0
    

    正如您所看到的,它确实很好地处理了这两种情况。

    键是df.setLenient(false)。对于简单的情况,这就足够了。如果您正在寻找更健壮(我怀疑)和/或像joda time这样的替代库,那么请查看


    上面的日期解析方法很好,我只是在现有方法中添加了新的check,这些方法使用formatter将转换后的日期与原始日期进行双重检查,因此在我验证的情况下,它几乎适用于每种情况。e、 g.2013年2月29日为无效日期。 给定函数根据当前可接受的日期格式解析日期。如果未成功解析日期,则返回true

     public final boolean validateDateFormat(final String date) {
            String[] formatStrings = {"MM/dd/yyyy"};
            boolean isInvalidFormat = false;
            Date dateObj;
            for (String formatString : formatStrings) {
                try {
                    SimpleDateFormat sdf = (SimpleDateFormat) DateFormat.getDateInstance();
                    sdf.applyPattern(formatString);
                    sdf.setLenient(false);
                    dateObj = sdf.parse(date);
                    System.out.println(dateObj);
                    if (date.equals(sdf.format(dateObj))) {
                        isInvalidFormat = false;
                        break;
                    }
                } catch (ParseException e) {
                    isInvalidFormat = true;
                }
            }
            return isInvalidFormat;
        }
    

    我建议您使用apache中的
    org.apache.commons.validator.GenericValidator

    GenericValidator.isDate(字符串值、字符串日期模式、布尔严格)


    注意:严格-是否有日期模式的精确匹配。

    这对我来说非常有用。本提出了上述方法

    private static boolean isDateValid(String s) {
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        try {
            Date d = asDate(s);
            if (sdf.format(d).equals(s)) {
                return true;
            } else {
                return false;
            }
        } catch (ParseException e) {
            return false;
        }
    }
    
    java.time 通过将(类)内置到Java8及更高版本中,您可以使用该类

    为了解决所指出的问题,我添加了一个方法来验证
    dateString
    不包含任何无效字符

    我是这样做的:

    private boolean isDateCorrect(String dateString) {
        try {
            Date date = mDateFormatter.parse(dateString);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            return matchesOurDatePattern(dateString);    //added my method
        }
        catch (ParseException e) {
            return false;
        }
    }
    
    /**
     * This will check if the provided string matches our date format
     * @param dateString
     * @return true if the passed string matches format 2014-1-15 (YYYY-MM-dd)
     */
    private boolean matchesDatePattern(String dateString) {
        return dateString.matches("^\\d+\\-\\d+\\-\\d+");
    }
    

    我认为最简单的方法就是将字符串转换为日期对象,然后将其转换回字符串。如果两个字符串仍然匹配,则给定的日期字符串可以

    public boolean isDateValid(String dateString, String pattern)
    {   
        try
        {
            SimpleDateFormat sdf = new SimpleDateFormat(pattern);
            if (sdf.format(sdf.parse(dateString)).equals(dateString))
                return true;
        }
        catch (ParseException pe) {}
    
        return false;
    }
    

    以下是我在不使用外部库的情况下对节点环境所做的操作:

    Date.prototype.yyyymmdd = function() {
       var yyyy = this.getFullYear().toString();
       var mm = (this.getMonth()+1).toString(); // getMonth() is zero-based
       var dd  = this.getDate().toString();
       return zeroPad([yyyy, mm, dd].join('-'));  
    };
    
    function zeroPad(date_string) {
       var dt = date_string.split('-');
       return dt[0] + '-' + (dt[1][1]?dt[1]:"0"+dt[1][0]) + '-' + (dt[2][1]?dt[2]:"0"+dt[2][0]);
    }
    
    function isDateCorrect(in_string) {
       if (!matchesDatePattern) return false;
       in_string = zeroPad(in_string);
       try {
          var idate = new Date(in_string);
          var out_string = idate.yyyymmdd();
          return in_string == out_string;
       } catch(err) {
          return false;
       }
    
       function matchesDatePattern(date_string) {
          var dateFormat = /[0-9]+-[0-9]+-[0-9]+/;
          return dateFormat.test(date_string); 
       }
    }
    
    下面是如何使用它:

    isDateCorrect('2014-02-23')
    true
    
    tl;博士 使用on来解析一个。这是一个陷阱

    解析之后,您可以检查合理的值。例如,过去一百年内的出生日期

    birthDate.isAfter( LocalDate.now().minusYears( 100 ) )
    
    避免遗留日期时间类 避免使用Java最早版本附带的麻烦的旧日期时间类。现在被班级取代了

    LocalDate
    &
    DateTimeFormatter
    &
    ResolverStyle
    该类表示一个仅限日期的值,不包含一天中的时间和时区

    String input = "31/02/2000";
    DateTimeFormatter f = DateTimeFormatter.ofPattern ( "dd/MM/uuuu" );
    try {
        LocalDate ld = LocalDate.parse ( input , f );
        System.out.println ( "ld: " + ld );
    } catch ( DateTimeParseException e ) {
        System.out.println ( "ERROR: " + e );
    }
    
    该类可以设置为使用枚举中定义的三种宽容模式中的任意一种来解析字符串。我们在上面的代码中插入一行来尝试每种模式

    f = f.withResolverStyle ( ResolverStyle.LENIENT );
    
    结果是:

    • ResolverStyle.lencient

      ld:2000-03-02
    • ResolverStyle.SMART

      ld:2000-02-29
    • ResolverStyle.STRICT

      错误:java.time.format.DateTimeParseException:文本“31/02/2000”无法为PAR
      birthDate.isAfter( LocalDate.now().minusYears( 100 ) )
      
      String input = "31/02/2000";
      DateTimeFormatter f = DateTimeFormatter.ofPattern ( "dd/MM/uuuu" );
      try {
          LocalDate ld = LocalDate.parse ( input , f );
          System.out.println ( "ld: " + ld );
      } catch ( DateTimeParseException e ) {
          System.out.println ( "ERROR: " + e );
      }
      
      f = f.withResolverStyle ( ResolverStyle.LENIENT );
      
      // to return valid days of month, according to month and year
      int returnDaysofMonth(int month, int year) {
          int daysInMonth;
          boolean leapYear;
          leapYear = checkLeap(year);
          if (month == 4 || month == 6 || month == 9 || month == 11)
              daysInMonth = 30;
          else if (month == 2)
              daysInMonth = (leapYear) ? 29 : 28;
          else
              daysInMonth = 31;
          return daysInMonth;
      }
      
      // to check a year is leap or not
      private boolean checkLeap(int year) {
          Calendar cal = Calendar.getInstance();
          cal.set(Calendar.YEAR, year);
          return cal.getActualMaximum(Calendar.DAY_OF_YEAR) > 365;
      }
      
       public static boolean checkFormat(String dateTimeString) {
          return dateTimeString.matches("^\\d{4}-\\d{2}-\\d{2}") || dateTimeString.matches("^\\d{4}-\\d{2}-\\d{2}\\s\\d{2}:\\d{2}:\\d{2}")
                  || dateTimeString.matches("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}") || dateTimeString
                  .matches("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z") ||
                  dateTimeString.matches("^\\d{4}-\\d{2}-\\d{2}\\s\\d{2}:\\d{2}:\\d{2}Z");
      }
      
              public static String detectDateFormat(String inputDate, String requiredFormat) {
              String tempDate = inputDate.replace("/", "").replace("-", "").replace(" ", "");
              String dateFormat;
      
              if (tempDate.matches("([0-12]{2})([0-31]{2})([0-9]{4})")) {
                  dateFormat = "MMddyyyy";
              } else if (tempDate.matches("([0-31]{2})([0-12]{2})([0-9]{4})")) {
                  dateFormat = "ddMMyyyy";
              } else if (tempDate.matches("([0-9]{4})([0-12]{2})([0-31]{2})")) {
                  dateFormat = "yyyyMMdd";
              } else if (tempDate.matches("([0-9]{4})([0-31]{2})([0-12]{2})")) {
                  dateFormat = "yyyyddMM";
              } else if (tempDate.matches("([0-31]{2})([a-z]{3})([0-9]{4})")) {
                  dateFormat = "ddMMMyyyy";
              } else if (tempDate.matches("([a-z]{3})([0-31]{2})([0-9]{4})")) {
                  dateFormat = "MMMddyyyy";
              } else if (tempDate.matches("([0-9]{4})([a-z]{3})([0-31]{2})")) {
                  dateFormat = "yyyyMMMdd";
              } else if (tempDate.matches("([0-9]{4})([0-31]{2})([a-z]{3})")) {
                  dateFormat = "yyyyddMMM";
              } else {
                  return "Pattern Not Added";
      //add your required regex
              }
              try {
                  String formattedDate = new SimpleDateFormat(requiredFormat, Locale.ENGLISH).format(new SimpleDateFormat(dateFormat).parse(tempDate));
      
                  return formattedDate;
              } catch (Exception e) {
                  //
                  return "";
              }
      
          }
      
      public boolean isThisDateValid(String dateToValidate, String dateFromat){
      
          if(dateToValidate == null){
              return false;
          }
      
          SimpleDateFormat sdf = new SimpleDateFormat(dateFromat);
          sdf.setLenient(false);
      
          try {
      
              //if not valid, it will throw ParseException
              Date date = sdf.parse(dateToValidate);
              System.out.println(date);
      
          } catch (ParseException e) {
      
              e.printStackTrace();
              return false;
          }
      
          return true;
      }
      
      import java.time.format.DateTimeFormatter;
      import java.time.format.DateTimeParseException;
      public boolean isValidFormat(String dateString, String pattern) {
          boolean valid = true;
          DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
          try {
              formatter.parse(dateString);
          } catch (DateTimeParseException e) {
              valid = false;
          }
          return valid;
      }
      
          public boolean isValidFormat(String source, String pattern) {
          SimpleDateFormat sd = new SimpleDateFormat(pattern);
          sd.setLenient(false);
          try {
              Date date = sd.parse(source);
              return date != null && sd.format(date).equals(source);
          } catch (Exception e) {
              return false;
          }
      }