Thang Pham
Thang Pham

Reputation: 38705

Java.util.Date: try to understand UTC and ET more

I live in North Carolina, btw, which is on the East Side. So I compile and run this code and it print out the same thing. The documentation say that java.util.date try to reflect UTC time.

Date utcTime = new Date();
Date estTime = new Date(utcTime.getTime() + TimeZone.getTimeZone("ET").getRawOffset());
DateFormat format = new SimpleDateFormat("dd/MM/yy h:mm a");
System.out.println("UTC: " + format.format(utcTime));
System.out.println("ET: " + format.format(estTime));   

And this is what I get

UTC: 11/05/11 11:14 AM
ET: 11/05/11 11:14 AM

But if I go to this website which try to reflect all different time, UTC and ET are different. What did I do wrong here

Upvotes: 5

Views: 4319

Answers (6)

Arvind Kumar Avinash
Arvind Kumar Avinash

Reputation: 78965

Unknowingly, you have introduced two major problems in your code:

  1. Not using the proper timezone name: The two/three/four letter timezone names (e.g. ET, EST, CEST etc.) are error-prone. The proper way of naming a timezone is Region/City e.g. Europe/London. In most cases, the Region is the name of the continent to which the City belongs.
  2. Not using Locale with SimpleDateFormat: A parsing/formatting type e.g. the legacy, SimpleDateFormat or the modern, DateTimeFormatter are Locale-sensitive and therefore you should always use a Locale to avoid surprises. You can check this answer to learn more about it.

Also, note that a java.util.Date object is not a real Date-Time object like the modern Date-Time types; rather, it represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT (or UTC). Since it does not hold any format and timezone information, it applies the format, EEE MMM dd HH:mm:ss z yyyy and the JVM's timezone to return the value of Date#toString derived from this milliseconds value. If you need to print the Date-Time in a different format and timezone, you will need to use a SimpleDateFormat with the desired format and the applicable timezone e.g.

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) {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yy hh:mm a zzz", Locale.ENGLISH);

        sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
        System.out.println(sdf.format(date));

        sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
        System.out.println(sdf.format(date));
    }
}

A sample output:

05/06/21 08:29 AM EDT
05/06/21 12:29 PM UTC

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*.

A demo using java.time, the modern API:

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Main {
    public static void main(String[] args) {
        Instant now = Instant.now();
        System.out.println(now);

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

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

A sample output:

2021-06-05T12:19:58.092338Z
2021-06-05T12:19:58.092338Z[Etc/UTC]
2021-06-05T08:19:58.092338-04:00[America/New_York]

ONLINE DEMO

Need output string in a different format?

You can use DateTimeFormatter for the output string in a different format e.g.

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        Instant now = Instant.now();
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd/MM/uu hh:mm a zzz", Locale.ENGLISH);

        ZonedDateTime zdtUTC = now.atZone(ZoneId.of("Etc/UTC"));
        System.out.println(dtf.format(zdtUTC));

        ZonedDateTime zdtNewYork = now.atZone(ZoneId.of("America/New_York"));
        System.out.println(dtf.format(zdtNewYork));
    }
}

A sample output:

05/06/21 12:34 PM UTC
05/06/21 08:34 AM EDT

ONLINE DEMO

Here, you can use yy instead of uu but I prefer u to y.

Learn more about java.time, 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.

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1499770

That's because getRawOffset() is returning 0 - it does that for me for "ET" as well, and in fact TimeZone.getTimeZone("ET") basically returns GMT. I suspect that's not what you meant.

The best Olson time zone name for North Carolina is "America/New_York", I believe.

Note that you shouldn't just add the raw offset of a time zone to a UTC time - you should set the time zone of the formatter instead. A Date value doesn't really know about a time zone... it's always just milliseconds since January 1st 1970 UTC.

So you can use:

import java.text.; import java.util.;

Date date = new Date();
DateFormat format = new SimpleDateFormat("dd/MM/yy h:mm a zzz");

format.setTimeZone(TimeZone.getTimeZone("America/New_York"));
System.out.println("Eastern: " + format.format(date));

format.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
System.out.println("UTC: " + format.format(date));

Output:

Eastern: 11/05/11 11:30 AM EDT
UTC: 11/05/11 3:30 PM UTC

I'd also recommend that you look into using java.time now - which is much, mnuch better than the java.util classes.

Upvotes: 7

Michael
Michael

Reputation: 35331

The proper abbreviation for Eastern Standard Time is "EST", not "ET". It looks like the getRawOffset() method returns 0 if it is passed an unknown time zone.

TimeZone.getTimeZone("EST").getRawOffset()

Also, when you output the utcTime variable, you are not outputting the UTC time. You are outputting EST time because you live in that timezone. From what I understand, the Date class internally stores the time in UTC...but when you format it in order to output it as a human-readable string, it takes the current locale/timezone into account.

Upvotes: 1

Adrian
Adrian

Reputation: 46413

The time zone you're looking for is "EST" or "EDT" (for Daylight time), not "ET". See http://mindprod.com/jgloss/timezone.html.

Upvotes: 1

VirtualTroll
VirtualTroll

Reputation: 3091

TimeZone.getTimeZone("ET").getRawOffset() is returning 0 this is why

Upvotes: 1

Reporter
Reporter

Reputation: 3948

according this post you habe to write TimeZone.getTimeZone("ETS") instead of TimeZone.getTimeZone("ET")

Upvotes: 1

Related Questions