24

我有一个字符串,它代表法语语言环境中的日期:09-oct-08:

我需要解析那个字符串,所以我想出了这个 SimpleDateFormat :

String format2 = "dd-MMM-yy";

但是我对月份部分有疑问,这似乎与结束点有关:

df2.format(new Date());

给我 :

 28-oct.-09

现在让我理解 SimpleDateFormat ("09-oct-08") 的最佳方法是什么?

完整代码:

String format2 = "dd-MMM-yy"; 
DateFormat df2 = new SimpleDateFormat(format2,Locale.FRENCH); 
date = df2.parse("09-oct-08"); 

这给了我: java.text.ParseException: Unparseable date: "09-oct-08"

如果我然后尝试登录:

df2.format(new Date()); 

我得到:09 年 10 月 28 日

4

6 回答 6

7

这似乎有效:

    DateFormatSymbols dfsFr = new DateFormatSymbols(Locale.FRENCH);
    String[] oldMonths = dfsFr.getShortMonths();
    String[] newMonths = new String[oldMonths.length];
    for (int i = 0, len = oldMonths.length; i < len; ++ i) {
        String oldMonth = oldMonths[i];

        if (oldMonth.endsWith(".")) {
            newMonths[i] = oldMonth.substring(0, oldMonths[i].length() - 1);
        } else {
            newMonths[i] = oldMonth;
        }
    }
    dfsFr.setShortMonths(newMonths);
    DateFormat dfFr = new SimpleDateFormat(
        "dd-MMM-yy", dfsFr);

    // English date parser for creating some test data.
    DateFormat dfEn = new SimpleDateFormat(
        "dd-MMM-yy", Locale.ENGLISH);
    System.out.println(dfFr.format(dfEn.parse("10-Oct-09")));
    System.out.println(dfFr.format(dfEn.parse("10-May-09")));
    System.out.println(dfFr.format(dfEn.parse("10-Feb-09")));

编辑:看起来圣影子打败了我。

于 2009-10-28T09:01:58.607 回答
5

java.time

让我们看看java.time框架是否可以提供帮助。

关于 java.time

Java 8 和更高版本中内置的java.time框架取代了麻烦的旧 java.util.Date/.Calendar 类。新课程的灵感来自非常成功的Joda-Time框架,旨在作为其继任者,在概念上相似但重新架构。由JSR 310定义。由ThreeTen-Extra项目扩展。请参阅教程

LocalDate

与旧类不同,java.time 提供LocalDate类来表示仅日期值,没有时间或时区。

法语缩写

看看 java.time 中的格式化程序对en Français中缩写月份名称的期望。

我们可以循环Month枚举以获取月份列表。这个枚举提供了getDisplayName生成月份本地化名称的方法。此代码演示该方法产生与 java.time 格式化程序相同的输出。

DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "dd-MMM-yyyy" ).withLocale ( Locale.FRENCH );
for ( Month month : Month.values () ) {
    LocalDate localDate = LocalDate.of ( 2015 , month.getValue () , 1 );
    String output = formatter.format ( localDate );
    String displayName = month.getDisplayName ( TextStyle.SHORT , Locale.FRENCH );
    System.out.println ( "output: " + output + " | displayName: " + displayName );// System.out.println ( "input: " + input + " → " + localDate + " → " + output );
}
output: 01-janv.-2015 | displayName: janv.
output: 01-févr.-2015 | displayName: févr.
output: 01-mars-2015 | displayName: mars
output: 01-avr.-2015 | displayName: avr.
output: 01-mai-2015 | displayName: mai
output: 01-juin-2015 | displayName: juin
output: 01-juil.-2015 | displayName: juil.
output: 01-août-2015 | displayName: août
output: 01-sept.-2015 | displayName: sept.
output: 01-oct.-2015 | displayName: oct.
output: 01-nov.-2015 | displayName: nov.
output: 01-déc.-2015 | displayName: déc.

我们发现混合了 3 个和 4 个字母的拼写。较长的名称缩写为四个字符加上一个句点 ( FULL STOP )。四个月的名称足够短,可以不用缩写:mars, mai, juin, août.

因此,正如其他答案中所讨论的,没有简单的解决方案。

修复数据源

我的第一个建议是修复您的数据源。该来源显然没有遵循适当的法语缩写规则。耶鲁同意 Java 8 对法语的理解。顺便说一句,如果修复您的数据源,我强烈建议使用四位数的年份作为两个,这会导致混乱和模棱两可。

修复输入

当然,来源可能不受您的控制/影响。在这种情况下,与其他答案一样,您可能需要进行蛮力替换,而不是尝试任何聪明。另一方面,如果您输入的唯一问题只是缺少句点(FULL STOP),那么您可以使用Month枚举进行软编码,而不是对不正确的值进行硬编码。

我会做一个初步的解析尝试。DateTimeParseException在尝试修复之前捕获 , 。如果抛出异常,则修复输入。

要修复输入,请通过循环可能的枚举实例集来尝试一年中的每个月。对于每个月,获取其缩写名称。从该缩写中删除句点(FULL STOP),以匹配我们怀疑是我们不正确的传入值。测试以查看这是否确实与输入匹配。如果没有,请转到下个月。

当我们确实得到匹配时,将输入修复为正确缩写为区域设置规则(在我们的例子中是法语规则)。然后解析固定输入。这将是我们的第二次解析尝试,因为我们在顶部进行了初步尝试。如果第二次尝试失败,则说明出现了非常错误的情况,如FIXME:这里所见。但通常第二次解析尝试会成功,我们可以跳出枚举的for循环。Month

最后,您可以通过测试结果是否仍然是最初设置的虚假标志值来验证成功(LocalDate.MIN)。

String input = "09-oct-08"; // Last two digits are Year.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "dd-MMM-yy" ).withLocale ( Locale.FRENCH );
LocalDate localDate = LocalDate.MIN; // Some folks prefer a bogus default value as a success/failure flag rather than using a NULL.
try {
    localDate = LocalDate.parse ( input , formatter );
} catch ( DateTimeParseException e ) {
    // Look for any month name abbreviation improperly missing the period (FULL STOP).
    for ( Month month : Month.values () ) {
        String abbreviation = month.getDisplayName ( TextStyle.SHORT , Locale.FRENCH );
        String abbreviationWithoutFullStop = abbreviation.replace ( "." , "" ); // Get short abbreviation, but drop any period (FULL STOP).
        String proper = "-" + abbreviation + "-";
        String improper = "-" + abbreviationWithoutFullStop + "-";
        if ( input.contains ( improper ) ) {
            String inputFixed = input.replace ( improper , proper );
            try {
                localDate = LocalDate.parse ( inputFixed , formatter );
            } catch ( DateTimeParseException e2 ) {
                // FIXME: Handle this error. We expected this second parse attempt to succeed.
            }
            break; // Bail-out of the loop as we got a hit, matching input with a particular improper value.
        }
    }
}
Boolean success =  ! ( localDate.equals ( LocalDate.MIN ) );
String formatted = formatter.format ( localDate );;
String outputImproper = formatted.replace ( "." , "" );  // Drop any period (FULL STOP).

转储到控制台。

System.out.println ( "success: " + success + ". input: " + input + " → localDate: " + localDate + " → formatted: " + formatted + " → outputImproper: " + outputImproper );

成功:是的。输入:09-oct-08 → localDate:2008-10-09 → 格式化:09-oct.-08 → outputImproper:09-oct-08

于 2015-11-12T22:30:36.883 回答
3

您可以简单地删除“。”:

df2.format(new Date()).replaceAll("\\.", ""));

编辑,关于柠檬的答案:

使用 Locale French 时,格式似乎有问题。因此,我建议您.像我解释的那样简单地使用删除。

确实,下面的代码:

    String format2 = "dd-MMM-yy";
    Date date = Calendar.getInstance().getTime();
    SimpleDateFormat sdf = new SimpleDateFormat(format2, Locale.FRENCH);
    System.out.println(sdf.format(date));
    sdf = new SimpleDateFormat(format2, Locale.ENGLISH);
    System.out.println(sdf.format(date));

显示以下输出:

28-oct.-09
28-Oct-09

再次编辑

好的,我现在有你的问题。

我真的不知道如何在不先处理 String 的情况下解决这个问题。想法是将原始字符串中的月份替换为综合月份:

        String[] givenMonths = { "jan", "fév", "mars", "avr.", "mai", "juin", "juil", "août", "sept", "oct", "nov", "déc" };
        String[] realMonths = { "janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc." };
        String original = "09-oct-08";
        for (int i = 0; i < givenMonths.length; i++) {
            original = original.replaceAll(givenMonths[i], realMonths[i]);
        }
        String format2 = "dd-MMM-yy";
        DateFormat df2 = new SimpleDateFormat(format2, Locale.FRENCH);
        Date date = df2.parse(original);
        System.out.println("--> " + date);

SimpleDateFormat我同意,这很糟糕,但是如果您使用 to和Dateclasses ,我看不到任何其他解决方案。

另一种解决方案是使用真实的日期和时间库而不是原始的 JDK 库,例如Joda Time

于 2009-10-28T07:47:30.010 回答
2
String format2 = "dd-MMM-yy";
Date date = Calendar.getInstance().getTime();
SimpleDateFormat sdf = new SimpleDateFormat(format2);
System.out.println(sdf.format(date));

输出28-Oct-09

先生,我没有看到任何点。您是否尝试过重新检查您的打印件?也许你不小心.在你的旁边放了一个MMM


你得到的java.text.ParseException: Unparseable date: "09-oct-08"因为与使用默认语言环境(我认为是美国)"09-oct-08"的格式不匹配,Locale.FRENCH或者.在你的旁边添加一个oct

于 2009-10-28T07:47:32.723 回答
2

好的,然后尝试«蛮力»:)

DateFormatSymbols dfs = new DateFormatSymbols(Locale.FRENCH);
String[] months = new String[13]
<fill with correct month names or just replace these month, that are not fully correct>
dfs.setMonths(months);
SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yy", dfs);
Date nweDate = sdf.parse("09-fév-08");
于 2009-10-28T08:16:40.637 回答
1

我遇到了同样的问题(法语和多余的点),我相信解决这个问题的正确方法是像这样全局覆盖法语语言环境:

import moment from 'moment';
moment.locale('fr', { monthsShort: 'janv_févr_mars_avr_mai_juin_juil_août_sept_oct_nov_déc'.split('_') });

The original monthsShort french object has the dots like janv._févr._mars_avr._..., so we're just removing them.

Here's a link to docs where you can check what can be overwritten.

Note that we don't need to pass a complete locale object if we just want to overwrite ie.: monthsShort.

于 2016-02-22T22:31:16.987 回答