2017-08-16 92 views
4

我是新來的Java。我有一段時間是從網頁獲得的,這是「hh:mm」格式(不是24小時)。這是我的一個字符串。然後我想把這個字符串與今天的日期結合起來,以便使我可以使用的Java Date操縱和Java

在C#:

string s = "5:45 PM"; 
DateTime d; 
DateTime.TryParse(s, out d); 

在Java中我曾嘗試:

String s = "5:45 PM"; 
Date d = new Date(); // Which instantiates with the current date/time. 

String[] arr = s.split(" "); 
boolean isPm = arr[1].compareToIgnoreCase("PM") == 0; 

arr = arr[0].split(":"); 
int hours = Integer.parseInt(arr[0]); 
d.setHours(isPm ? hours + 12 : hours); 
d.setMinutes(Integer.parseInt(arr[1])); 
d.setSeconds(0); 

有沒有更好的方式來實現我想要什麼?

+0

使用SimpleDateForma classt處理java中的每種格式。 –

+3

@AMALlal:理想情況下,不要使用'java.time'。 –

+0

@Jon:我的壞 –

回答

13

有沒有更好的方式來實現我想要什麼?

絕對 - 事實上,在.NET和Java中都是如此。在.NET我最好(在偏置方式)建議使用Noda Time這樣你就可以代表短短一天的時間爲LocalTime,精確分析你所期望的模式。

在Java 8,你可以做同樣的事情java.time.LocalTime

import java.time.*; 
import java.time.format.*; 

public class Test { 
    public static void main(String[] args) { 
     String text = "5:45 PM"; 
     DateTimeFormatter format = DateTimeFormatter.ofPattern("h:mm a"); 
     LocalTime time = LocalTime.parse(text, format); 
     System.out.println(time); 
    } 
} 

一旦你解析你有到合適的類型的文本,你可以與其他類型的結合起來。例如,爲了獲得ZonedDateTime系統時區,用今天的日期和指定的一天中的時間,你可以使用:

ZonedDateTime zoned = ZonedDateTime.now().with(time); 

使用系統默認的時區和時鐘,很難測試 - 我建議通過Clock進行測試。

(同一類的事情是在Noda時間可用,但略有不同。讓我知道如果你需要的細節。)

我會強烈使用java.util.Date,這just represents an instant in time建議並有一個可怕的API 。

這裏的關鍵點是:

  • 分析文本,以良好的指定格式
  • 分析文本,爲表示它傳達的信息的類型:一天的時間
  • 再加上與應仔細規定(時鐘和時區而言)的另一個值值

所有這些都將導致清晰,可靠,可測試的代碼。 (。而現有的.NET代碼不符合任何這些要點中,IMO)

+0

等等,喬恩,這不會給我等同於我的.NET代碼。我想擁有今天的日期,將時間推薦​​給我想要的字符串值。所以今天「16/08/2017 15:45」更適合作爲日期對象,所以我可以對它執行操作。這只是在轉儲到控制檯時給出「17:45」。 – MoonKnight

+1

@MoonKnight:一個'Date'對象是一個*即時* *。你想要什麼時區?日期幾乎總是使用錯誤的類型。我會更多地編輯我的答案。 –

+0

@MoonKnight:擴展了很多。 –

2

要解析的時候,你可以做在@Jon Skeet's answer解釋說:

String input = "5:45 PM"; 
DateTimeFormatter parser = DateTimeFormatter.ofPattern("h:mm a", Locale.ENGLISH); 
LocalTime time = LocalTime.parse(input, parser); 

請注意,我還使用了java.util.Locale,因爲如果不指定它,它將使用系統的默認區域設置 - 某些區域設置可以爲AM/PM字段使用不同的符號。使用顯式區域設置避免了這種情況(即使在運行時也可以更改默認區域設置,所以最好使用明確區域設置)。

要與今天的日期相結合,你需要一個java.time.LocalDate(獲取日期),並與LocalTime結合起來,得到一個LocalDateTime

// combine with today's date 
LocalDateTime combined = LocalDate.now().atTime(time); 

然後你可以使用其他格式格式化LocalDateTime

DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"); 
System.out.println(combined.format(fmt)); 

的輸出是:

16/08/2017 17:45


如果你想在LocalDateTime轉換爲java.util.Date,你必須採取的一些細節問題。

A java.util.Date表示自1970-01-01T00:00Z(又名Unix Epoch)以來的毫秒數。這是一個瞬間(特定時間點)。檢查this article瞭解更多信息。

所以,同樣Date對象可以表示不同的日期或時間,這取決於你在哪裏:覺得,現在,在這一刻,每個人都在世界上處於同一時刻(因爲1970-01-01T00:00Z相同的毫秒數),但當地的日期和時間在世界各地都不一樣。

A LocalDateTime表示「本地」這個概念:它是日期(日,月和年)和時間(小時,分鐘,秒和納秒),但與特定時區沒有任何關係。

對象可以代表不同時間點的不同時刻。所以,要將其轉換爲Date,您必須定義您想要的時區。

一種選擇是使用系統的默認時區:

// convert to system's default timezone 
ZonedDateTime atDefaultTimezone = combined.atZone(ZoneId.systemDefault()); 
// convert to java.util.Date 
Date date = Date.from(atDefaultTimezone.toInstant()); 

但是默認可以從系統/環境而有所不同,也可以改變,甚至在運行時。爲了不依賴於,並已超過它更多的控制,你可以使用一個明確的區域:

// convert to a specific timezone 
ZonedDateTime zdt = combined.atZone(ZoneId.of("Europe/London")); 
// convert to java.util.Date 
Date date = Date.from(zdt.toInstant()); 

請注意,我用Europe/London。該API使用IANA timezones names(始終格式爲Region/City,如America/Sao_PauloEurope/Berlin)。 避免使用3字母縮寫(如CST或),因爲它們是ambiguous and not standard

通過調用ZoneId.getAvailableZoneIds(),您可以獲得可用時區列表(並選擇最適合您系統的時區)。

還有夏時制的角落案例(當LocalDateTime可能存在兩次或由於overlaps and gaps而不能存在時)。在這種情況下,Jon's solution使用ZonedDateTime可避免此問題)。

+1

夢幻般的答案,非常感謝您的時間。我從中學到了很多東西。祝一切順利。 – MoonKnight

+0

@MoonKnight不客氣,很高興幫助!我可以推薦這個[教程](https://docs.oracle.com/javase/tutorial/datetime),它是'java.time' API的一個很好的起點。乾杯! – 2017-08-16 13:55:00