1

I am running my code in EST timezone.

Using Instant.now() in my code and it returns time in UTC.

But, I am trying to test a method which gets data from DB as Date not Instant and hence trying to convert this to Date using

Date.from(Instant.now())

Since, I am running this in EST, this Date gives me time in EST.

Actual code,

    final Optional<Date> dbTime = dbService.getUpdatedTime();
    final Instant lastInstant = dbTime.orElseGet(() -> Date.from(Instant.now())).toInstant();

Test Code,

final Date dbTime = Date.from(Instant.now().minusSeconds(36000));
when(dbService.getUpdatedTime().thenReturn(Optional.of(dbTime));

Here, the dbTime gets converted to EST time. I can make that to return UTC time by setting TimeZone.setDefault(TimeZone.getTimeZone("UTC"));

Is there any other better way? Is this ok to set TimeZone.setDefault(TimeZone.getTimeZone("UTC")); in the main Application class so that it will always be treated as UTC?

user1578872
  • 7,808
  • 29
  • 108
  • 206
  • Possible duplicate of [Timezone conversion](https://stackoverflow.com/questions/6567923/timezone-conversion) – pvg Nov 14 '17 at 06:49
  • 2
    A `Date` doesn't have a time zone. It's just an instant in time. See https://codeblog.jonskeet.uk/2017/04/23/all-about-java-util-date/ – Jon Skeet Nov 14 '17 at 07:06
  • 1
    @JonSkeet is right. So you basically don’t have a problem. It’s just `Date.toString()` that led you to believe you had one. – Ole V.V. Nov 14 '17 at 07:46
  • To clarify: The legacy class `java.util.Date` and the modern `java.time.Instant` both represent a moment in UTC. `Instant` replaced `Date`. No need to mix the classes. As of JDBC 4.2 and later, never use `Date`, always use `Instant`. – Basil Bourque Aug 21 '18 at 20:14

1 Answers1

2

First recommendation, since you can use the modern Java date and time API, use it as much as you can and minimize the use of the outdated Date class. Best will be if you can modify getUpdatedTime() to return an Optional<Instant> rather than an Optional<Date> (a modern JDBC driver can give you the datetime from your database as an Instant directly). Since an Instant prints in UTC, this should wipe away all of your issue and your question.

In this answer I am assuming that you either cannot do that or don’t want to do it just yet. You can still get close, though:

    final Optional<Instant> dbTime = dbService.getUpdatedTime().map(Date::toInstant);
    final Instant lastReconInstant = dbTime.orElseGet(Instant::now);

Avoid TimeZone.setDefault(). Since the JVM only has one global time zone setting, this may unintentionally change the behaviour of other parts of your program or other programs running in the same JVM.

A detail, in your stub code I recommend to make it explicit that you subtract 10 hours. Two options are

    final Date dbTime = Date.from(Instant.now().minus(10, ChronoUnit.HOURS));

    final Date dbTime = Date.from(Instant.now().minus(Duration.ofHours(10)));

All of this said, it still seems to me that you didn’t have a problem in the first place. A Date does not have a time zone in it. Its toString method just grabs the JVM’s default time zone and uses it for rendering the date and time. This has fooled many and is just one of the reasons to avoid that class when you can.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161