Java 使用SimpleDataFormat(字符串,区域设置)分析法语区域设置时出错

Java 使用SimpleDataFormat(字符串,区域设置)分析法语区域设置时出错,java,simpledateformat,french,Java,Simpledateformat,French,我在java方面有一段类似这样的代码: private static DateFormat getHourFormatter(){ //DateFormatSymbols dateFormatSymbols = new DateFormatSymbols(_locale); Locale locale = Locale.FRENCH; //locale : "fr" DateFormat hourFormatter = new SimpleDat

我在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; 
         }
    }
如果我将区域设置值更改为US,则可以在英语区域设置中正常工作

但对于法语语言环境来说,这是一个错误


java.text.ParseException:可升级日期“01:01 Matin”


我添加了调试信息作为注释行,以便更好地理解而不必重写现有的代码库,您仍然可以为此目的引入
java.time
,即现代java日期和时间API。它确实为法语提供了一个解决方案:

    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));
混合
java.time
和过时的类

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

我强烈建议您尽可能地使用
java.time
。和他一起工作总的来说要好得多。一旦你开始使用它,我相信你不会想回去


对于纯
SimpleDataFormat
解决方案,请参见。

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

    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));
混合
java.time
和过时的类

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

我强烈建议您尽可能地使用
java.time
。和他一起工作总的来说要好得多。一旦你开始使用它,我相信你不会想回去


有关纯
SimpleDateFormat
解决方案,请参阅。

如果且仅当您只有两个可能的值(此处为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,以防止任何区域效应。如果需要,您可以偏离它(但需要小心)


正如一些评论中提到的,我仍然不认为使用AM/PM字段真的适用于英语以外的其他语言。例如,法国人至少知道两个或两个以上的值,如“nuit”(=夜间)或“après-midi”(=下午)。但是,对于旧的API或新的
java.time
-包(需要像ICU4J或Time4J这样的外部LIB),这种方法是不可能的。

如果并且仅当您只有两个可能的值(这里是AM/PM),那么您可以使用
SimpleDataFormat
这样做:

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,以防止任何区域效应。如果需要,您可以偏离它(但需要小心)


正如一些评论中提到的,我仍然不认为使用AM/PM字段真的适用于英语以外的其他语言。例如,法国人至少知道两个或两个以上的值,如“nuit”(=夜间)或“après-midi”(=下午)。但是,对于旧的API或新的
java.time
-包(需要像ICU4J或Time4J这样的外部LIB),这种方式是不可能的。

谢谢大家的回答

正如我前面提到的,我负担不起更改代码库。

因此,我所做的是:

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;
    }
}
\u locale我从Action类传递给from类的值。如果它不是英语,它将进入其中一个If块,如果是英语,默认情况下它将进入else块。基于本地值,它从属性文件中获取AM/PM值并相应地进行转换

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


你们可以称之为丑陋的黑客,但猜猜看,这解决了我的目的。

谢谢你们所有这些答案

正如我前面提到的,我负担不起更改代码库。

因此,我所做的是:

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;
    }
}
\u locale我从Action类传递给from类的值。如果它不是英语,它将进入其中一个If块,如果是英语,默认情况下它将进入else块。基于本地值,它从属性文件中获取AM/PM值并相应地进行转换

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


你们可以称之为丑陋的黑客,但猜猜看,它解决了我的问题。

你也可以发布异常吗?java.text.ParseException:Upparsable date“01:01 Matin”--这是异常String Hourd的值是什么?为什么你仍然使用早已过时的
SimpleDateFormat
类,和他一起工作要好得多。查找类
DateTimeFormatter
LocalTime
。您的问题与我在中描述的非常相似。您也可以发布异常吗?java.text.ParseException:upparsable date“01:01 Matin”--这是例外情况String HourdSplayer的值是多少?为什么您仍然使用长期过时的
SimpleDateFormat
类,和他一起工作要好得多。查找类
DateTimeFormatter
LocalTime
。您的问题与我在中描述的问题非常相似。可以使用
SimpleDateFormat
实现您的建议。只需创建一个自定义版本的
DateFormatSymbols
,并使用它。新的API肯定比旧的API更方便,尽管仍然不是最优的(为了比较:我的lib Time4J甚至可以代替长原语)。尽管我使用的是DateTimeFormatter,但仍然需要从旧方法返回DateFormat。是否可以将DateTimeFormatter转换为DateFormat?但我也担心仅仅使用AM/PM字段是不够的