JFormattedTextField使用双位数年份DateFormatter的世纪偏移问题咨询
最优方案:保留Locale格式的同时替换双位年份为四位
该方案完全符合用户自定义Locale的需求,不需要硬编码全局日期格式,也不受百年区间限制:
- 从用户指定Locale的
DateFormat实例中获取原生格式模板,将模板中的双位年份标识yy替换为四位yyyy - 新格式完全保留对应Locale的日期顺序、分隔符、时间格式规则,仅升级年份为四位,从根源上避免双位年份的跨世纪解析问题
代码示例:
dateField.setFormatterFactory(new JFormattedTextField.AbstractFormatterFactory() { @Override public JFormattedTextField.AbstractFormatter getFormatter(JFormattedTextField tf) { // 此处替换为用户实际选择的Locale即可 Locale userLocale = Locale.GERMANY; DateFormat originalFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, userLocale); // 绝大多数场景下Locale返回的DateFormat都是SimpleDateFormat实现 if (originalFormat instanceof SimpleDateFormat sdf) { String rawPattern = sdf.toPattern(); // 仅替换年份位,其他格式规则完全不变 String adaptedPattern = rawPattern.replace("yy", "yyyy"); SimpleDateFormat adaptedFormat = new SimpleDateFormat(adaptedPattern, userLocale); // 可选:关闭宽松解析,避免无效日期(如2月30日)被自动修正 adaptedFormat.setLenient(false); return new DateFormatter(adaptedFormat); } // 极端兼容场景下 fallback 到原生格式 return new DateFormatter(originalFormat); } });
备选方案:自定义解析逻辑,保留双位年份显示
如果业务要求必须沿用Locale原生的双位年份显示规则,可以自定义DateFormatter重写解析逻辑,完全自主控制年份补全规则,不受默认100年区间限制:
public class FullRangeDateFormatter extends DateFormatter { // 可根据业务需求自定义双位年份覆盖范围,示例为以当前年份为基准,前后覆盖1000年 private static final int YEAR_RANGE_OFFSET = 500; public FullRangeDateFormatter(DateFormat format) { super(format); } @Override public Object stringToValue(String text) throws ParseException { DateFormat format = getFormat(); Date rawParsed = format.parse(text); // 提取用户输入的年份 Pattern yearPattern = Pattern.compile("\\b(\\d{2,4})\\b"); Matcher matcher = yearPattern.matcher(text); if (!matcher.find()) { return rawParsed; } String inputYearStr = matcher.group(1); Calendar cal = Calendar.getInstance(); cal.setTime(rawParsed); // 四位年份直接使用用户输入值,不做修正 if (inputYearStr.length() == 4) { cal.set(Calendar.YEAR, Integer.parseInt(inputYearStr)); return cal.getTime(); } // 双位年份按自定义规则补全世纪 int inputTwoDigitYear = Integer.parseInt(inputYearStr); int currentYear = cal.get(Calendar.YEAR); int currentTwoDigitYear = currentYear % 100; int centuryBase = currentYear / 100 * 100; if (inputTwoDigitYear > currentTwoDigitYear + YEAR_RANGE_OFFSET % 100) { centuryBase -= 100 * (YEAR_RANGE_OFFSET / 100 + 1); } else if (inputTwoDigitYear < currentTwoDigitYear - YEAR_RANGE_OFFSET % 100) { centuryBase += 100 * (YEAR_RANGE_OFFSET / 100 + 1); } cal.set(Calendar.YEAR, centuryBase + inputTwoDigitYear); return cal.getTime(); } }
使用时直接用自定义的FullRangeDateFormatter替换原有DateFormatter即可。
内容的提问来源于stack exchange,提问作者Ture Pålsson
相关产品推荐
相关产品推荐

