Sarthak Sahu
Sarthak Sahu

Reputation: 57

How to manage time zones across multiple systems in java?

I have a web application that returns a booking time based on the country where the event was performed.

Eg: If the booking was created in India at 02-JUNE-2020 1700 IST,then time returned is:

2020-06-02T17:00:00+0530

If the booking was created in Thailand at 02-JUNE-2020 1700 Thai Time,then time returned is:

2020-06-02T17:00:00+0700  

Now I have to store all this in a system in UK time,so the data would be:
for India,in UK system: 2020-06-02T12:30:00+0100
for Thailand,in UK system: 2020-06-02T11:00:00+0100

I know I can use the zone indicator of +0530 to convert to milliseconds offset by using

TimeZone.getAvailableIDs(milliseconds);

and find the corresponding timezone to do a reverse integration.
But is there an easy way to translate the IST to UK time directly in java ?

Upvotes: 1

Views: 719

Answers (3)

Arvind Kumar Avinash
Arvind Kumar Avinash

Reputation: 79015

But is there an easy way to translate the IST to UK time directly in java ?

TL;DR

Yes, you can use ZonedDateTime#withZoneSameInstant for this purpose.

ZonedDateTime.of(
    LocalDate.of(2020, 6, 2), 
    LocalTime.of(17, 0), 
    ZoneId.of("Asia/Kolkata")
).withZoneSameInstant(ZoneId.of("Europe/London"))

java.time

In March 2014, Java 8 introduced the modern, java.time date-time API which supplanted the error-prone legacy, java.util date-time API. The new code should use the java.time API. Whenever there is an opportunity to update the old code with legacy date-time API, one should switch to the java.time API by converting the java.util.Date into java.time.Instant, using Date#toInstant. Other date-time classes of java.time can be derived from java.time.Instant easily.

Note that TimeZone is a java.util date-time API and you should stop using it.

Avoid using abbreviated ID for time zone

Below is an excerpt from a very old documentation:

Three-letter time zone IDs

For compatibility with JDK 1.1.x, some other three-letter time zone IDs (such as "PST", "CTT", "AST") are also supported. However, their use is deprecated because the same abbreviation is often used for multiple time zones (for example, "CST" could be U.S. "Central Standard Time" and "China Standard Time"), and the Java platform can then only recognize one of them.

Demo:

public class Main {
    public static void main(String[] args) {
        // A sample date-time in ZoneId.of("Asia/Kolkata")
        ZonedDateTime zdtIndia = ZonedDateTime.of(
                LocalDate.of(2020, 6, 2),
                LocalTime.of(17, 0),
                ZoneId.of("Asia/Kolkata"));
        System.out.println(zdtIndia);

        // Convert it to corresponding date-time in ZoneId.of("Europe/London")
        ZonedDateTime zdtUK = zdtIndia.withZoneSameInstant(
                ZoneId.of("Europe/London"));
        System.out.println(zdtUK);
    }
}

Output:

2020-06-02T17:00+05:30[Asia/Kolkata]
2020-06-02T12:30+01:00[Europe/London]

Online Demo

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

Upvotes: 1

user15117826
user15117826

Reputation: 84

Try java.text.DateFormat.

jshell> java.text.DateFormat sdf = new java.text.SimpleDateFormat("dd-MM-yyyy'T'HH:mmZ")

jshell> Date d = new java.util.Date();
d ==> Sun Sep 29 17:29:33 IST 2024

jshell> sdf.setTimeZone(TimeZone.getTimeZone("EST"))

jshell> sdf.format(d)
$47 ==> "29-09-2024T06:59-0500"

jshell> sdf.setTimeZone(TimeZone.getTimeZone("GMT"))

jshell> sdf.format(d)
$49 ==> "29-09-2024T11:59+0000"

Date formatter can also parse a date value string in the specified format and convert it to Date object.

Upvotes: -1

rzwitserloot
rzwitserloot

Reputation: 102830

+0530 is not actually indicative of any particular time zone. A time zone could be, say, Europe/Amsterdam. This is +0100 in winter and +0200 in summer, and the zone Europe/Paris has the exact same offset at the exact same dates. Whilst unlikely, it is entirely possible that 5 years from now this is no longer the case. Note that +0100 does not accurately describe Europe/Amsterdam (it'd be wrong in summer), and cannot disambiguate between amsterdam and paris, which is why it's not good enough, generally. If this is just what you've been given and you can't change it, yea, getAvailableIDs is one way to at least attempt to convert +0530 into a zone, but note that usually you get many answers, so I don't know how you'd figure out how to pick the 'right' zone. Consider changing the system so that you get this timezone, the full ID, as part of the input instead.

Let's say you have obtained the zone, somehow.

Given 2020-06-02T17:00:00+0530 - you can translate this to the exact moment in time that the event being described by this timestamp has/will occur. That's presumably important; if you want an alarm to go off at that time anywhere on the planet you can now make that happen. That you store this 'in UK time' is just an implementation detail, that doesn't matter: You're storing the instant in time this event occurs, and not the way the human-oriented system that created this timestamp would refer to it (which is, presumably: '5 in the evening, on the second of june in 2020, in india').

But, you indicate a need to convert back from this 'exact instant in time' back to the zoned time.

Why?

If the answer is: So that it is familiar to the human, because the human I will end up printing this string to is definitely in india, you potentially have some issues if you go with the not-human-relevant zone ID of '+0530'; you optimally want to go with the more human-relevant zone ID of 'Asia/Kolkata', for example.

Okay, and now in java please!

an instant in time is best represented with an instance of java.time.Instant. This has no timezone info; it just marks a moment in time. (internally it stores as UTC, but that is an implementation detail. these things are timezoneless).

Once you have an Instant, and you have a TimeZone, you can do:

Instant x = ....; // obtain an instance somehow.
ZoneId zone = ZoneId.of("Asia/Kolkata"); // get a zone somehow.
ZonedDateTime zdt = x.atZone(zone);

You can print a zdt, for example with a java.time.format.DateTimeFormatter instance, and it'll render it as somebody in india would prefer.

If you have instead stored, say, a string containing the text 2020-06-02T12:30:00+0100, you can go from there to an instant rather easily, and then you can .atZone your way back to indian time.

Upvotes: 2

Related Questions