Home > Back-end >  Am I using java.time correctly, here? It seems like the old API would be easier
Am I using java.time correctly, here? It seems like the old API would be easier

Time:05-24

I haven't used the java.time API very much because mostly my work involves capturing, storing, and displaying dates and times without manipulating them in any way. But occasionally, I have to do something like:

  • Get the date 30 days in the past

I've also decided that, based upon other unrelated experiences, humans tend to consider "30 days in the past" to actually mean "the start of the day 30 days in the past" not just "now minus 30*24*60*60*1000 milliseconds in the past" which is super-easy to do with just System.currentTimeMillis and arithmetic.

So my requirement is:

  • Get the date 30 days in the past, at the beginning of the day in my time zone

If I were to do this with the old API, I would do this:

TimeZone zone = ...; // However I get my time zone
Locale locale = ...; // However I get my locale
Calendar now = Calendar.getInstance(zone, locale);
// Reset to midnight
now.set(Calendar.HOUR, 0);
now.set(Calendar.MINUTE, 0);
now.set(Calendar.SECOND, 0);
now.set(Calendar.MILLISECOND, 0);
// Now go back 30 days
now.add(Calendar.DAY, -30);
// done

Aside from the repeated calls to blank-out the time part of the Calendar, it's pretty straightforward. It uses only 3 classes, and two of them are the TimeZone and Locale classes, only one of which is really necessary (TimeZone).

This time around, I decided to use java.time because, well, it's "better." I really don't know my way around it, so I did a lot of internet searching to figure out how to do various things, and I finally came up with the code below. Isn't this supposed to be "easier?"

TimeZone zone = ...; // However I get my time zone
ZoneId zid = zone.toZoneId(); // Convert to new kind of time zone
ZonedDateTime date = ZonedDateTime.now(zid);
date = date.minus(Period.ofDays(30)); // Rewind 30 days
date = date.truncatedTo(ChronoUnit.DAYS);
Instant instant = date.toInstant(); // Convert to Instant for comparisons

Now I'm using 6 different classes. Okay, 2 of them are constant-type things so we can ignore them. I have to use Instant because all the dates I have to use for comparison are java.util.Date, and Instant is the class that bridges all the gaps.

Is the problem that this is a "simple problem" and java.time is intended to solve problems that are far more complicated?

CodePudding user response:

Get the date 30 days in the past

sounds like

java.time.LocalDate.now().minusDays(30)

CodePudding user response:

The purpose of the multiple different classes in java.time is exactly to model many of the things you mentioned in your question.

humans tend to consider "30 days in the past" to actually mean "the start of the day 30 days in the past"

Right, you don't care about the time, so you don't need a DateTime, just a LocalDate.

LocalDate prev = LocalDate.now().minusDays(30);

If you have to convert to an Instant, then you need to specify a timezone.

Instant asInstant = prev.atStartOfDay​(zone).toInstant();

However if you don't care about the time then you probably shouldn't be converting to Instant, just stick with LocalDate.

I have to use Instant because all the dates I have to use for comparison are java.util.Date

Date includes a time part. Are you truncating those to the start of day as well? One way to do that and get back a LocalDate is:

date.toInstant().atZone(zone).toLocalDate();
  • Related