9

We have a library used for generating reports. It reads from a data file (SQL, XML, JSON, etc.), the datetime may then be modified in a user written equation, and then it is formatted as specified for the report output.

The use in an equation can be add a timespan, get parts of the value as in "if date.month == 2", and pretty much all the datetime macros in Excel.

Because the data can be JSON (or XML with no schema) the datetime can be "2019-01-25", "2019-01-25T14:32:23", "2019-01-25T14:32:23.12345", "2019-01-25T14:32:23Z", or "2019-01-25T14:32:23Z-0500" (last two can have the ".12345" also).

If there's no timezone offset we assume the datetime is UTC. While that should be true, often it isn't and it's local time but the way it's used, it doesn't matter. So making it UTC unless a timezone offset is specified works (up till now we've used Date).

First question - what class should I use to hold this value? From what I've read I think ZonedDateTime, but maybe Instant?

Second question - what class should I use for timespan when I have to do something like add 3 days to the datetime?

Third question - is there some parser that can parse all the different strings as I listed above? Or do I need to call String.contains() to determine the format and then do an explicit pattern based on that? And if so, using what class?

assylias
  • 297,541
  • 71
  • 621
  • 741
David Thielen
  • 22,779
  • 27
  • 83
  • 163
  • 1
    There are no timezones in your examples, only timezone offsets, so `OffsetDateTime` would make more sense than `ZonedDateTime`. – assylias Jan 25 '19 at 14:51
  • Have you considered Joda Time? It is my favourite class for working with time. If you could implement it, I could make an answer about it if you want. – S. Czop Jan 25 '19 at 14:55
  • @S.Czop we're on Java 1.8 so we're going to use java.time. – David Thielen Jan 25 '19 at 15:00
  • 2
    @S.Czop why use an external library for something that's now covered in the standard runtime (unless you have to use Java 7). – Henry Jan 25 '19 at 15:00
  • Re. your first Q. looking at your last example `2019-01-25T14:32:23Z-0500`: do you need to know the offset of 5hrs? Or are you ok with only keeping the same instant in UTC, i.e. `2019-01-25T19:32:23Z`? Or would you prefer having `2019-01-25T14:32:23Z` (which is NOT the same instant but the same local time)? – assylias Jan 25 '19 at 15:37
  • Re. you 2nd Q: once you have an OffsetDateTime (for example), you can write `datetime.plusDays(3)` to add 3 days. But there is no Timespan class in Java Time. You could easily write your own class or use [ThreeTen `Interval` class](https://www.threeten.org/threeten-extra/apidocs/org.threeten.extra/org/threeten/extra/Interval.html) which is an extension of Java Time. – assylias Jan 25 '19 at 15:39
  • @assylias - Good question. I think if they give us an offset, we need to keep it and work with it. For most uses the offset won't matter. But if it does, it would be an error if we converted them to UTC. Or am I missing something? – David Thielen Jan 25 '19 at 15:40
  • And for Q3: https://stackoverflow.com/questions/36188428/java-8-date-equivalent-to-jodas-datetimeformatterbuilder-with-multiple-parser-f#comment60016288_36188428 – assylias Jan 25 '19 at 15:40
  • @assylias - if you put all that in an answer, I'm happy to mark that the answer. Also, should I use OffsetDateTime or LocalDateTime as my class to hold this? As I can get an offset, I'm thinking OffsetDateTime??? – David Thielen Jan 25 '19 at 15:43

2 Answers2

5

Third question - is there some parser that can parse all the different strings as I listed above? Or do I need to call String.contains() to determine the format and then do an explicit pattern based on that? And if so, using what class?

I might be horrible wrong, but can you use DateTimeFormatter with optional parts on pattern and parseBest method:

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
Anton Balaniuc
  • 8,462
  • 1
  • 30
  • 47
3

As to the 2nd question: Yes there is a "timespan" class in the Java JDK.

For a span-of-time not attached to the timeline:

Period

Represents a number of days/weeks/months/years. Can be used in date calculations, automatically accounting for Daylight Savings Time (DST).

For example, to subtract 3 days from a given date, you could do

ZonedDateTime threeDaysAgo = Period.ofDays(-3).addTo(ZonedDateTime.now());

Duration

Similar to Period but on the scale of days (as 24-hour chunks, not calendar days), hours, minutes, seconds, and fractional second.

ChronoUnit

If you need to do calculations on a wider scale (like include hours/minutes/secods etc) There is also the ChronoUnit enum:

ZonedDateTime threeHoursAgo = ChronoUnit.HOURS.addTo(ZonedDateTime.now(), -3);
Basil Bourque
  • 218,480
  • 72
  • 657
  • 915
Sharon Ben Asher
  • 12,476
  • 5
  • 25
  • 42
  • Yes and know - It's not really a timespan in the sense that it doesn't hold the start and end date - not sure if that's an issue. And also doesn't have hour/minute/second precision. – assylias Jan 25 '19 at 16:17
  • 1
    you meant yes and no. and regardless of the meaning of the term, it is exactly what OP requested - a container for something like "3 days" not range between specific days. – Sharon Ben Asher Jan 25 '19 at 16:33
  • edited answer to include a solution for wider range of time units – Sharon Ben Asher Jan 25 '19 at 16:42
  • 1
    For a span-of-time attached to the timeline, see the `Interval` & `LocalDateRange` classes in the [*ThreeTen-Extra*](https://www.threeten.org/threeten-extra/) library. – Basil Bourque Jan 25 '19 at 18:26