【问题标题】:Parsing error for French locale with SimpleDateFormat(string,locale)使用 SimpleDateFormat(string,locale) 解析法语语言环境的错误
【发布时间】:2017-11-24 06:59:39
【问题描述】:

我的 java 端有一段这样的代码:

private static DateFormat getHourFormatter(){

        //DateFormatSymbols dateFormatSymbols = new DateFormatSymbols(_locale);
        Locale locale = Locale.FRENCH; //locale : "fr"
        DateFormat hourFormatter = new SimpleDateFormat( "hh:mm a",locale); //hourFormatter: simpleDateFormat@103068 locale: "fr"
        hourFormatter.setTimeZone( TimeZone.getTimeZone("GMT") );
        return hourFormatter; //hourFormatter: SimpleDateFormat@103068
    }



protected static boolean isHoursTimeStringValid( String hourDisplay ) {
         try {
            getHourFormatter().parse( hourDisplay ); //hourDisplay: "01:01 Matin"
            return true;
         } catch (ParseException e) { //e: "java.text.ParseException: Upparseable date "01:01 Matin"
            return false; 
         }
    }

如果我将语言环境值更改为美国,它适用于英语语言环境。

但对于法语语言环境,它会引发解析错误。

java.text.ParseException:可解析日期“01:01 Matin”

我已将调试信息添加为注释行以便更好地理解

【问题讨论】:

  • 你也可以发布异常吗?
  • java.text.ParseException: Upparseable date "01:01 Matin" -- 这是例外
  • String hourDisplay的值是多少
  • 您为什么仍在使用早已过时的SimpleDateFormat 类? java.time, the modern Java date and time API,使用起来更好。查找课程 DateTimeFormatterLocalTime
  • 你的问题和我在my post here中描述的很相似。

标签: java simpledateformat french


【解决方案1】:

在不重写现有代码库的情况下,您仍然可以为此特定目的引入现代 Java 日期和时间 API java.time。它确实为法语提供了解决方案:

    Map<Long, String> amPmText = new HashMap<>(4);
    amPmText.put(0L, "Matin");
    amPmText.put(1L, "Soir");
    DateTimeFormatter timeFormatter = new DateTimeFormatterBuilder().appendPattern("hh:mm ")
            .appendText(ChronoField.AMPM_OF_DAY, amPmText)
            .toFormatter(Locale.FRENCH);

    System.out.println(LocalTime.parse("01:01 Matin", timeFormatter));
    System.out.println(LocalTime.parse("10:59 Soir", timeFormatter));

打印出来

01:01
22:59

混合java.time 和过时的类

到目前为止,我们的代码库(旧的)是新旧日期和时间 API 使用的有趣组合。坦率地说,我们很少重写任何旧代码和工作代码,但我们总是将现代 API 用于新代码。

我强烈建议您尽可能使用java.time。使用它通常要好得多。一旦你开始使用它,我相信你不会想回去。

对于纯SimpleDateFormat 解决方案,请参阅Meno Hochschild’s comment below

【讨论】:

  • 可以通过SimpleDateFormat实现您的建议。只需使用它创建DateFormatSymbolsfeed the formatter 的自定义版本。新的 API 肯定比旧的 API 更方便,尽管仍然不是最佳的(为了比较:我的 lib Time4J 甚至可以 work with enums 而不是 long-primitives)。
  • 即使我使用的是 DateTimeFormatter,但仍然从我的旧方法中我需要返回 DateFormat。是否可以将 DateTimeFormatter 转换为 DateFormat ??
  • 但我也担心仅使用 AM/PM 字段是不够的。还有“nuit”或“après-midi”需要两个以上的值。使用模式符号“B”而不是“a”显然更合适(但仅ICU4J和Time4J支持。这里Java-8是有限的。
  • @SubhenduGN 恐怕这是不可能的。我没有深入研究,但我认为DateTimeFormatter 可以做SimpleDateFormat 做不到的事情,所以开发一个通用的转换可能并非易事。
  • @SubhenduGN DateTimeFormatter 只能转换为java.text.Format(没有属性字符支持),请参阅API
【解决方案2】:

当且仅当您只有两个可能的值(此处为 AM/PM)时,您可以使用 SimpleDateFormat 这样做:

DateFormatSymbols dfs = DateFormatSymbols.getInstance(Locale.FRENCH);
dfs.setAmPmStrings(new String[] { "Matin", "Soir" });
SimpleDateFormat input = new SimpleDateFormat("hh:mm a", Locale.FRENCH);
input.setTimeZone(java.util.TimeZone.getTimeZone("GMT"));
input.setDateFormatSymbols(dfs);

Date parsed = input.parse("01:01 Matin");

// control of parsing
SimpleDateFormat output = new SimpleDateFormat("HH:mm");
output.setTimeZone(java.util.TimeZone.getTimeZone("GMT"));
System.out.println(output.format(parsed)); // 01:01 (24-hour-clock)

我在这里将时区设置为 GMT 以防止任何区域影响。如果需要,您可以偏离它(但需要小心)。

正如一些 cmets 中所提到的,我仍然认为使用 AM/PM 字段并不适合英语以外的其他语言。例如,法语至少知道两个或多个值,例如“nuit”(=night)或“après-midi”(=afternoon)。但这种方式对于旧 API 或新 java.time-package 是不可能的(需要像 ICU4J 或 Time4J 这样的外部库)。

【讨论】:

  • 这可能是我第一次使用SimpleDateFormat 对答案进行投票,但这个很好,并且很好地符合 OP 的要求。
  • @OleV.V.谢谢,我总是尝试认真对待 OP 的要求,即使这意味着使用旧的 API。但是在您的答案中显示更现代的替代方案也是可以的。
【解决方案3】:

谢谢大家的回答。

正如我之前提到的,我无法更改代码库。

所以,我所做的是:

public void setBeginAMPM( String ampm ) {
    if(ampm.equals(new I18NStringFactory().getString("Calendar", _locale , "default.time.am" ))) {
        _beginAMPM = "AM";
    }
    else if(ampm.equals(new I18NStringFactory().getString("Calendar", _locale , "default.time.pm" ))) {
        _beginAMPM = "PM";
    }
    else{
        _beginAMPM = ampm;
    }
}


public void setEndAMPM( String ampm ) {
    if(ampm.equals(new I18NStringFactory().getString("Calendar", _locale , "default.time.am" ))) {
        _endAMPM = "AM";
    }
    else if(ampm.equals(new I18NStringFactory().getString("Calendar", _locale , "default.time.pm" ))) {
        _endAMPM = "PM";
    }
    else{
        _endAMPM = ampm;
    }
}

_locale 值我从 Action 类传递到 From 类。如果它不是英语,它将进入 if 块之一,或者如果是英语,它将默认进入 else 块。根据本地值,它从属性文件中获取 AM/PM 值并进行相应的转换。

我只是将 AM/PM 值从其他特定于语言环境的语言修改为英语,因为 SimpleDateFormat() 仅支持英语。

你们可以称之为丑陋的黑客,但你猜怎么着,它正在解决我的目的。

【讨论】:

    猜你喜欢
    • 2016-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-10
    相关资源
    最近更新 更多