将作为Query-Params传递的不同日期解析为REST API的标准方法是什么? [英] What is the Standard way to Parse different Dates passed as Query-Params to the REST API?

查看:175
本文介绍了将作为Query-Params传递的不同日期解析为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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆