0

I have receiving a date in UTC format but needed to display it in my local timezone (EDT).

Stumbled across the following link :

How to set time zone of a java.util.Date?

Which provide this following answer :

SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = isoFormat.parse("2010-05-23T09:01:02");

I added the following line of code :

isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));

And what do you know it worked.

Trying to understand what happened and it seems a bit backwards.

I would have expected to have to enter EDT to convert from UTC to EDT but it appears to be the opposite.

isoFormat.setTimeZone(TimeZone.getTimeZone("EDT"));

Per the Java Docs for DateFormat it reads ....

enter image description here

And based on the above, it seems like I should be providing the TimeZone I want and not what I am converting from.

Can you explain what am I missing or misinterpreting?

If I enter in UTC, how is it getting EDT to know to convert it correct?

Can anyone fill in the blanks on how I should have know they were asking for the "From" TimeZone?

Unhandled Exception
  • 1,427
  • 14
  • 30
  • 1
    You're obtaining a `Date` - that's just an instant in time. When you call `toString()` on that, it converts it to the system local time zone... but it isn't inherently "in" EDT... it's just an instant in time. – Jon Skeet Jun 28 '21 at 18:58
  • I recommend you don’t use `SimpleDateFormat`, TimeZone` and `Date`. Those classes are poorly designed and long outdated, the first in particular notoriously troublesome. Instead use `LocalDateTime`, `DateTimeFormatter` and `ZoneId`, all from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Jun 29 '21 at 03:16

3 Answers3

3

tl;dr

Use java.time classes.

LocalDateTime
.parse( "2021-07-23T00:00" ) 
.atOffset( ZoneOffset.UTC )
.atZoneSameInstant(  ZoneId.of( "America/Montreal" ) )
.format(
    DateTimeFormatter
    .ofLocalizedDateTime( FormatStyle.FULL )
    .withLocale( Locale.CANADA_FRENCH )
)

Details

You are using terrible date-time classes that were years ago supplanted by the modern java.time classes.

Apparently your input strings are in standard ISO 8601 format. The java.time classes use ISO 8601 formats by default when parsing or generating text. So no need to define a custom formatting pattern.

String input = "2021-07-23T01:23:45" ;
LocalDateTime ldt = LocalDateTime.parse( input ) ;

Apparently you know for certain that the input was meant to be seen as a date and time in UTC, that is, having an offset-from-UTC of zero hours-minutes-seconds. If so, educate them publisher of your data to convince them to supply that string with a +00:00 or Z on the end to express that intention.

Meanwhile, we can assign an offset of zero to instantiate a OffsetDateTime.

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

And you apparently want to adjust that date-time to a particular time zone. Apply a ZoneId to get a ZonedDateTime object.

You asked for EDT. Unfortunately, such 2-4 letter codes are not a real time zone. Real time zone names are in format of Continent/Region such as Europe/Paris. Perhaps you meant a time zone such as America/New_York.

ZoneId z = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
0

A java.util.Date object simply represents an instant on the timeline — a wrapper around the number of milliseconds since the UNIX epoch (January 1, 1970, 00:00:00 GMT). Since it does not hold any timezone information, its toString function applies the JVM's timezone to return a String in the format, EEE MMM dd HH:mm:ss zzz yyyy, derived from this milliseconds value. To get the String representation of the java.util.Date object in a different format and timezone, you need to use SimpleDateFormat with the desired format and the applicable timezone e.g.

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

public class Main {
    public static void main(String[] args) throws ParseException {
        SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH);
        isoFormat.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
        Date date = isoFormat.parse("2010-05-23T09:01:02");
        
        isoFormat.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
        String strDateUtc = isoFormat.format(date);
        System.out.println(strDateUtc);

        isoFormat.setTimeZone(TimeZone.getTimeZone("America/New_York"));
        String strDateNewYork = isoFormat.format(date);
        System.out.println(strDateNewYork);     
    }
}

Output:

2010-05-23T09:01:02
2010-05-23T05:01:02

ONLINE DEMO

java.time

The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.

Solution using java.time, the modern Date-Time API:

The modern Date-Time API is based on ISO 8601 and does not require using a DateTimeFormatter object explicitly as long as the Date-Time string conforms to the ISO 8601 standards.

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Main {
    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.parse("2010-05-23T09:01:02");

        ZonedDateTime zdtUtc = ldt.atZone(ZoneId.of("Etc/UTC"));
        System.out.println(zdtUtc);

        ZonedDateTime zdtNewYork = zdtUtc.withZoneSameInstant(ZoneId.of("America/New_York"));
        System.out.println(zdtNewYork);
    }
}

Output:

2010-05-23T09:01:02Z[Etc/UTC]
2010-05-23T05:01:02-04:00[America/New_York]

ONLINE DEMO

Note: For any reason, if you need to convert this object of ZonedDateTime to an object of java.util.Date, you can do so as follows:

Date date = Date.from(zdtUtc.toInstant());

or

Date date = Date.from(zdtNewYork.toInstant());

Learn more about the modern Date-Time API from Trail: Date Time.


* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
-1

First thing Java doesn't support EDT abbreviation instead use "EST5EDT". If something is not found it falls EST5EDT. You can check full list of available timezones

In SimpleDateFormatter if you are using parse() it means you trying to read "from" something. If you are using format() it means you are trying to write "to" something.

Conclusion, In the case of parse() timezone act as input format but in case of format() it acts as output format. The below program converts an EDT date to IST date. Probably using the comments in the below example you will understand what exactly is happening.

// EDT Formatter
SimpleDateFormat edtFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
edtFormat.setTimeZone(TimeZone.getTimeZone("EST5EDT"));

// IST Formatter
SimpleDateFormat istFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
istFormat.setTimeZone(TimeZone.getTimeZone("IST"));

// Convert EDT to IST 
String edtDate = "2010-05-23T00:00:00";
Date date = edtFormat.parse(edtDate); //Parse from EDT to Local Timezone
String istDate = istFormat.format(date); //Parse from Local Timezone to IST

System.out.println("EDT: "+edtDate);
System.out.print("Local Date: ");
System.out.println(date);
System.out.println("IST: "+istDate);

I understand java's inital release of java.util.Date was very badly designed which created a lot of confusion that is why later they introduced java.time api whose name are way clear like LocalDate, ZonedDate etc.

sgrpwr
  • 431
  • 3
  • 12
  • 2
    There are two serious problems with your answer: (1) You are using `SimpleDateFormat` without a `Locale`. Check [Never use SimpleDateFormat or DateTimeFormatter without a Locale](https://stackoverflow.com/a/65544056/10819573) (2) You should never use three-letter abbv. for timezone. Check **Three-letter time zone IDs** section at [this page](https://docs.oracle.com/javase/7/docs/api/java/util/TimeZone.html). – Arvind Kumar Avinash Jun 28 '21 at 19:42
  • @ArvindKumarAvinash I know about locale but it has nothing to do with the core question here. I wanted to explain with bare minimum code which is easy to understand. I don't support copy-paste culture. Talking about good practices, any code assessment tool like Sonar could have pointed that out. In short, I am helping in understanding the concept with easy language and bare minimum code not coding standards – sgrpwr Jun 30 '21 at 04:34
  • @OleV.V. you are right, the problem is java doesn't support the abbreviation "EDT" check the [full list of supported abbreviations here](https://mkyong.com/java/java-display-list-of-timezone-with-gmt/). Probably you need to pass "EST5EDT". Since it is not able to find EDT it is falling back to GMT. I'll update my answer – sgrpwr Jun 30 '21 at 04:51