简体   繁体   English

C#与Java中的DateTime操作

[英]DateTime Manipulation in C# vs Java

I'm new to Java. 我是Java的新手。 I have a time I am getting from a web-page, this is in the "hh:mm" format (not 24 hour). 我有时间从网页上获取,这是“hh:mm”格式(不是24小时)。 This comes to me as a string. 这对我来说是一个字符串。 I then want to combine this string with todays date in order to make a Java Date I can use. 然后我想将此字符串与今天的日期结合起来,以便创建一个我可以使用的Java Date

In C#: 在C#中:

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

in Java I have attempted: 在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);

Is there a better way to achieve what I want? 有没有更好的方法来实现我想要的?

Is there a better way to achieve what I want? 有没有更好的方法来实现我想要的?

Absolutely - in both .NET and in Java, in fact. 绝对 - 实际上在.NET和Java中都是如此。 In .NET I'd (in a biased way) recommend using Noda Time so you can represent just a time of day as a LocalTime , parsing precisely the pattern you expect. 在.NET中,我(以偏向的方式)推荐使用Noda Time,这样您就可以将一天中的某个时间表示为LocalTime ,从而精确地解析您期望的模式。

In Java 8 you can do the same thing with java.time.LocalTime : 在Java 8中,您可以使用java.time.LocalTime执行相同的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);
    }
}

Once you've parsed the text you've got into an appropriate type, you can combine it with other types. 一旦你解析了你已经进入适当类型的文本,就可以将它与其他类型结合起来。 For example, to get a ZonedDateTime in the system time zone, using today's date and the specified time of day, you might use: 例如,要使用今天的日期和指定的时间在系统时区中获取ZonedDateTime ,您可以使用:

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

That uses the system time zone and clock by default, making it hard to test - I'd recommend passing in a Clock for testability. 默认情况下使用系统时区和时钟 ,很难测试 - 我建议传入Clock进行测试。

(The same sort of thing is available in Noda Time, but slightly differently. Let me know if you need details.) (Noda Time也提供同样的东西,但略有不同。如果您需要详细信息,请告诉我。)

I would strongly recommend against using java.util.Date , which just represents an instant in time and has an awful API. 我强烈建议不要使用java.util.Date ,它只是代表一个即时的并且有一个糟糕的API。

The key points here are: 这里的关键点是:

  • Parse the text with a well-specified format 使用明确指定的格式解析文本
  • Parse the text into a type that represents the information it conveys: a time of day 将文本解析为表示其传达的信息的类型:一天中的某个时间
  • Combine that value with another value which should also be carefully specified (in terms of clock and time zone) 将该值与另一个值相结合,该值应该仔细指定(就时钟和时区而言)

All of these will lead to clear, reliable, testable code. 所有这些都将导致清晰,可靠,可测试的代码。 (And the existing .NET code doesn't meet any of those bullet points, IMO.) (并且现有的.NET代码不符合任何这些要点,IMO。)

To parse the time, you can do as explained in @Jon Skeet's answer : 要解析时间,你可以按@Jon Skeet的答案解释:

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

Note that I also used a java.util.Locale because if you don't specify it, it'll use the system's default locale - and some locales can use different symbols for AM/PM field. 请注意,我还使用了java.util.Locale因为如果您不指定它,它将使用系统的默认语言环境 - 并且某些语言环境可以为AM / PM字段使用不同的符号。 Using an explicit locale avoids this corner-case (and the default locale can also be changed, even at runtime, so it's better to use an explicit one). 使用显式语言环境可避免出现这种情况(即使在运行时也可以更改默认语言环境,因此最好使用显式语言环境)。

To combine with the today's date, you'll need a java.time.LocalDate (to get the date) and combine with the LocalTime , to get a LocalDateTime : 与今天的日期相结合,你需要一个java.time.LocalDate (获取日期),并与结合LocalTime ,以获得LocalDateTime

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

Then you can format the LocalDateTime using another formatter: 然后,您可以使用另一个格式化程序格式化LocalDateTime

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

The output is: 输出是:

16/08/2017 17:45 2017/08/16 17:45


If you want to convert the LocalDateTime to a java.util.Date , you must take care of some details. 如果要将LocalDateTime转换为java.util.Date ,则必须注意一些细节。

A java.util.Date represents the number of milliseconds since 1970-01-01T00:00Z (aka Unix Epoch). java.util.Date表示自1970-01-01T00:00Z (又名Unix Epoch)以来的毫秒数。 It's an instant (a specific point in time). 这是一个瞬间(一个特定的时间点)。 Check this article for more info. 有关详细信息,请查看此文章

So, the same Date object can represent different dates or times, depending on where you are: think that, right now, at this moment, everybody in the world are in the same instant (the same number of milliseconds since 1970-01-01T00:00Z ), but the local date and time is different in each part of the world. 因此,相同的Date对象可以代表不同的日期或时间,具体取决于您所处的位置:现在想想,此时此世界上的每个人都处于同一时刻(自1970-01-01T00:00Z以来相同的毫秒数) 1970-01-01T00:00Z ),但世界各地的当地日期和时间不同。

A LocalDateTime represents this concept of "local": it's a date (day, month and year) and a time (hour, minute, second and nanosecond), but without any relation to a specific timezone. LocalDateTime表示“本地”的概念:它是日期(日,月和年)和时间(小时,分钟,秒和纳秒),但与特定时区无关。

The same LocalDateTime object can represent different instants in time in different timezones. 相同的LocalDateTime对象可以在不同的时区中表示不同的时刻。 So, to convert it to a Date , you must define in what timezone you want it. 因此,要将其转换为Date ,您必须定义您想要的时区。

One option is to use the system's default timezone: 一种选择是使用系统的默认时区:

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

But the default can vary from system/environment, and can also be changed, even at runtime. 但是默认值可能因系统/环境而异,也可以在运行时更改。 To not depend on that and have more control over it, you can use an explicit zone: 要不依赖于它并对其进行更多控制,您可以使用显式区域:

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

Note that I used Europe/London . 请注意,我使用的是Europe/London The API uses IANA timezones names (always in the format Region/City , like America/Sao_Paulo or Europe/Berlin ). API使用IANA时区名称 (始终采用Region/City格式,如America/Sao_PauloEurope/Berlin )。 Avoid using the 3-letter abbreviations (like CST or PST ) because they are ambiguous and not standard . 避免使用3个字母的缩写(如CSTPST ),因为它们不明确且不标准

You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds() . 您可以通过调用ZoneId.getAvailableZoneIds()获取可用时区列表(并选择最适合您系统的时区ZoneId.getAvailableZoneIds()

And there's also the corner cases of Daylight Saving Time (when a LocalDateTime can exist twice or can't exist due to overlaps and gaps ). 此外还有夏令时的LocalDateTime情况(当LocalDateTime可以存在两次或由于重叠和间隙而不能存在时)。 In this case, Jon's solution using ZonedDateTime avoids this problem). 在这种情况下,使用ZonedDateTime Jon的解决方案避免了这个问题)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM