【问题标题】:Java DateFormat/SimpleDateFormat with Locale (show just day in month and month)Java DateFormat/SimpleDateFormat with Locale(仅显示月份和月份中的一天)
【发布时间】:2017-06-09 19:50:15
【问题描述】:

我有一个多元文化的应用程序,该项目使用 Java 7。我需要显示日期,但只显示月份和月份中的日期。例如,在Locale.UK 中,今天的日期看起来像:24/01,但在 Locale.US 中像:1/24。如何在 Java 7 中实现这一点?我尝试使用DateFormat.getDateInstance(dateFormat, locale),但在这种情况下,我可以只使用预定义的日期格式,例如DateFormat.SHORTDateFormat.DEFAULT 等。没有预定义的格式只有月份和月份中的日期。接下来我尝试将 SimpleDateFormat 与语言环境一起使用,但这并不像我想的那样工作,它只是根据语言环境翻译一些文本。这是我的示例代码:

DateFormat dfuk = DateFormat.getDateInstance(DateFormat.SHORT, Locale.UK);
DateFormat dfus = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
System.out.println(dfuk.format(new Date()));  // 24/01/17
System.out.println(dfus.format(new Date()));  // 1/24/17
SimpleDateFormat sdfuk = new SimpleDateFormat("dd/MM", Locale.UK);
SimpleDateFormat sdfus = new SimpleDateFormat("dd/MM", Locale.US);
System.out.println(sdfuk.format(new Date()));  // 24/01
System.out.println(sdfus.format(new Date()));  // 24/01

我希望最后一行打印 01/24(或 1/24)。如何做到这一点?

【问题讨论】:

  • 关于sdfus 的倒数第三行说的是SimpleDateFormat sdfus = new SimpleDateFormat("dd/MM", Locale.US); -- 你的意思是说MM/dd 吗?
  • 是的,可以,但如果你说我必须编写额外的条件来验证实际的语言环境,并选择适当的格式(dd/MM 或 MM/dd)我希望找到构建的 Java 库-解决我的问题。
  • getDateInstance() 方法接受style 的参数。最短的样式似乎是DateFormat.SHORT。您可以争辩说,也许他们应该提供一个更短的(DateFormat.SHORTER 也许?)c.f. docs.oracle.com/javase/6/docs/api/java/text/…
  • 我的库 Time4J 提供了 net.time4j.xml.AnnualDate 类,支持大约 80 种语言环境中的四种格式样式。版本行 v3.x 可以在 Java-6 或 7 上运行,较新的版本 v4.x 可以在 Java-8 上运行。如果您仍然错过任何语言环境,那么只需在 Time4J 的跟踪器上打开一个问题。当前的 i18n-data 基于 unicode-cldr-version v30。

标签: java date format locale


【解决方案1】:

将你的倒数第三行更改为

SimpleDateFormat sdfus = new SimpleDateFormat("MM/dd", Locale.US);

克服标准 Java 提供的缺点:

getDateInstance() 方法接受style 的参数。最短的样式似乎是DateFormat.SHORT。你可以争辩说,也许他们应该提供一个更短的(DateFormat.SHORTER 也许?)c.f.

http://docs.oracle.com/javase/6/docs/api/java/text/DateFormat.html#getDateInstance(int)

在此之前,您可以为较短的样式构建一个模式枚举。下面是一个例子:

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

enum PatternShorter { // or PatternMonthDayOnly
    MM_SLASH_DD     ("MM/dd")
    , DD_SLASH_MM   ("dd/MM")
    ;
    private String pattern;

    public String getPattern() {
        return pattern;
    }

    private PatternShorter(String pattern) {
        this.pattern = pattern;
    }

    public static PatternShorter getDefault() { return DD_SLASH_MM; }
}

public class DateFormatEx {
    private static Map<Locale, PatternShorter> patternShorter = new HashMap<>();

    static {
        patternShorter.put(Locale.UK, PatternShorter.DD_SLASH_MM);
        patternShorter.put(Locale.UK, PatternShorter.MM_SLASH_DD);
        // any locale not listed here will get the default pattern
    }

    private static String getPattern (Locale locale) {      
        if (patternShorter.get(locale)!=null) {
            return patternShorter.get(locale).getPattern();
        } else {
            return PatternShorter.getDefault().getPattern();
        }
    }

    public static void main(String[] args) {
        List<Locale> listOfLocale = Arrays.asList(Locale.UK, Locale.US, Locale.FRENCH);
        for (Locale locale : listOfLocale) {
            SimpleDateFormat fmt 
            = new SimpleDateFormat(getPattern(locale), locale);
            System.out.format("for locale %s the shorter date/month display is: %s%n"
                    , locale.toString()
                    , fmt.format(new Date()));  
        }
    }

}

输出将是:

for locale en_GB the shorter date/month display is: 01/24
for locale en_US the shorter date/month display is: 24/01
for locale fr the shorter date/month display is: 24/01

【讨论】:

  • 这没关系,但我们有大约 80 个语言环境,以防你说我必须编写附加条件来验证实际语言环境,并选择适当的格式(dd/MM 或 MM/dd)我希望为我的问题找到 Java 库的内置解决方案。
  • @bladekp -- 我已经更新了答案并添加了关于如何克服标准 Java 提供的缺点的解释
【解决方案2】:

您的代码抛出了相同的格式,因为两个 DateFormat 都是用相同的模式构造的,这是不正确的..

SimpleDateFormat sdfuk = new SimpleDateFormat("dd/MM", Locale.UK);
SimpleDateFormat sdfus = new SimpleDateFormat("dd/MM", Locale.US);

如果您有一个要转换为日期的字符串,则需要本地...

示例

DateFormat sdfuk = new SimpleDateFormat("dd/MM");
DateFormat sdfus = new SimpleDateFormat("MM/d");
System.out.println(sdfuk.format(new Date())); // 24/01
System.out.println(sdfus.format(new Date())); // 01/24

【讨论】:

  • 这没关系,但我们有大约 80 个语言环境,以防你说我必须编写额外的条件来验证实际语言环境,并选择适当的格式(dd/MM 或 MM/dd)我希望为我的问题找到 Java 库的内置解决方案。
【解决方案3】:

tl;博士

MonthDay.from( 
    LocalDate.now( ZoneId.of( "America/Montreal" ) ) 
).format( DateTimeFormatter.ofPattern( "MM/dd" ) )

01/24

MonthDay

有一个类:MonthDay

MonthDay 表示月份和月份的组合。

MonthDay md = MonthDay.of( Month.JANUARY , 24 );

避免使用旧的日期时间类。

避免麻烦的旧日期时间类,例如 SimpleDateFormat,现在是遗留的,被 java.time 类取代。

MonthDay 类是 Java 8 及更高版本中内置的 java.time 框架的一部分。大部分 java.time 都向后移植到 Java 6 和 Java 7(见下文)。

ISO 8601

md.toString(): --01-24

toString 方法生成标准ISO 8601 格式的字符串。 MonthDay 类也可以解析这样的字符串。

当前日期

您需要当前日期的月-日。对于当前日期,我们将使用 LocalDate 类。 LocalDate 类表示没有时间和时区的仅日期值。

时区

时区对于确定日期至关重要。对于任何给定的时刻,日期在全球范围内因区域而异。例如,Paris France 中午夜后几分钟是新的一天,而 Montréal Québec 中仍然是“昨天”。

continent/region 的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用 3-4 个字母的缩写,例如 ESTIST,因为它们不是真正的时区,没有标准化,甚至不是唯一的 (!)。

请清楚Locale 与时区无关Locale 仅适用于生成字符串时的文本格式,但与时区分开且不同。

ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( z );

现在提取一个MonthDay 对象。

MonthDay md = MonthDay.from( today );

tod​​ay.toString(): 2017-01-25

md.toString(): --01-25

其他格式

您可以生成其他格式的字符串。

java.time 类可以通过Locale 自动本地化一些日期时间值。不幸的是,这不适用于MonthDay。对于MonthDay,当您需要标准ISO 8601 格式以外的格式时,您必须在DateTimeFormatter 对象中明确指定所需格式。顺便说一句,我鼓励您尽可能坚持使用标准格式,尤其是在交换数据时。您甚至可以考虑培训您的用户接受这种格式。标准格式是明确的,而您的英美格式(dd/MM、MM/dd)可能完全不明确,例如 01/02 是 1 月 2 日或 2 月 1 日。

Locale 确定 (a) 用于翻译日期名称、月份名称等的人类语言,以及 (b) 决定缩写、大写、标点符号等问题的文化规范。通常,我建议始终为您的DateTimeFormatter 指定Locale,而不是隐式依赖JVM 当前默认的Locale。但我看不出Locale 会影响这种特定格式的输出。所以我在这个例子中省略了Locale

DateTimeFormatter fUS = DateTimeFormatter.ofPattern( "MM/dd" );
DateTimeFormatter fUK = DateTimeFormatter.ofPattern( "dd/MM" );

String output = md.format( fUS );

实时代码

请参阅此示例code run live at IdeOne.com


关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

从哪里获得 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

  • 我认为这没有抓住问题的重点。 OP 想要一种方法来检索区域设置的“最短”日期格式 - 即 Locale.US 的 MM/d,Locale.UK 的 d/MM,以及适用于任何其他区域设置的任何格式,例如 dd.MM为德国。我不认为这是可能的。但你回答的是完全不同的问题。
【解决方案4】:

我最终修改了DateFormat.getDateInstance(DateFormat.SHORT) 提供的本地化格式字符串,从格式中删除了年份部分:

DateFormat shortDateFormat = DateFormat.getDateInstance(DateFormat.SHORT);
String shortPattern = ((SimpleDateFormat) shortDateFormat).toLocalizedPattern();
String shorterPattern = shortPattern.replaceAll("[/\\- ]*[yY]+[^a-zA-Z]*", "");
DateFormat shorterDateFormat = new SimpleDateFormat(shorterPattern);

我浏览了系统提供的所有 734 种语言环境,据我所知,生成的日期模式对所有语言环境都很好。

将原始短模式与修改后的短模式进行比较的一些示例:

         short      shorter
en_US    M/d/yy     M/d
en_GB    dd/MM/y    dd/MM
de_DE    dd.MM.yy   dd.MM.
fr_FR    dd/MM/y    dd/MM
nl_NL    dd-MM-y    dd-MM
ja_JP    y/MM/dd    MM/dd

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-17
    • 1970-01-01
    • 2018-06-28
    • 2011-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多