C#vs Java中的日期时间操作

C#vs Java中的日期时间操作,java,c#,datetime,date-parsing,Java,C#,Datetime,Date Parsing,我是Java新手。我有一个时间,我从一个网页,这是在“hh:mm”格式(不是24小时)。这对我来说就像一根绳子。然后,我想将这个字符串与todays date结合起来,以便生成一个我可以使用的Javadate 在C#中: 在Java中,我尝试过: String s = "5:45 PM"; Date d = new Date(); // Which instantiates with the current date/time. String[] arr = s.split(" "); boo

我是Java新手。我有一个时间,我从一个网页,这是在“hh:mm”格式(不是24小时)。这对我来说就像一根绳子。然后,我想将这个字符串与todays date结合起来,以便生成一个我可以使用的Java
date

在C#中:

在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);
有没有更好的方法来实现我的目标

有没有更好的方法来实现我的目标

绝对-事实上,在.NET和Java中都是如此。在.NET中,我(有偏见地)建议使用,这样您就可以将一天中的某个时间表示为
LocalTime
,精确解析您期望的模式

在Java8中,您可以对
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);
    }
}
// combine with today's date
LocalDateTime combined = LocalDate.now().atTime(time);
一旦将文本解析为适当的类型,就可以将其与其他类型组合。例如,要使用今天的日期和一天中的指定时间在系统时区中获取
ZoneDateTime
,可以使用:

ZonedDateTime zoned = ZonedDateTime.now().with(time);
默认情况下,这会使用系统时区和时钟,因此很难进行测试-我建议传入
时钟
,以提高可测试性

(野田佳彦也提供同样的服务,但略有不同。如果您需要详细信息,请告诉我。)

我强烈建议不要使用
java.util.Date
,因为它有一个糟糕的API

这里的要点是:

  • 使用指定的格式解析文本
  • 将文本解析为表示它所传递信息的类型:一天中的某个时间
  • 将该值与另一个也应仔细指定的值相结合(根据时钟和时区)

所有这些都将产生清晰、可靠、可测试的代码。(在我看来,现有的.NET代码不符合这些要点中的任何一点。)

要解析时间,您可以按照中的说明执行:

请注意,我还使用了
java.util.Locale
,因为如果不指定它,它将使用系统的默认区域设置,并且一些区域设置可以为AM/PM字段使用不同的符号。使用显式区域设置可以避免这种情况(并且默认区域设置也可以更改,即使在运行时也是如此,因此最好使用显式区域设置)

要与今天的日期组合,需要一个
java.time.LocalDate
(获取日期)并与
LocalTime
组合,以获取
LocalDateTime

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);
    }
}
// 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));
输出为:

2017年8月16日17:45


如果要将
LocalDateTime
转换为
java.util.Date
,必须注意一些细节

A
java.util.Date
表示自
1970-01-01T00:00Z
(又称Unix历元)以来的毫秒数。这是一个瞬间(一个特定的时间点)。查看更多信息

因此,同一个
Date
对象可以表示不同的日期或时间,具体取决于您所处的位置:现在,在这个时刻,世界上的每个人都在同一个瞬间(自
1970-01-01T00:00Z以来的毫秒数相同),但世界各地的本地日期和时间都不同

LocalDateTime
表示“本地”的概念:它是一个日期(天、月和年)和一个时间(小时、分钟、秒和纳秒),但与特定时区没有任何关系

同一个
LocalDateTime
对象可以表示不同时区的不同时间点。因此,要将其转换为日期,必须定义所需的时区

一个选项是使用系统的默认时区:

// 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());
请注意,我使用了
欧洲/伦敦
。API使用的格式(始终为
地区/城市
,如
美国/圣保罗
欧洲/柏林
)。 避免使用三个字母的缩写(如
CST
PST
),因为它们是

通过调用
ZoneId.getAvailableZoneIds()
,可以获得可用时区的列表(并选择最适合您的系统的时区)


还有夏令时的一些极端情况(当一个
LocalDateTime
可以存在两次或由于以下原因而不存在时)。在这种情况下,使用
ZonedDateTime
可以避免这个问题)。

使用SimpleDateForma classt来处理java中的每种格式。@AMallal:理想情况下,不要使用
java.time
。@Jon skeet:My badWait,Jon,这并没有给我与.NET代码相同的内容。我想要有todays date,时间是我想要的字符串值。因此,对于今天的“16/08/2017 15:45”,最好将其作为日期对象,以便我可以对其执行操作。这只在转储到控制台时给出“17:45”。@MoonKnight:A
Date
对象是时间上的一个瞬间。你想把它放在哪个时区<代码>日期
几乎总是使用错误的类型。我会再编辑我的答案。@MoonKnight:扩展了很多。很好。我只想要一张快照,但我同意你关于日期的所有观点。非常感谢您花时间写一份详细的回复,非常感谢。我接受你说的一切。再次感谢。回答得很好,非常感谢您抽出时间。我从中学到了很多。祝你一切顺利。@MoonKnight不客气,很高兴能帮助你!我可以推荐这一点吗?这是
java.time
API的一个很好的起点。干杯您应该按原样使用
Locale.ROOT