解析和格式化日期
Parse and format date
我有以下代码以字符串形式获取日期 yyyy-MM-dd HH:mm:ss
(UTC 时区)并将其转换为 EEEE d(st, nd, rd, th) MMMM yyyy HH:mm
(设备的默认时区)。
但是,我这样做的问题是代码看起来凌乱且效率低下。有没有一种方法可以实现我想要的,而无需多次格式化和解析相同的日期以提高效率?或任何其他改进?
最好支持AndroidAPI14级
String inputExample = "2017-06-28 22:44:55";
//Converts UTC to Device Default (Local)
private String convertUTC(String dateStr) {
try {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
df.setTimeZone(TimeZone.getTimeZone("UTC"));
Date temp = df.parse(dateStr);
df.setTimeZone(TimeZone.getDefault());
String local = df.format(temp);
Date localDate = df.parse(dateStr);
SimpleDateFormat outputDF1 = new SimpleDateFormat("EEEE ");
SimpleDateFormat outputDF2 = new SimpleDateFormat(" MMMM yyyy HH:mm");
return outputDF1.format(temp) + prefix(local) + outputDF2.format(temp);
} catch(java.text.ParseException pE) {
Log.e("", "Parse Exception", pE);
return null;
}
}
private String prefix(String dateStr) {
try {
SimpleDateFormat outputDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date temp = outputDF.parse(dateStr);
SimpleDateFormat df = new SimpleDateFormat("d");
int d = Integer.parseInt(df.format(temp));
if(1 <= d && d <= 31) {
if(11 <= d && d <= 13)
return d + "th";
switch (d % 10) {
case 1: return d + "st";
case 2: return d + "nd";
case 3: return d + "rd";
default: return d + "th";
}
}
Log.e("", "Null Date");
return null;
} catch(java.text.ParseException pE) {
Log.e("", "Parse Exception", pE);
return null;
}
}
SimpleDateFormat
可能没有太多需要改进的地方。由于您的输出格式有 EEEE
(星期几)和 MMMM
(月份名称),您必须解析日期才能知道这些日期的值。如果不使用日期格式化程序,您将不得不做很多 if
来获取每个值的相应名称。
在 Android 中,作为 SimpleDateFormat
的替代,您可以使用 ThreeTen Backport, a great backport for Java 8's new date/time classes, together with the ThreeTenABP (more on how to use it ).
所有类都在org.threeten.bp
包下。在下面的代码中,我也使用了 Locale.ENGLISH
,否则它将使用系统的默认值(因为我的不是英语,我假设你的是):
String inputExample = "2017-06-28 22:44:55";
// parser for input
DateTimeFormatter parser = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH);
// parse the date and set to UTC
ZonedDateTime z = LocalDateTime.parse(inputExample, parser).atZone(ZoneOffset.UTC);
// map of custom values - map each numeric value to its string with suffix (st, nd...)
Map<Long, String> textLookup = new HashMap<Long, String>();
for (int i = 1; i <= 31; i++) {
String suffix = "";
switch (i) {
case 1:
case 21:
case 31:
suffix = "st";
break;
case 2:
case 22:
suffix = "nd";
break;
case 3:
case 23:
suffix = "rd";
break;
default:
suffix = "th";
}
textLookup.put((long) i, i + suffix);
}
// output formatter
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// day of week
.appendPattern("EEEE ")
// append day with suffix (use map of custom values)
.appendText(ChronoField.DAY_OF_MONTH, textLookup)
// rest of pattern
.appendPattern(" MMMM yyyy HH:mm")
// create formatter with English locale
.toFormatter(Locale.ENGLISH);
// print date, convert it to device default timezone
System.out.println(fmt.format(z.withZoneSameInstant(ZoneId.systemDefault())));
输出将是:
Wednesday 28th June 2017 19:44
时间设置为 19:44
因为我的默认时区是 America/Sao_Paulo
(在 UTC-03:00)。
不确定它是否对您来说不够混乱,但至少在我看来它比 SimpleDateFormat
清晰得多。只创建了 2 个格式化程序(一个用于输出,另一个用于输出)。当然还有 textLookup
映射,但它只有 31 个条目,格式化程序也可以重复使用。
和SimpleDateFormat
is not thread safe, while the new API is.
我有以下代码以字符串形式获取日期 yyyy-MM-dd HH:mm:ss
(UTC 时区)并将其转换为 EEEE d(st, nd, rd, th) MMMM yyyy HH:mm
(设备的默认时区)。
但是,我这样做的问题是代码看起来凌乱且效率低下。有没有一种方法可以实现我想要的,而无需多次格式化和解析相同的日期以提高效率?或任何其他改进?
最好支持AndroidAPI14级
String inputExample = "2017-06-28 22:44:55";
//Converts UTC to Device Default (Local)
private String convertUTC(String dateStr) {
try {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
df.setTimeZone(TimeZone.getTimeZone("UTC"));
Date temp = df.parse(dateStr);
df.setTimeZone(TimeZone.getDefault());
String local = df.format(temp);
Date localDate = df.parse(dateStr);
SimpleDateFormat outputDF1 = new SimpleDateFormat("EEEE ");
SimpleDateFormat outputDF2 = new SimpleDateFormat(" MMMM yyyy HH:mm");
return outputDF1.format(temp) + prefix(local) + outputDF2.format(temp);
} catch(java.text.ParseException pE) {
Log.e("", "Parse Exception", pE);
return null;
}
}
private String prefix(String dateStr) {
try {
SimpleDateFormat outputDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date temp = outputDF.parse(dateStr);
SimpleDateFormat df = new SimpleDateFormat("d");
int d = Integer.parseInt(df.format(temp));
if(1 <= d && d <= 31) {
if(11 <= d && d <= 13)
return d + "th";
switch (d % 10) {
case 1: return d + "st";
case 2: return d + "nd";
case 3: return d + "rd";
default: return d + "th";
}
}
Log.e("", "Null Date");
return null;
} catch(java.text.ParseException pE) {
Log.e("", "Parse Exception", pE);
return null;
}
}
SimpleDateFormat
可能没有太多需要改进的地方。由于您的输出格式有 EEEE
(星期几)和 MMMM
(月份名称),您必须解析日期才能知道这些日期的值。如果不使用日期格式化程序,您将不得不做很多 if
来获取每个值的相应名称。
在 Android 中,作为 SimpleDateFormat
的替代,您可以使用 ThreeTen Backport, a great backport for Java 8's new date/time classes, together with the ThreeTenABP (more on how to use it
所有类都在org.threeten.bp
包下。在下面的代码中,我也使用了 Locale.ENGLISH
,否则它将使用系统的默认值(因为我的不是英语,我假设你的是):
String inputExample = "2017-06-28 22:44:55";
// parser for input
DateTimeFormatter parser = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH);
// parse the date and set to UTC
ZonedDateTime z = LocalDateTime.parse(inputExample, parser).atZone(ZoneOffset.UTC);
// map of custom values - map each numeric value to its string with suffix (st, nd...)
Map<Long, String> textLookup = new HashMap<Long, String>();
for (int i = 1; i <= 31; i++) {
String suffix = "";
switch (i) {
case 1:
case 21:
case 31:
suffix = "st";
break;
case 2:
case 22:
suffix = "nd";
break;
case 3:
case 23:
suffix = "rd";
break;
default:
suffix = "th";
}
textLookup.put((long) i, i + suffix);
}
// output formatter
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// day of week
.appendPattern("EEEE ")
// append day with suffix (use map of custom values)
.appendText(ChronoField.DAY_OF_MONTH, textLookup)
// rest of pattern
.appendPattern(" MMMM yyyy HH:mm")
// create formatter with English locale
.toFormatter(Locale.ENGLISH);
// print date, convert it to device default timezone
System.out.println(fmt.format(z.withZoneSameInstant(ZoneId.systemDefault())));
输出将是:
Wednesday 28th June 2017 19:44
时间设置为 19:44
因为我的默认时区是 America/Sao_Paulo
(在 UTC-03:00)。
不确定它是否对您来说不够混乱,但至少在我看来它比 SimpleDateFormat
清晰得多。只创建了 2 个格式化程序(一个用于输出,另一个用于输出)。当然还有 textLookup
映射,但它只有 31 个条目,格式化程序也可以重复使用。
和SimpleDateFormat
is not thread safe, while the new API is.