2017-06-28 237 views
1

我有以下代碼以字符串yyyy-MM-dd HH:mm:ss(UTC時區)的形式取日期並將其轉換爲EEEE d(st, nd, rd, th) MMMM yyyy HH:mm(設備的默認時區)。解析和格式日期

但是,我所做的方式的問題是代碼看起來凌亂和低效。有沒有一種方法可以實現我想要的功能,而無需多次格式化和解析同一日期以提高效率?還是有其他改進?

最好的Android支持API級別14


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; 
    } 
} 
+7

我投票結束這個問題作爲題外話,因爲它屬於[codereview.se]。 – shmosel

+0

@shmosel謝謝你指出。我會在那裏發佈 – Dan

+0

你必須剖析你的代碼,找出導致性能差的原因。至於「雜亂」的部分 - 好吧,java.util.date API被廣泛認爲是「雜亂」,沒有太多可以做的事情。重構代碼以找到更清潔的方法。在開始重構之前,確保你有一套防彈套裝的單元測試。 – Egor

回答

2

隨着SimpleDateFormat有可能沒有太大的改善。由於您的輸出格式有EEEE(星期幾)和MMMM(月份名稱),您必須解析日期以瞭解這些日期的值。如果不使用日期格式化程序,則必須執行大量if以獲取每個值的相應名稱。


在Android中,作爲替代SimpleDateFormat,您可以使用ThreeTen Backport,對Java 8的新的日期/時間類大反向移植,與ThreeTenABP在一起(更多關於如何使用它here)。

所有類都低於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()))); 

輸出將是:

週三2017年6月28日19:44

的時間爲19:44,因爲我的默認時區爲America/Sao_Paulo(在UTC-03:00)。

不知道它是否足夠混亂,但至少海事組織,它比SimpleDateFormat更清晰。只創建了2個格式化器(一個用於輸出,另一個用於輸出)。當然有textLookup映射,但它只有31個條目,格式化程序也可以重用。

SimpleDateFormat is not thread safe,而the new API is