我正在使用ThreeTen-Backport(特别是ThreeTenABP)来显示项目中的时间戳。我希望显示的时间戳以本地化格式显示(基于系统的Locale
);这很容易使用DateTimeFormatter.ofLocalizedDateTime()
方法之一:
DateTimeFormatter formatter = DateTimeFormatter
.ofLocalizedDateTime(FormatStyle.LONG)
.withLocale(Locale.getDefault())
.withZone(ZoneId.systemDefault());
String timestamp = formatter.format(Instant.now());
问题在于我对格式化程序的输出没有多少控制权,只有四种FormatStyle
类型SHORT
,MEDIUM
,LONG
,{{1 }})。我很好奇是否有办法对输出进行更精细的控制,而不会丢失本地化格式。
使用上一代码,FULL
语言区域的结果timestamp
将为:
"en_US"
虽然"January 23, 2017 1:28:37 PM EST"
语言环境的结果是:
"ja_JP"
如您所见,每个语言环境都使用特定模式,并使用12或24小时格式的默认值。我想维护本地化模式,但更改时区是否显示,或者是否使用12或24小时格式。
例如;如果我可以将两个语言环境设置为使用12小时格式,并删除时区;结果如下:
"2017年1月23日 13:28:37 GMT-5:00"
答案 0 :(得分:2)
FormatStyle
(AFAIK)的问题在于他们使用预定义的模式。虽然,可以让他们操纵/改变模式以满足您的需求。
我没有使用特定于Android的环境,因此我不确定此代码对您的效果如何。我正在使用 Java JDK 1.7.0_79 和 ThreeTen Backport 1.3.4 。我还使用 America / New_York 时区进行测试 - 我猜这与 EST 相对应。
我注意到您的环境存在一些差异:
FormatStyle.LONG
用于日语区域设置会为我2017/01/23 13:28:37 EST
FormatStyle.FULL
来获取2017年1月23日 13時28分37秒 EST
但我认为这并没有使我的测试无效。
首先,我使用java.text.DateFormat
类将本地化模式作为String
。然后我根据所需的配置对String
进行了一些替换:
HH
,hh
,H
或h
并更改为使用12或24小时格式(我替换时保留相同数量的字母)z
(或Z
):删除或添加时区h
字面(如HH'h'
变为13h
),所以我在更换创建格式化程序的代码是:
// creates a formatter with the specified style, locale and zone
// there are options to use 12 or 24 hour format and include or not a timezone
public DateTimeFormatter getFormatter(FormatStyle style, Locale locale, ZoneId zone,
boolean use24HourFormat, boolean useTimezone) {
// get the format correspondent to the style and locale
DateFormat dateFormat = DateFormat.getDateTimeInstance(style.ordinal(), style.ordinal(), locale);
// *** JDK 1.7.0_79 returns SimpleDateFormat ***
// If Android returns another type, check if it's possible to get the pattern from this type
if (dateFormat instanceof SimpleDateFormat) {
// get the pattern String for the locale
String pattern = ((SimpleDateFormat) dateFormat).toPattern();
if (use24HourFormat) {
if (pattern.contains("hh")) { // check the "hh" hour format
// hh not surrounded by ' (to avoid literals)
pattern = pattern.replaceAll("((?<!\')hh)|(hh(?!\'))", "HH");
} else { // check the "h" hour format
// h not surrounded by ' (to avoid literals)
pattern = pattern.replaceAll("((?<!\')h)|(h(?!\'))", "H");
}
} else {
if (pattern.contains("HH")) { // check the "HH" hour format
// HH not surrounded by ' (to avoid literals)
pattern = pattern.replaceAll("((?<!\')HH)|(HH(?!\'))", "hh");
} else { // check the "H" hour format
// H not surrounded by ' (to avoid literals)
pattern = pattern.replaceAll("((?<!\')H)|(H(?!\'))", "h");
}
}
if (useTimezone) {
// checking if already contains a timezone (the naive way)
if (!pattern.contains("z") && !pattern.contains("Z")) {
// I'm adding z in the end, but choose whatever pattern you want for the timezone (it can be Z, zzz, and so on)
pattern += " z";
}
} else {
// 1 or more (z or Z) not surrounded by ' (to avoid literals)
pattern = pattern.replaceAll("((?<!\')[zZ]+)|([zZ]+(?!\'))", "");
}
// create the formatter for the locale and zone, with the customized pattern
return DateTimeFormatter.ofPattern(pattern, locale).withZone(zone);
}
// can't get pattern string, return the default formatter for the specified style/locale/zone
return DateTimeFormatter.ofLocalizedDateTime(style).withLocale(locale).withZone(zone);
}
一些使用示例(我的默认Locale
是 pt_BR - 巴西葡萄牙语):
ZoneId zone = ZoneId.of("America/New_York");
Instant instant = ZonedDateTime.of(2017, 1, 23, 13, 28, 37, 0, zone).toInstant();
FormatStyle style = FormatStyle.FULL;
// US locale, 24-hour format, with timezone
DateTimeFormatter formatter = getFormatter(style, Locale.US, zone, true, true);
System.out.println(formatter.format(instant)); // Monday, January 23, 2017 13:28:37 PM EST
// US locale, 24-hour format, without timezone
formatter = getFormatter(style, Locale.US, zone, true, false);
System.out.println(formatter.format(instant)); // Monday, January 23, 2017 13:28:37 PM
// US locale, 12-hour format, with timezone
formatter = getFormatter(style, Locale.US, zone, false, true);
System.out.println(formatter.format(instant)); // Monday, January 23, 2017 1:28:37 PM EST
// US locale, 12-hour format, without timezone
formatter = getFormatter(style, Locale.US, zone, false, false);
System.out.println(formatter.format(instant)); // Monday, January 23, 2017 1:28:37 PM
// japanese locale, 24-hour format, with timezone
formatter = getFormatter(style, Locale.JAPAN, zone, true, true);
System.out.println(formatter.format(instant)); // 2017年1月23日 13時28分37秒 EST
// japanese locale, 24-hour format, without timezone
formatter = getFormatter(style, Locale.JAPAN, zone, true, false);
System.out.println(formatter.format(instant)); // 2017年1月23日 13時28分37秒
// japanese locale, 12-hour format, with timezone
formatter = getFormatter(style, Locale.JAPAN, zone, false, true);
System.out.println(formatter.format(instant)); // 2017年1月23日 1時28分37秒 EST
// japanese locale, 12-hour format, without timezone
formatter = getFormatter(style, Locale.JAPAN, zone, false, false);
System.out.println(formatter.format(instant)); // 2017年1月23日 1時28分37秒
// pt_BR locale, 24-hour format, with timezone
formatter = getFormatter(style, Locale.getDefault(), zone, true, true);
System.out.println(formatter.format(instant)); // Segunda-feira, 23 de Janeiro de 2017 13h28min37s EST
// pt_BR locale, 24-hour format, without timezone
formatter = getFormatter(style, Locale.getDefault(), zone, true, false);
System.out.println(formatter.format(instant)); // Segunda-feira, 23 de Janeiro de 2017 13h28min37s
// pt_BR locale, 12-hour format, with timezone
formatter = getFormatter(style, Locale.getDefault(), zone, false, true);
System.out.println(formatter.format(instant)); // Segunda-feira, 23 de Janeiro de 2017 01h28min37s EST
// pt_BR locale, 12-hour format, without timezone
formatter = getFormatter(style, Locale.getDefault(), zone, false, false);
System.out.println(formatter.format(instant)); // Segunda-feira, 23 de Janeiro de 2017 01h28min37s
备注:强>
DateFormat.getDateTimeInstance
会返回SimpleDateFormat
,但我不确定它在Android中的工作方式是否相同。您可以检查它是否返回不同类型,以及是否可以从此课程中获取模式String
(如果不是,那么我不知道另一种做法它)。String
,你可以用它做任何事情-05:00
),您可以使用xxx
模式(而不是z
)。如果您希望偏移量为 GMT (例如GMT-05:00
),则可以使用ZZZZ
模式。z
作为时区(他们可以使用Z
或x
),因此您可能会更改代码以查找其他模式。在我的测试中,我没有找到与z
不同的任何内容,但无论如何,我建议对此进行双重检查以确保。pattern.contains("z")
检查模式是否已经有时区 - 这是一种非常天真/愚蠢的方式,因为它不会处理z
文字(内部引号)。也许这可以更改为使用正则表达式(尽管我没有找到具有z
字面值的模式的区域设置。答案 1 :(得分:0)
您可以使用Locale
获取DateTimeFormatterBuilder.getLocalizedDateTimePattern
的格式字符串。获得该字符串后,您可以使用DateTimeFormatter.ofPattern
方法对其进行操作。
String fr = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.LONG, FormatStyle.FULL, IsoChronology.INSTANCE, Locale.FRANCE);
//d MMMM yyyy HH' h 'mm z
String ge = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.LONG, FormatStyle.FULL, IsoChronology.INSTANCE, Locale.GERMAN);
//d. MMMM yyyy HH:mm' Uhr 'z
String ca = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.LONG, FormatStyle.FULL, IsoChronology.INSTANCE, Locale.CANADA);
//MMMM d, yyyy h:mm:ss 'o''clock' a z
String en = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.LONG, FormatStyle.FULL, IsoChronology.INSTANCE, Locale.ENGLISH);
//MMMM d, yyyy h:mm:ss a z
在DateTimeFormatter
中,您可以使用符号字符和方法指定日期的各个单位。每单位使用的符号字符数也会影响显示的内容:
M
会以数字显示月份。 MM
将为您提供两位数的月份,即使月份小于10。MMM
应该为您提供月份名称。请参阅“格式化和分析的模式”部分
DateTimeFormatter
文档。
下面的模式为您提供四位数年份,两位数月份和两位数日期。
LocalDate localDate = LocalDate.now(); //For reference
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
String formattedString = localDate.format(formatter);