首页 > 解决方案 > Why is the time difference off when subtracting the same date from two different time zones?

问题描述

The following is an example that attempts to calculate the difference in hours between time zones.

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

public class ForPosting
{
   public static void main (String[] args)
   {
       try {
               String myDateString = "07-13-2021 11:00:00";
        
               SimpleDateFormat localDateTime = new SimpleDateFormat("MM-dd-yyyy HH:mm:ss");
               SimpleDateFormat utcDateTime = new SimpleDateFormat("MM-dd-yyyy HH:mm:ss");
               
               localDateTime.setTimeZone(TimeZone.getTimeZone("EET"));
               System.out.println(localDateTime.parse(myDateString));
               
               utcDateTime.setTimeZone(TimeZone.getTimeZone("UTC"));
               System.out.println(utcDateTime.parse(myDateString));
               float diff = ((localDateTime.parse(myDateString).getTime() - utcDateTime.parse(myDateString).getTime() ) / 3600000);
               System.out.println("EET & UTC Time Difference : " +  diff);

               localDateTime.setTimeZone(TimeZone.getDefault());
               System.out.println(localDateTime.parse(myDateString));
               
               utcDateTime.setTimeZone(TimeZone.getTimeZone("UTC"));
               System.out.println(utcDateTime.parse(myDateString));
               diff = ((localDateTime.parse(myDateString).getTime() - utcDateTime.parse(myDateString).getTime() ) / 3600000);
               System.out.println("Default & UTC Time Difference : " +  diff);
               
               
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
   }
} 

The above code generates the following output.

enter image description here

The Default & UTC Time Difference : 4.0 was confirmed by checking the current dates and it confirms there is a 4 hour difference.

enter image description here enter image description here

Doing the same check for EET & UTC is different.

EET & UTC Time Difference : -3.0

The output shows a 3 hour difference yet the following shows there is only 2.

enter image description here enter image description here

Why does the EET & UTC actual time show 2 hour difference yet the Java code shows a 3 hour difference?

标签: javatimezone

解决方案


EET is not a time zone

EET is a common abbreviation of some 20 time zones in Europe and Northern Africa that are at offset +02:00 from UTC during standard time. Many, not all of them are using summer time (daylight saving time) abbreviated EEST for Eastern European Summer Time and hence are at offset +03:00 during the 7 “summer” months. So what you get when asking for EET, I can’t tell. So don’t do that. Use a proper time zone ID like Europe/Uzhgorod, always in region/city format. So that you know what you get.

So to answer your question:

Why does the EET & UTC actual time show 2 hour difference yet the Java code shows a 3 hour difference?

Because they interpret EET differently. Both interpretations are fully valid and none is authoritative.

This is nothing special for EET. Many two, three, four and five letter time zone abbreviations are in common use. Very many of them are ambiguous, like EET. And very many of them are not time zones. It may be that there are situations where you can use one for informal communication to the user, for example just to distinguish between EET and EEST in a situation where the user knows well enough what each of those means in the context. You certainly cannot rely on them for defining a time zone in your program.

java.time

I recommend that you use java.time, the modern Java date and time API, for your date and time work. To find the difference between some time zone and UTC at a moment in time:

    ZoneId zone = ZoneId.of("Europe/Uzhgorod");
    Instant when = Instant.now();
    
    ZoneOffset differenceFromUtc = when.atZone(zone).getOffset();
    
    System.out.format("%s & UTC Time Difference : %s%n", zone, differenceFromUtc);

Output when running just now:

Europe/Uzhgorod & UTC Time Difference : +03:00

It’s summer now in Europe/Uzhgorod, and the difference of 3 hours comes from that time zone using summer time. Try with an instant in winter:

    Instant when = Instant.parse("2022-01-01T00:00:00Z");

Europe/Uzhgorod & UTC Time Difference : +02:00

As I said, some Eastern European time zones do not use summer time. Try with one of those:

    ZoneId zone = ZoneId.of("Europe/Kaliningrad");
    Instant when = Instant.now();

Europe/Kaliningrad & UTC Time Difference : +02:00

Minor comments to your code

While UTC works for defining a time zone, the canonical ID is Etc/UTC. Etc is a pseudo-region for time zones that don’t belong in a well-defined geographical region including Etc/UTC, Etc/GMT and also the IDs for mere whole-hour offsets like Etc/GMT-2 (for offset +02:00, the sign is inverted).

Assigning the result of your division to a float does not help you. You are dividing a long values by an int value, and the result is always truncated to an long number. When assigning to a float you will still always have a whole number. If you wanted a fraction as result, you would need to convert at least one of the operands to float (or double) before dividing.

And a funny detail, your code measures the difference in hours between when it’s 11 o’clock in EET and 11 o’clock in UTC. You get a result exactly because there are 3 hours between those two moments. What I am not so pleased about is that you are not measuring the difference at a well-defined point in time. Instead in my code I am choosing one point in time and finding the difference at that point.

Oracle tutorial: Date Time explaining how to use java.time.


推荐阅读