将作为Query-Params传递的不同日期解析为REST API的标准方法是什么? [英] What is the Standard way to Parse different Dates passed as Query-Params to the REST API?
问题描述
我正在开发一个支持Date作为查询参数的REST API。由于它是Query param,因此它将是String。现在Date可以在QueryParams中以下列格式发送:
yyyy-mm-dd [(T |)HH: MM:SS [.fff]] [(+ | - )NNNN]
这意味着以下内容有效日期:
2017-05-05 00:00:00.000 + 0000
2017-05-05 00:00 :00.000
2017-05-05T00:00:00
2017-05-05 + 0000
2017-05-05
现在解析所有这些不同的日期时间我使用 Java8 datetime
api。代码如下所示:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()。parseCaseInsensitive()
.append(DateTimeFormatter) .ofPattern(yyyy-MM-dd [[] [['T'] [] HH:mm:ss [.SSS]] [Z]))
.toFormatter();
LocalDateTime localDateTime = null;
LocalDate localDate = null;
ZoneId zoneId = ZoneId.of(ZoneOffset.UTC.getId());
Date date = null;
try {
localDateTime = LocalDateTime.parse(datetime,formatter);
date = Date.from(localDateTime.atZone(zoneId).toInstant());
} catch(异常异常){
System.out.println(Inside Excpetion);
localDate = LocalDate.parse(datetime,formatter);
date = Date.from(localDate.atStartOfDay(zoneId).toInstant());
}
从我使用的代码中可以看到 DateTimeFormatter
并附加模式。现在我首先尝试在 try-block
中将日期解析为 LocalDateTime
,如果它为类似的案例抛出异常 2017-05-05
因为没有时间过去,我在中使用
。 LocalDate
catch block
上面的方法给了我正在寻找的解决方案,但我的问题是这是处理以字符串形式发送的日期的标准方法,我的方法是符合这些标准?
另外,如果可能的话,我可以解析不同类型的日期(显示为上面的有效日期)的另一种方式除了一些其他简单的解决方案,例如使用数组列表然后使用for-loop尝试解析日期?
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
// time是可选的
.optionalStart()
.parseCaseInsensitive()
。 appendPattern([] ['T'])
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.optionalEnd()
// offset是可选的
.appendPattern([xx ])
.parseDefaulting(ChronoField.HOUR_OF_DAY,0)
.parseDefaulting(ChronoField.OFFSET_SECONDS,0)
.toFormatter();
for(String queryParam:new String [] {
2017-05-05 00:00:00.000 + 0000,
2017-05-05 00:00:00.000,
2017-05-05T00:00:00,
2017-05-05 + 0000,
2017-05-05,
2017-05 -05T11:20:30.643 + 0000,
2017-05-05 16:25:09.897 + 0000,
2017-05-05 22:13:55.996,
2017-05-05t02:24:01
}){
Instant inst = OffsetDateTime.parse(queryParam,formatter).toInstant();
System.out.println(inst);
}
此代码段的输出为:
2017-05-05T00:00:00Z
2017-05-05T00:00:00Z
2017-05-05T00:00:00Z
2017-05-05T00:00:00Z
2017-05-05T00:00:00Z
2017-05-05T11:20:30.643Z
2017-05-05T16: 25:09.897Z
2017-05-05T22:13:55.996Z
2017-05-05T02:24:01Z
我使用的技巧包括:
- 可选部分可包含在<$ c $中c> optionalStart /
optionalEnd
或模式中的[]
。我使用两者,每一个我觉得它更容易阅读,你可能更喜欢不同。 - 已经预定义了日期和时间的格式化程序,所以我重复使用它们。特别是我利用
DateTimeFormatter.ISO_LOCAL_TIME
已经处理可选秒和秒的分数这一事实。 - 用于解析为
OffsetDateTime
要工作,我们需要为查询参数中可能缺少的部分提供默认值。parseDefaulting
执行此操作。
在您的代码中,您将转换为日期
。 java.util.Date
类已经过时且存在许多设计问题,因此如果可以,请避免使用它。 即时
会很好。如果您确实需要一个 Date
来保存您无法更改或不想立即更改的旧API,请按照与问题相同的方式进行转换。 / p>
编辑:现在默认 HOUR_OF_DAY
,而不是 MILLI_OF_DAY
。后者仅在毫秒丢失时引起冲突,但似乎格式化程序对缺少时间的默认小时数感到满意。
I am working on a REST API which supports Date as a query param. Since it is Query param it will be String. Now the Date can be sent in the following formats in the QueryParams:
yyyy-mm-dd[(T| )HH:MM:SS[.fff]][(+|-)NNNN]
It means following are valid dates:
2017-05-05 00:00:00.000+0000
2017-05-05 00:00:00.000
2017-05-05T00:00:00
2017-05-05+0000
2017-05-05
Now to parse all these different date-times i am using Java8 datetime
api. The code is as shown below:
DateTimeFormatter formatter = new DateTimeFormatterBuilder().parseCaseInsensitive()
.append(DateTimeFormatter.ofPattern("yyyy-MM-dd[[ ][['T'][ ]HH:mm:ss[.SSS]][Z]"))
.toFormatter();
LocalDateTime localDateTime = null;
LocalDate localDate = null;
ZoneId zoneId = ZoneId.of(ZoneOffset.UTC.getId());
Date date = null;
try {
localDateTime = LocalDateTime.parse(datetime, formatter);
date = Date.from(localDateTime.atZone(zoneId).toInstant());
} catch (Exception exception) {
System.out.println("Inside Excpetion");
localDate = LocalDate.parse(datetime, formatter);
date = Date.from(localDate.atStartOfDay(zoneId).toInstant());
}
As can be seens from the code I am using DateTimeFormatter
and appending a pattern. Now I am first trying to parse date as LocalDateTime
in the try-block
and if it throws an exception for cases like 2017-05-05
as no time is passed, I am using a LocalDate
in the catch block
.
The above approach is giving me the solution I am looking for but my questions are that is this the standard way to deal with date sent as String and is my approach is in line with those standards?
Also, If possible what is the other way I can parse the different kinds of date (shown as the Valid dates above) except some other straightforward solutions like using an Array list and putting all the possible formats and then using for-loop trying to parse the date?
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
// time is optional
.optionalStart()
.parseCaseInsensitive()
.appendPattern("[ ]['T']")
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.optionalEnd()
// offset is optional
.appendPattern("[xx]")
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
.toFormatter();
for (String queryParam : new String[] {
"2017-05-05 00:00:00.000+0000",
"2017-05-05 00:00:00.000",
"2017-05-05T00:00:00",
"2017-05-05+0000",
"2017-05-05",
"2017-05-05T11:20:30.643+0000",
"2017-05-05 16:25:09.897+0000",
"2017-05-05 22:13:55.996",
"2017-05-05t02:24:01"
}) {
Instant inst = OffsetDateTime.parse(queryParam, formatter).toInstant();
System.out.println(inst);
}
The output from this snippet is:
2017-05-05T00:00:00Z
2017-05-05T00:00:00Z
2017-05-05T00:00:00Z
2017-05-05T00:00:00Z
2017-05-05T00:00:00Z
2017-05-05T11:20:30.643Z
2017-05-05T16:25:09.897Z
2017-05-05T22:13:55.996Z
2017-05-05T02:24:01Z
The tricks I am using include:
- Optional parts may be included in either
optionalStart
/optionalEnd
or in[]
in a pattern. I use both, each where I find it easier to read, and you may prefer differently. - There are already predefined formatters for date and time of day, so I reuse those. In particular I take advantage of the fact that
DateTimeFormatter.ISO_LOCAL_TIME
already handles optional seconds and fraction of second. - For parsing into an
OffsetDateTime
to work we need to supply default values for the parts that may be missing in the query parameter.parseDefaulting
does this.
In your code you are converting to a Date
. The java.util.Date
class is long outdated and has a number of design problems, so avoid it if you can. Instant
will do fine. If you do need a Date
for a legacy API that you cannot change or don’t want to change just now, convert in the same way as you do in the question.
EDIT: Now defaulting HOUR_OF_DAY
, not MILLI_OF_DAY
. The latter caused a conflict when only the millis were missing, but it seems the formatter is happy with just default hour of day when the time is missing.
这篇关于将作为Query-Params传递的不同日期解析为REST API的标准方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!