【问题标题】:Parsing 2-digit years: Setting the pivot date with an unknown date pattern解析 2 位数年份:使用未知日期模式设置基准日期
【发布时间】:2015-09-25 12:51:06
【问题描述】:

用户将以不同的模式向我的应用程序输入日期。对于 2 位数年份,他还必须确定基准日期。


示例:
模式 = yy-MM-dd
枢轴日期 = 70(我以编程方式添加当前千年和上个世纪以获得更多动态 => 1970

69-04-22 变为 2069-04-22
70-04-22 变为 1970-04 -22


this answer 中所述,当日期模式(此处为ddMMyy)已知时,很容易构建DateTimeFormatter
但是由于用户输入了模式,我不确定如何正确构建DateTimeFormatterBuilder。我不能硬编码。

我是否必须自己解析模式并以正确的顺序调用appendPattern()appendValueReduced()?还是有内置的解决方案?

【问题讨论】:

  • 不确定您的问题出在哪里。假设您没有基准日期问题,并且用户刚刚输入了模式。你知道那时你会做什么吗?还是您的问题是您不信任用户输入正确的模式?如果他的模式是有效的,添加appendValueReduced 有什么问题?
  • 假设输入的模式是有效的。问题是java.time 在将 2 位数年份转换为 4 位数时采用当前世纪(2000 年)。但我想让用户决定选择上世纪(1900)或当前世纪(2000)的哪一年。
  • 是的,但我不明白给定答案有什么问题。 new DateTimeFormatterBuilder().appendPattern(userPattern).appendValueReduced(...) 怎么了?
  • 这行不通,因为对于我的模式,它必须是new DateTimeFormatterBuilder().appendValueReduced(...).appendPattern(userPattern)。所以它们必须以另一个顺序调用,userPattern 必须被编辑为 -MM-dd

标签: java date java-time


【解决方案1】:

这里是 Java-8 解决方案(看起来有点像 hack):

String pattern = "MM/dd/yy 'US'"; // user-input
String text = "10/04/69 US"; // user-input
Locale locale = Locale.US; // user-input, too?

int yy = pattern.indexOf("yy");
DateTimeFormatter dtf;

if (
    (yy != -1) // explanation: condition ensures exactly two letters y
    && ((yy + 2 >= pattern.length()) || pattern.charAt(yy + 2) != 'y')
) {
    DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
    String part1 = pattern.substring(0, yy);
    if (!part1.isEmpty()) {
        builder.appendPattern(part1);
    }
    builder.appendValueReduced(ChronoField.YEAR, 2, 2, 1970);
    String part2 = pattern.substring(yy + 2);
    if (!part2.isEmpty()) {
        builder.appendPattern(part2);
    }
    dtf = builder.toFormatter(locale);
} else {
    dtf = DateTimeFormatter.ofPattern(pattern, locale);
}

LocalDate ld = LocalDate.parse(text, dtf);
System.out.println("user-date: " + ld); // 2069-10-04

只有一个小小的警告:如果任何用户疯狂地想在模式中分别定义两次“yy”,那么建议的解决方案将失败。正确的解决方案需要对模式字符进行某种迭代,但我认为这太过分了,所以我把它放在这里。

只是为了比较,使用我的外部库 Time4J 可以实现以下简短的解决方案,因为它的解析引擎也具有设置任何合适的格式属性的概念:

LocalDate ld = 
  ChronoFormatter.ofDatePattern(pattern, PatternType.CLDR, locale)
  .with(Attributes.PIVOT_YEAR, 2070).parse(text).toTemporalAccessor();

【讨论】:

  • 因为您已经编写了 Time4J,我想您应该知道可能的内置解决方案。因此,您的答案似乎是(目前)唯一且最好的。谢谢!
  • @halloei 谢谢,如果有人敢像我一样写一个新的时间库——目标是改进或引入很多功能——那么他必须非常了解和研究现有的优缺点标准(如新的 java.time-lib)。如果您查看 DateTimeFormatter 中的 with() 方法和 builder 类中的 non-append() 方法(如 parseCaseInsensitive()),那么您可以很容易地看到没有针对您的问题的内置解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-26
相关资源
最近更新 更多