【问题标题】:Binding Date on multiple patterns多种模式的绑定日期
【发布时间】:2014-03-10 16:08:06
【问题描述】:

我曾经支持 Java DateJoda Localdate 模式绑定使用 Spring DateTimeFormat pattern 这样的属性

@DateTimeFormat(pattern = "dd.MM.yyyy")
private LocalDate creationDate;

但我需要支持两种日期模式,例如:

如果用户输入了31/12/199931/12/99,那么它们都可以绑定到相同的值31/12/1999。是否可以为@DateTimeFormat 定义两种模式?

编辑:

我尝试将模式更改为

@DateTimeFormat(pattern = "dd.MM.yy")
private LocalDate creationDate;

我发现它可以处理这两种情况(例如,当用户输入31/12/199931/12/99 时)两者都绑定到31/12/1999。有cmets吗?

【问题讨论】:

    标签: spring date spring-mvc jodatime date-format


    【解决方案1】:

    在我看来,绑定到 LocalDate 类型属性的 spring 注释 @DateTimeFormat 将导致 Spring 选择 JodaTime-Formatter,而不是标准格式化程序,否则 Spring 将无法成功将任何输入字符串解析为LocalDate 类型的对象。这条语句是对Spring source code的分析做的(见方法getParser(DateTimeFormat annotation, Class<?> fieldType)的实现)。

    如果是这样,那么问题仍然是为什么您的变通方法和解决方案“dd.MM.yy” 能够解析两位数年份以及正常的四位数年份。答案可以在 Joda 资源和文档中找到。

    org.joda.time.format.DateTimeFormat

    源代码摘录(在私有方法 parsePatternTo(DateTimeFormatterBuilder builder, String pattern) 中完成的 JodaTime 模式分析):

        case 'y': // year (number)
        case 'Y': // year of era (number)
            if (tokenLen == 2) {                    
              boolean lenientParse = true;
              // Peek ahead to next token.
              if (i + 1 < length) {
                indexRef[0]++;
                if (isNumericToken(parseToken(pattern, indexRef))) {
                  // If next token is a number, cannot support
                  // lenient parse, because it will consume digits that it should not.                            
                  lenientParse = false;                        
                }
                indexRef[0]--;
              }
              // Use pivots which are compatible with SimpleDateFormat.                                       
              switch (c) {
                case 'x':
                  builder.appendTwoDigitWeekyear(new DateTime().getWeekyear() - 30, lenientParse);
                  break;
                case 'y':
                case 'Y':
                default:
                    builder.appendTwoDigitYear(new DateTime().getYear() - 30, lenientParse);
                    break;                    
              }
    

    所以我们认识到 JodaTime 将模式表达式“yy”转换为对构建器方法 appendTwoDigitYear() 的调用,其中参数 lenientParse 设置为 true。有趣的是,所选的枢轴年份偏离了通常的 Joda 设置(+/-50 年),即(-80/+20 年)。

    Javadoc of mentioned builder-method中是这样说的:

    "lenientParse - 为真时,如果位数不是两个,则视为绝对年份"

    这充分解释了为什么 "dd.mm.yy" 可以将两位数年份解析为四位数年份。

    【讨论】:

      【解决方案2】:

      DateFormatter 的 Spring 当前实现只允许设置一种模式。

      根据您的编辑发现并根据Java Documentation for SimpleDateFormat,使用“yy”会导致 SimpleDateFormat 解释相对于某个世纪的缩写年份。它通过将日期调整为创建 SimpleDateFormat 实例之前的 80 年和之后的 20 年来实现这一点。

      如果你想定义一个 DateFormatter 接受一个列表或一组模式,而不是在调用它的 parse 方法时调用 return getDateFormat(locale).parse(text);,你必须实现一个 CustomDateFormatter 来实现接口 Formatter&lt;T&gt;,如在Spring 3 Field Formatting.

      您将拥有一个字符串列表,而不是模式私有变量的单个字符串,并且您的解析方法将类似于 StackOverflow Question 中的示例。

      按照Spring 3 Field Formatting 中的说明实现AnnotationFormatterFactory,然后您可以将您的模式列表指定为注释。

      【讨论】:

      • 我认为问题是关于 JodaTime,而不仅仅是 java.util.Date
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-04
      • 1970-01-01
      • 2020-09-14
      • 2021-01-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多