Anurag
Anurag

Reputation: 397

Calendar.getInstance with TimeZone vs new Date()

I have a utility written in my application that takes in a timezone and returns me a date (java.util.Date) as follows -

// Inside MyDateHelper.java
public static java.util.Date getTimeForTimeZone(String timeZoneId)
{
    final Date currentDate = Calendar.getInstance(TimeZone.getTimeZone(timeZoneId)).getTime();
    return currentDate;
}

I researched around the internet to find that Date does not have any timeZone information in it. Rather it is a wrapper around a long value starting from the epoch of 1970. So, my question is if I have to get the current Date-Time instant a transaction has occurred to store in a date field (of type java.util.Date), Is this utility of any use?

For all practical purposes are the two lines of code achieving the same?

transactionEntry.setTime(MyDateHelper.getTimeForTimeZone("UTC+7:00"));

OR

transactionEntry.setTime(new Date());

I also checked out the new Java 8 Time API, but for my purpose I think doing this is also an overkill and achieves nothing more new Date() -

Date date4 = new Date();
LocalDateTime localDate = date4.toInstant().atZone(ZoneId.of("UTC+07:00")).toLocalDateTime();
final ZonedDateTime dateWithZone = localDate.atZone(ZoneId.of("UTC+07:00"));
Date dateOutput = Date.from(dateWithZone.toInstant());
transactionEntry.setTime(dateOutput);

The whole purpose is to capture the time a transaction occurred with the time zone, but I can only store the time as a java.util.Date. No matter in which timezone the transaction occurred, the Date will be able to capture the instant of time correctly, right? Can someone confirm that this understanding is correct?

Upvotes: 2

Views: 3493

Answers (3)

xingbin
xingbin

Reputation: 28289

but I can only store the time as a java.util.Date.

Then the time zone does not matter,

Calendar calendar = Calendar.getInstance();

calendar.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
Date america = calendar.getTime();

calendar.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
Date shanghai = calendar.getTime();

System.out.println(america.equals(shanghai)); // true

You can just use:

transactionEntry.setTime(new Date());

This page will help you to understant Instant/Date, LocalDateTime, ZonedDateTime.

I think you might re-think the design. Why only java.util.Date is allowd?

From the description, it seems that you do care about the time zone where transaction occurs. While java.util.Date just do not support it. Which means you can store an accurate value(millis since epoch) to java.util.Date, but this value can not be represented by accurate date time, since the time zone has been lost.

You might need use java.time.ZonedDateTime to achieve it.

Upvotes: 3

Basil Bourque
Basil Bourque

Reputation: 339332

The Answer by Ole V.V. Is correct. I’ll add just a bit of discussion.

There is only one timeline experienced by everyone on Earth simultaneously (ignoring Einstein et al.). By convention we track that time in UTC.

Learn to think of UTC as The One True Time. All other offsets and zones are but a mere variation of UTC. When on the job as a programmer or sysadmin, forget about your own parochial time zone. Keep a second click on your desk or wall tracking time in UTC. Do all your logging, tracing, data-storage, and data-exchange in UTC.

The basic class for tracking a moment in UTC is java.time.Instant. Objects of this class are always in UTC by definition. This class supplants java.util.Date, which also represents a moment in UTC, but has many design flaws and should never be used. Instant has a resolution of nanoseconds, finer than the milliseconds of Date.

For more flexibility, use the OffsetDateTime class.

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;

And back again.

Instant instant = odt.toInstant() ;

An offset-from-UTC is merely a number of hours-minutes-seconds. A time zone is much more. A time zone is a history of past, present, and future changes to the offset used by the people of a particular region.

To use a time zone, apply a ZoneId to get a ZonedDateTime. This class supplants the terrible Calendar and GregorianCalendar classes.

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZoneId( z ) ;

Going back again.

Instant instant = zdt.toInstant() ;

This zdt, odt, and instant all represent the very same simultaneous moment, the same point on the timeline.

Lastly, stop using Date and Calendar. Sun, Oracle, and the JCP community all gave up on those classes when they adopted JSR 310, and so should you. Those legacy classes really are a bloody awful mess.

Upvotes: 6

Anonymous
Anonymous

Reputation: 86323

First suggestion:

    Instant transactionTime = Instant.now();

You are correct that there is no point in going through the time in your time zone, neither in a ZonedDateTime nor in a Calendar, when what you need is a timestamp, a moment in time. java.time.Instant is exactly that, a point in time without time zone (and is therefore the most direct replacement for a Date). You should probably want to use java.time, the modern Java date and time API, when you can. Date, Calendar and TimeZone are not only long outdated, they also have a range of design problems with them. The modern classes are so much nicer to work with.

If your transaction entry class internally uses java.util.Date and you don’t want to upgrade its internal logic right now, you can still add an overloaded setTime method that accepts an Instant.

public void setTime(Instant time) {
    // Delegate to the old method that accepts a java.util.Date
    setTime(Date.from(time));
}

A possible next step could be to mark the method that accepts a Date deprecated.

Second suggestion, if you insist on a Date I would still prefer:

    Date transactionTime = Date.from(Instant.now());

It does the same as new Date(), but tells the reader much more directly that you obtain the current moment. I can’t see how this could not be an advantage.

As an aside, if you did want to use your time zone, you should use a proper time zone ID like Antarctica/Davis rather than an offset. Again it tells your reader more about your intentions and is future-proof in case summer time (DST) is introduced some time or the offset changes for other reasons.

Upvotes: 4

Related Questions