我应该使用哪个Java日期时间类?

9
我们有一个用于生成报告的库。它从数据文件(SQL、XML、JSON等)中读取,日期时间可以在用户编写的方程式中进行修改,然后按照报告输出的指定格式进行格式化。
在方程式中使用可以添加时间跨度,获取值的部分,如“if date.month == 2”,以及几乎所有Excel中的日期时间宏。
由于数据可以是JSON(或没有模式的XML),日期时间可以是“2019-01-25”、“2019-01-25T14:32:23”、“2019-01-25T14:32:23.12345”、“2019-01-25T14:32:23Z”或“2019-01-25T14:32:23Z-0500”(最后两个也可以有“.12345”)。
如果没有时区偏移量,我们假设日期时间为UTC。虽然这应该是正确的,但通常并不是,它是本地时间,但在使用方式上并不重要。因此,除非指定了时区偏移量,否则将其设置为UTC可行(到目前为止我们一直使用Date)。

第一个问题 - 我应该使用哪个类来保存这个值?根据我所了解的,我认为应该使用ZonedDateTime,但也可能是Instant?

第二个问题 - 当我需要执行像将3天添加到日期时间之类的操作时,我应该使用什么类来表示时间段?

第三个问题 - 是否有一些解析器可以解析我上面列出的所有不同字符串?或者我需要调用String.contains()方法来确定格式,然后根据格式进行显式模式匹配?如果是这样,使用哪个类?


1
你的示例中没有时区,只有时区偏移量,因此使用OffsetDateTimeZonedDateTime更合理。 - assylias
你是否考虑过 Joda Time?这是我最喜欢的处理时间的类。如果你能够实现它,我可以帮你回答相关问题。 - S. Czop
@S.Czop 我们使用的是Java 1.8,因此我们将使用java.time。 - David Thielen
2
@S.Czop为什么要使用一个外部库来处理现在已经被标准运行时覆盖的东西(除非你必须使用Java 7)。 - Henry
关于你的第一个问题,看着你最后一个例子 2019-01-25T14:32:23Z-0500:你需要知道5小时的偏移量吗?或者你只想保持相同的UTC时间,即 2019-01-25T19:32:23Z?还是你更喜欢 2019-01-25T14:32:23Z(这不是相同的瞬间,但是是相同的本地时间)? - assylias
显示剩余4条评论
2个回答

6
第三个问题 - 是否有一些解析器可以解析我上面列出的所有不同字符串?还是我需要调用String.contains()来确定格式,然后根据那个显式模式进行操作?如果是这样,使用哪个类?
我可能非常错误,但您可以在模式上使用可选部分和parseBest方法,使用DateTimeFormatter。
List<String> dates = List.of(
    "2019-01-25", 
    "2019-01-25T14:32:23",
    "2019-01-25T14:32:23.12345", 
    "2019-01-25T14:32:23Z", 
    "2019-01-25T14:32:23Z-0500"
);

DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
   "yyyy-MM-dd['T'[HH:mm:ss][.SSSSS]][z][x]"
); // all the possible combinations

dates.forEach( date -> {
            TemporalAccessor accessor = formatter.parseBest(date,                       
       OffsetDateTime::from, // going from most specific date
       LocalDateTime::from, 
       LocalDate::from); // to the less specific 

            System.out.println( accessor.getClass() + " " + accessor);
        }

);

// output for this is 
class java.time.LocalDate 2019-01-25
class java.time.LocalDateTime 2019-01-25T14:32:23
class java.time.LocalDateTime 2019-01-25T14:32:23.123450
class java.time.OffsetDateTime 2019-01-25T14:32:23Z
class java.time.OffsetDateTime 2019-01-25T14:32:23-05:00

3
关于第二个问题:是的,Java JDK中有一个“timespan”类。
对于没有附加到时间线的时间跨度:

Period

表示一定数量的天数/周数/月数/年数。可用于日期计算,自动考虑夏令时(DST)。
例如,要从给定日期减去3天,可以这样做:
ZonedDateTime threeDaysAgo = Period.ofDays(-3).addTo(ZonedDateTime.now());

持续时间

类似于Period,但是基于天数的规模(以24小时为一块,而不是日历天),包括小时、分钟、秒和小数秒。

ChronoUnit

如果您需要在更广泛的范围内进行计算(如包括小时/分钟/秒等),还有ChronoUnit枚举类型:ChronoUnit

ZonedDateTime threeHoursAgo = ChronoUnit.HOURS.addTo(ZonedDateTime.now(), -3);

是和否 - 从意义上讲,它并不真正表示时间跨度 - 不确定这是否会成为问题。它也没有小时/分钟/秒的精度。 - assylias
1
你的意思是“是”和“否”。无论术语的含义如何,这正是OP所请求的——一个容器,用于存放类似“3天”这样的内容,而不是特定日期之间的范围。 - Sharon Ben Asher
编辑答案以包括更广泛的时间单位解决方案。 - Sharon Ben Asher
1
有关时间跨度附加到时间线上,请参见ThreeTen-Extra库中的IntervalLocalDateRange类。 - Basil Bourque

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接