我是Java的新手。 我有时间从网页上获取,这是"hh:mm"格式(不是24小时)。 这对我来说是一个字符串。 然后我想将这个字符串与今天的日期结合起来,以便创建一个我可以使用的Java Date。
在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);
有没有更好的方法来实现我想要的?
使用SimpleDateFormat类来处理java中的每种格式。
@AMallal:理想情况下,不要 - 使用java.time代替。
@Jon双向:我的不好
Is there a better way to achieve what I want?
绝对 - 实际上在.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 Time也提供同样的东西,但略有不同。如果您需要详细信息,请告诉我。)
我强烈建议不要使用java.util.Date,它只是代表一个时刻,并且有一个糟糕的API。
这里的关键点是:
使用明确指定的格式解析文本
将文本解析为表示其传达的信息的类型:一天中的某个时间
将该值与另一个值相结合,该值也应该仔细指定(就时钟和时区而言)
所有这些都将导致清晰,可靠,可测试的代码。 (并且现有的.NET代码不符合任何这些要点,IMO。)
等等,Jon,这并没有给我平等的.NET代码。 我想拥有今天的日期,并将时间推荐给我想要的字符串值。 所以对于今天"16/08/2017 15:45"作为日期对象更好,所以我可以对它进行操作。 当转储到控制台时,这只会给出"17:45"。
@MoonKnight:Date对象是即时的。 你想要什么时区? Date几乎总是使用错误的类型。 我会稍微编辑一下我的答案。
@MoonKnight:扩大了很多。
尼斯。 我只想要一个快照,但我同意你对Date的所有观点。 非常感谢您抽出宝贵的时间来确保详细介绍,我们非常感谢。 我把你所说的一切都带到了船上。 再次感谢。
要解析时间,你可以按@Jon Skeet的答案解释:
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)以来的毫秒数。这是一个瞬间(一个特定的时间点)。有关详细信息,请查看此文章。
因此,相同的Date对象可以表示不同的日期或时间,具体取决于您所处的位置:现在想想,此时此世界上的每个人都处于同一时刻(自1970-01-01T00:00Z以来的相同毫秒数) ),但世界各地的当地日期和时间不同。
LocalDateTime表示"本地"的概念:它是日期(日,月和年)和时间(小时,分钟,秒和纳秒),但与特定时区无关。
相同的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时区名称(始终采用Region/City格式,如America/Sao_Paulo或Europe/Berlin)。
避免使用3个字母的缩写(如CST或PST),因为它们不明确且不标准。
您可以通过调用ZoneId.getAvailableZoneIds()获取可用时区列表(并选择最适合您系统的时区)。
此外还有夏令时的极端情况(当LocalDateTime可以存在两次或由于重叠和间隙而不能存在时)。在这种情况下,使用ZonedDateTime的Jon的解决方案避免了这个问题)。
非常好的回答,非常感谢您的时间。 我从中学到了很多东西。 祝一切顺利。
@MoonKnight欢迎您,很乐意提供帮助! 我可以推荐本教程,它是java.time API的一个很好的起点。 干杯!