andresmonc
andresmonc

Reputation: 478

Java setTimeZone changing date

I'm parsing a String "11/15/2020" into a date. I need to set the time zone to EDT but this changes date to 11/14/2020. I'm assuming because I'm in CST it's removing that hour time difference from : Sun Nov 15 00:00:00 CST 2020 and this becomes the prior day.

I would like to set the timezone without modifying the date. How can I go about doing this? It would not be sufficient to just add an hour.

dateFormat dataFormat = new SimpleDateFormat("MM/dd/yy");
dataFormat.setTimeZone(TimeZone.getTimeZone(Constants.EDT_TZN));

Upvotes: 0

Views: 862

Answers (2)

Basil Bourque
Basil Bourque

Reputation: 340118

A date has no time zone

I would like to set the timezone without modifying the date.

A date-only value such as November 15 of 2020 has no notion of time zone. You have no need to worry about time zones.

Avoid legacy date-time classes

You are using terrible date-time classes that were supplanted years ago by the java.time classes defined in JSR 310. Never use SimpleDateFormat, Date, or Calendar.

Table of date-time types in Java (both legacy and modern) and in standard SQL.

LocalDate

In Java, a date-only value without time-of-day and without time-of-day is represented by the LocalDate class.

String input = "11/15/2020" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "MM/dd/uuuu" ) ;
LocalDate ld = LocalDate.parse( input , f ) ;

See this code run live at IdeOne.com.

ld.toString: 2020-11-15

Moment

Perhaps you do want a moment rather than just a date. I assume that would mean you want the first moment of the day.

Do not assume the day starts at 00:00:00. Anomalies such as Daylight Saving Time (DST) means the day may start at a time such as 01:00:00. Let java.time determine what a particular day in a particular time zone begins.

Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST, EDT, CST, or IST as they are not true time zones, not standardized, and not even unique(!). For example, CST could be China Standard Time just as easily as Central Standard Time in the Americas.

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ld.atStartOfDay( z ) ;

zdt.toString(): 2020-11-15T00:00-05:00[America/Montreal]

Generally best to store and exchange moments in UTC. To adjust from our specified time zone to UTC, extract a Instant from the ZonedDateTime. An Instant is always in UTC by definition.

Instant instant = zdt.toInstant() ;

instant.toString(): 2020-11-15T05:00:00Z

Generate text in standard ISO 8601 format. The Z on the end means UTC, and is pronounced “Zulu”.

instant.toString(): 2020-11-15T05:00:00Z

Convert

If you must interoperate with old code not yet updated to java.time, you can convert back-and-forth. Look to new to…/from… methods added to the old classes.

The legacy class Date, though misnamed, is equivalent to Instant, both representing a moment in UTC. Instant uses a finer resolution of nanoseconds rather than milliseconds.

Date d = java.util.Date.from( instant ) ;

…and…

Instant instant = d.toInstant() ;

Be aware that the Date::toString method tells a lie, applying the current default time zone. While well-intentioned, in practice this is quite confusing. One of many reasons to avoid this class.

Upvotes: 2

ControlAltDel
ControlAltDel

Reputation: 35106

Time in Java (as per the Date object and System.currentTimeMillis) is defined as the milliseconds past January 1, 1970, 00:00:00 GMT. All setting the TimeZone does is localize the offset in hours at a specific (Java) time.

So you have three choices:

  1. Don't add the extra hour and set the the timezone to EST, in which case you get a new date.
  2. Add the extra hour in which case the date will stay the same
  3. Find or build your own time/date package

Upvotes: 1

Related Questions