Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 有没有办法确定DateTimeFormatter是仅限日期还是仅限构建后的时间?_Java_Date_Java 8_Java Time - Fatal编程技术网

Java 有没有办法确定DateTimeFormatter是仅限日期还是仅限构建后的时间?

Java 有没有办法确定DateTimeFormatter是仅限日期还是仅限构建后的时间?,java,date,java-8,java-time,Java,Date,Java 8,Java Time,使用Java8新的日期时间库,将字符串解析为日期的方法是使用DateTimeFormatterLocalDate、LocalTime和LocalDateTime都有一个静态解析方法,该方法接受字符串和格式化程序。一个潜在的问题是,如果DateTimeFormat不包含时间部分(或者DateTime不包含日期部分),那么即使模式匹配,最终也会出现解析错误 范例 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("YYYY-MM-DD

使用Java8新的日期时间库,将字符串解析为日期的方法是使用
DateTimeFormatter
LocalDate
LocalTime
LocalDateTime
都有一个静态解析方法,该方法接受字符串和格式化程序。一个潜在的问题是,如果DateTimeFormat不包含时间部分(或者DateTime不包含日期部分),那么即使模式匹配,最终也会出现解析错误

范例

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("YYYY-MM-DD");
LocalDateTime dt = LocalDateTime.parse("2016-01-11", formatter);
这将在消息中抛出一个
DateTimeParseException
(如上所述)

java.time.format.DateTimeParseException:
Text '2016-01-11' could not be parsed:
Unable to obtain LocalDateTime from TemporalAccessor
这是一条没有什么帮助的错误消息,因为文本可以被解析,因为它与模式匹配。相反,错误与无法创建LocalDateTime的时间部分有关。将代码重构为以下功能:

LocalDateTime ldt = LocalDate.parse("2016-01-11", formatter).atStartOfDay());
我的问题是,假设你有一个这样的通用方法

 public static LocalDateTime getDate(String s, DateTimeFormatter format) {
  ...
  }

有没有办法通过应用一些默认逻辑来确定需要调用哪个静态解析方法来将字符串强制转换为LocalDateTime?e、 如果日期只使用午夜,如果时间只使用今天,等等。

我想你的问题正好相反。您不想确定格式化程序是只使用日期还是日期/时间。您可以根据应该解析的内容和要将结果存储到的内容创建格式化程序。显然,如果您创建的格式化程序不处理时间部分,那么使用它解析为
LocalDateTime
是一种误解

如果您需要解析可以以两种格式到达的日期,如
“yyyy-MM-dd”
“yyy-MM-dd HH:MM:ss”
(带有时间部分),则不需要由解析来确定应该做什么,而是由格式化程序在没有时间的情况下提供默认值

对于Java时间,这是通过可选部分和默认值完成的。例如,模式
“yyyy-MM-dd[HH:MM:ss]”
将能够解析日期字符串(如
“2016-01-11”
)和日期/时间字符串(如
“2016-01-11 20:10:10”
)。如果要将其存储到
LocalDateTime
,则需要提供默认值,以防没有时间组件。这是通过:这将告诉格式化程序返回该计时字段的给定默认值(如果尚未设置)

下面的代码创建了这样一个格式化程序,并将时间部分默认为午夜

public static void main(String[] args) {
    DateTimeFormatter formatter = 
            new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd[ HH:mm:ss]")
                                          .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
                                          .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
                                          .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
                                          .toFormatter();

    LocalDateTime dt1 = LocalDateTime.parse("2016-01-11", formatter);
    LocalDateTime dt2 = LocalDateTime.parse("2016-01-11 20:10:10", formatter);
}

当然,这个逻辑可以扩展到只解析时间字符串,并将日期组件默认为当前日期。

与标题中的主要问题相关,
DateTimeFormatter
只返回一般的
TemporalAccessor
,而不是具体的所需结果类型。相反,用户应该间接地使用解析器的结果向具体类型提供静态
from(parsed)
-方法。因此,您将在这些方法的文档中找到成功解析所需的字段类型:

因此,查询这些字段的原始解析数据就足以确定格式化程序是类似日期、类似时间还是一种组合。

DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.ENGLISH);
TemporalAccessor tacc = dateFormatter.parse("2015-07-24");
System.out.println("date-like: " + tacc.isSupported(ChronoField.EPOCH_DAY)); // true
System.out.println("time-like: " + tacc.isSupported(ChronoField.NANO_OF_DAY)); // false


DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm", Locale.ENGLISH);
tacc = timeFormatter.parse("17:45");
System.out.println("date-like: " + tacc.isSupported(ChronoField.EPOCH_DAY)); // false
System.out.println("time-like: " + tacc.isSupported(ChronoField.NANO_OF_DAY)); // true

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm", Locale.ENGLISH);
tacc = dateTimeFormatter.parse("2015-07-24 17:45");
System.out.println("date-like: " + tacc.isSupported(ChronoField.EPOCH_DAY)); // true
System.out.println("time-like: " + tacc.isSupported(ChronoField.NANO_OF_DAY)); // true

但除此之外,我必须同意@Tunaki的观点,即从设计角度来看,对字段使用默认值是更好的主意。要完成上面给出的代码,如果输入与模式不匹配等,您还需要特殊的异常处理。

使用其他人创建的格式化程序进行解析比解析您可以控制的格式化程序更复杂(Tunaki的
parseDefaulting()
答案正确)。但是可以这样做:

public static LocalDateTime getDate(String s, DateTimeFormatter format) {
    TemporalAccessor dt = parser.parseBest(
            str, LocalDateTime::from, LocalDate::from, LocalTime::from, YearMonth::from);

    if (dt instanceof LocalDate) {
        return ((LocalDate) dt).atStartOfDay();
    } else if (dt instanceof LocalTime) {
        return ((LocalTime) dt).atDate(LocalDate.now());
    } else if (dt instanceof YearMonth) {
        return ((YearMonth) dt).atDay(1).atStartOfDay();
    } else {
        return LocalDateTime.from(dt);
    }
}

我没有测试上面的代码,但这就是
parseBest()
方法的设计目的。

您可以创建一个Java对象,该对象具有一个解析字符串字段和一个开关字段或一个枚举字段,告诉您的静态解析方法“use midnight”、“use today”,等。将该Java对象的实例传递给您的静态解析方法。我假设下面的代码可以工作,但它会抛出一个异常
DateTimeFormatter formatter=DateTimeFormatter.ofPattern(“YYYY-MM-DD”)。带有ResolverFields(ChronoField.HOUR of theu DAY)
TemporalAccessor accessor=formatter.parse(“2016-01-11”)
LocalDateTime dt
if(accessor.isSupported(ChronoField.HOUR OF u DAY)){
`dt=LocalDateTime.from(accessor);`}else{``dt=LocalDate.from(accessor.atStartOfDay();`
@joecoder YYYY-MM-DD类型的ISO不正常(以周为基础的年、月、日组合不能产生日期)。使用
with resolverfields()
在这里一点都不相关。这只是一个示例格式,但对于日期,您有什么建议?@joecoder您应该遵循Tunaki的答案,并使用默认字段值来表示缺少的部分。我的回答只是一个暗示,并不完整。由于JSR-310解析引擎的局限性,为了实现这一点,您还需要异常处理。例如,如果输入与模式不匹配(由我测试,这里甚至没有
parseUnresolved()
帮助),那么查询原始数据就不容易了。谢谢。在这种情况下,责任由DateTimeFormatter创建者承担,在静态方法中无法通过增加额外开销来真正防范。@joecoder“增加额外开销”是什么意思?使用这种格式化程序(如果可以的话)的好处是不需要增加开销。将代码放在静态函数中,与其他示例一样,检查它支持哪种类型的日期。您的格式化程序工作得很好,但是如果另一个用户使用非默认格式化程序调用该函数,而您不想通过应用自己的默认设置引发异常。我