Java 解析没有点的短月份的日期

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1635681/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 18:02:41  来源:igfitidea点击:

Parsing a date with short month without dot

javalocaledate-format

提问by Jalil

I have a String that represents a date in Frenchlocale : 09-oct-08 :

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

I need to parsethat String so I came up with this SimpleDateFormat :

我需要解析那个 String 所以我想出了这个 SimpleDateFormat :

String format2 = "dd-MMM-yy";

But I have a problem with the month part, that seems to be expected with a ending dot :

但是我对月份部分有一个问题,这似乎是一个结尾点:

df2.format(new Date());

gives me :

给我 :

 28-oct.-09

What is now the best way for me to make SimpleDateFormat understand ("09-oct-08") ?

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

Full Code :

完整代码:

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

This gives me : java.text.ParseException: Unparseable date: "09-oct-08"

这给了我:java.text.ParseException:无法解析的日期:“09-oct-08”

And if I then try to log :

如果我然后尝试登录:

df2.format(new Date()); 

I get : 28-oct.-09

我得到:28-oct.-09

采纳答案by Hyman Leow

This seems to work:

这似乎有效:

    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")));

Edit: Looks like St. Shadow beat me to it.

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

回答by Romain Linsolas

You can simply remove the ".":

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

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


Edit, regarding the lemonanswer:

编辑,关于柠檬答案:

It seems to be a problem with the formatting when using the Locale French. Thus, I suggest that you simply use the .removal as I explained.

使用语言环境法语时,格式似乎有问题。因此,我建议您.按照我的解释简单地使用删除。

Indeed, the following code:

确实,下面的代码:

    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));

displays the following output:

显示以下输出:

28-oct.-09
28-Oct-09


Edit again

再次编辑

Ok, I got your problem right now.

好的,我现在知道你的问题了。

I don't really know how you can solve this problem without processing your String first. The idea is to replace the month in the original String by a comprehensive month:

我真的不知道如何在不先处理 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);

I agree, this is awful, but I don't see any other solution if you use to SimpleDateFormatand Dateclasses.

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

Another solution is to use a realdate and time library instead of the original JDK ones, such as Joda Time.

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

回答by lemon

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

Outputs 28-Oct-09

输出 28-Oct-09

I don't see any dots sir. Have you tried re-checking your prints? Maybe you accidentally placed a .beside your MMM?

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



You're getting java.text.ParseException: Unparseable date: "09-oct-08"since "09-oct-08"does not match the formatting of Locale.FRENCHeither use the default locale(US I think) or add a .beside your oct

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

回答by St.Shadow

Ok, then try ?brute force? :)

好的,然后尝试?蛮力?:)

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");

回答by Basil Bourque

java.time

时间

Let's see if the java.timeframework can help.

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

About java.time

关于 java.time

The java.timeframework built into Java 8 and later supplants the troublesome old java.util.Date/.Calendar classes. The new classes are inspired by the highly successful Joda-Timeframework, intended as its successor, similar in concept but re-architected. Defined by JSR 310. Extended by the ThreeTen-Extraproject. See the Tutorial.

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

LocalDate

LocalDate

Unlike the old classes, java.time offers the LocalDateclass to represent a date-only value, with no time-of-day nor time zone.

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

French Abbreviations

法语缩写

Take a look at what the formatters in java.time expect for abbreviated month names in en Fran?ais.

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

We can loop the Monthenum to get a list of months. This enum offers the getDisplayNamemethod for generating a localized name of the month. This code demonstrates that the method produces the same output as the java.time formatter.

我们可以循环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.

We find a mix of 3 and 4 letter spellings. Longer names are abbreviated to four characters plus a period (FULL STOP). Four months have names short enough to be used without abbreviation: mars, mai, juin, ao?t.

我们发现了 3 个和 4 个字母拼写的混合。较长的名称缩写为四个字符加一个句点 ( FULL STOP)。四个月的名字足够短,没有缩写被使用:marsmaijuinao?t

So, as discussed in the other Answers, no simple solution.

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

Fix the Data Source

修复数据源

My first suggestion is to fix your data source. That source apparently fails to follow proper French rules for abbreviation. Yaleagrees with Java 8's understanding of French. By the way, if fixing your data source I strongly suggest using four-digit years as two lead to no end of confusion and ambiguity.

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

Fix the Input

修复输入

Of course the source may be out of your control/influence. In that case, as with the other Answers, you may need to do a brute-force replace rather that attempt any cleverness. On the other hand, if the only problem with your input is simply missing the period (FULL STOP), then you could soft-code using the Monthenum rather than hard-code the improper values.

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

I would make an initial parse attempt. Trap for the DateTimeParseException, before attempting a fix. If the exception is thrown, then fix the input.

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

To fix the input, try each month of the year by looping the possible set of enum instances. For each month, get its abbreviated name. Strip the period (FULL STOP) from that abbreviation, to match what we suspect is our improper incoming value. Test to see if that indeed is a match for the input. If not, go to next month.

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

When we do get a match, fix the input to be properly abbreviated for the Locale's rules (French rules in our case). Then parse the fixed input. This would be our second parse attempt, as we made an initial attempt up top. If this second attempt fails, something is very wrong as noted in the FIXME:seen here. But normally this second parse attempt will succeed, and we can bail out of the forloop of the Monthenum.

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

Finally, you could verify success by testing if the result is still the bogus flag value set initially (LocalDate.MIN).

最后,您可以通过测试结果是否仍然是最初设置的虚假标志值 ( 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).

Dump to console.

转储到控制台。

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

success: true. input: 09-oct-08 → localDate: 2008-10-09 → formatted: 09-oct.-08 → outputImproper: 09-oct-08

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

回答by rafaelbiten

I was having the same problem (french and the extra dots) and I believe the right way to solve this problem is by globally overwriting the french locale like so:

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

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 monthsShortfrench object has the dots like janv._févr._mars_avr._..., so we're just removing them.

原始的monthsShort法语对象有像 的点 janv._févr._mars_avr._...,所以我们只是将它们删除。

Here's a link to docswhere 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.

请注意,如果我们只想覆盖 ie.: ,则不需要传递完整的语言环境对象monthsShort