(Simple)DateFormat that allow 24:00:00 and 00:00:00 as inputs

早过忘川 提交于 2019-12-10 04:22:20

问题


I've been looking for this for a while, with no success so far. Do you know if there's a "DateFormat" ish class, that will allow me to use "00:00:00" and "24:00:00" as input parameters (they're both midnight) but when called "getHour()" I'll get 0 or 24 as a result?

Using "kk" will only allow me to have <1:24> range, meanwhile I'm looking for <0:24> range formatting


回答1:


The value 24:00 is not represented in a LocalTime because it is strictly part of the next day. Consideration was given to models where 24:00 could be represented as part of LocalTime, but the conclusion was that it would be very confusing in a lot of use cases, and create more bugs than it solves.


There is support for 24:00 in java.time however. It is perfectly possible to parse it using the standard formatting techniques, however it is necessary to use SMART or LENIENT mode, see ResolverStyle. The default mode is SMART, however the formtter constants on DateTimeFormatter like DateTimeFormatter.ISO_LOCAL_DATE_TIME are in STRICT mode. Thus, ofPattern() defaults to SMART mode:

static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm");

LocalDateTime ldt = LocalDateTime.parse("2012-12-03T24:00", FORMATTER);
System.out.println(ldt);  // 2012-12-04T00:00

Note that this also works for OffsetDateTime and ZonedDateTime. The standard parser for Instant supports 24:00 without a special formatter:

Instant instant = Instant.parse("2015-01-01T24:00:00Z");
System.out.println(instant);  // 2015-01-02T00:00:00Z

Any formatter can be converted to SMART or LENIENT mode using withResolverStyle() as follows:

DateTimeFormatter f = ...  // obtain a formatter somehow
DateTimeFormatter smartMode = f.withResolverStyle(ResolverStyle.SMART);

// for example
f = DateTimeFormatter.ISO_LOCAL_DATE_TIME.withResolverStyle(ResolverStyle.SMART);

The second element of support is parseExcessDays(). This allows the excess day to be obtained when only the time is being parsed:

static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm");

TemporalAccessor parsed = TIME_FORMATTER.parse("24:00");
LocalTime lt = LocalTime.from(parsed);
Period excessDays = parsed.query(DateTimeFormatter.parsedExcessDays());
System.out.println(lt + " + " + excessDays);  // 00:00 + P1D

Finally, a note for advanced users. It should in theory be possible to write your own implementation of Temporal that is a copy of LocalTime but with support for 24:00 as a valid value. Such a class, say LocalTimeWithEndOfDay, could then operate with the formatter/parser without issue (and might make a good addition to ThreeTen-Extra.




回答2:


First let's make clear that the time 24:00 is a valid ISO-8601-time. Citation from ISO-8601:

4.2 Time of day
4.2.1 General
  This International Standard is based on the 24-hour timekeeping System
  that is now in common use. In expressions of time of day
  hour is represented by two digits from [00] to [24]. The representation
  of the hour by [24] is only allowed to indicate the end of a calendar
  day, see 4.2.3.

Java itself does not support 24:00 unless you use the lenient parsing mode of SimpleDateFormat. But even then the support is not available because if you ask the result (an instance of java.util.Date) for the hour you get zero as you have already observed. Similar thoughts are valid for java.util.GregorianCalendar. After parsing, there is no chance to determine if the input was 24:00 or not (without knowing what the original input was).

Java-8 also has no real support for this special hour. The best thing you can do here is using parseExcessDays() applied on the raw parsed data of DateTimeFormatter. You could use a workaround like this:

String input = "24:00:00";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("HH:mm:ss");
TemporalAccessor raw = dtf.parse(input);
int hour = raw.query(LocalTime::from).getHour();
Period period = raw.query(DateTimeFormatter.parsedExcessDays());
if (period.equals(Period.ofDays(1))) {
  hour = 24;
}
System.out.println("iso-hour=" + hour); // output: iso-hour=24

The popular 3rd-party library Joda-Time has no support for 24:00. The situation is similar to SimpleDateFormat.

The only library with built-in support I am aware of is Time4J which I have written myself. The full support is limited to PlainTime (similar pendant to LocalTime), not valid for complete date-time-representations (where it would be ambivalent, timestamps containing 24:00 will automatically be normalized to next day at 00:00):

PlainTime time = Iso8601Format.EXTENDED_WALL_TIME.parse("24:00:00");
System.out.println(time.get(PlainTime.ISO_HOUR)); // 24

Note that the state space of class PlainTime is slightly extended such that it can hold this special ISO-time-value. Therefore a direct programmatical access like this is possible:

PlainTime time24 = PlainTime.midnightAtEndOfDay(); // or: PlainTime.of(24, 0);
System.out.println(time24); // T24


来源:https://stackoverflow.com/questions/31106357/simpledateformat-that-allow-240000-and-000000-as-inputs

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!