0

How to Convert a 2021-09-29T17:04:31.0000 +05:30 to 2021-09-29 17:04:31.0000000 Asia/Calcutta In Java?

and additional question is here- I tried many ways to get the timezone(Asia/Calcutta) from offset(+05:30) but unable to get. Can someone please help?

FObersteiner
  • 22,500
  • 8
  • 42
  • 72
Pravin Mangalam
  • 151
  • 1
  • 2
  • 8
  • 4
    You are unable to get the zone from the offset because an offset is just an offset from UTC, but it doesn't tell you where it is actually applied. A zone tells you where it is and which offset it uses and it even considers daylight saving time. That means you cannot derive a zone from an offset, but the other way round is possible. – deHaar Oct 05 '21 at 14:09
  • What is the situation? Can you explain more in detail if you always have to use the same time zone or offset, for example? More information in the question are likely to cause more information in comments and answers. Please share some... – deHaar Oct 05 '21 at 14:19
  • 3
    You can’t. +05:30 could just as well mean Asia/Colombo. For other offsets the list typically gets much longer. For example my current offset, +02:00, could mean Europe/Sarajevo, Africa/Khartoum, Africa/Cairo, Africa/Mbabane, Europe/Amsterdam, Europe/Tirane, Africa/Blantyre, Europe/Busingen, Europe/Zagreb, Europe/Brussels, Africa/Bujumbura, Europe/Rome, Antarctica/Troll, Europe/Podgorica, Europe/Andorra, Europe/Budapest, Europe/Skopje, Africa/Johannesburg, Europe/Vatican, Europe/Oslo, Africa/Windhoek, Europe/Ljubljana, Arctic/Longyearbyen, Atlantic/Jan_Mayen, Europ… (Too long by 403 characters) – Ole V.V. Oct 05 '21 at 15:26
  • You are right @OleV.V. In this situation How can I know the exact timezone – Pravin Mangalam Oct 05 '21 at 16:32
  • I am sorry to repeat: you can’t. @PravinMangalam Not from that string you’ve received. You may ask at the folks at the source which time zone they intended, of course, perhaps they know. – Ole V.V. Oct 05 '21 at 23:07
  • Another thing, are you sure there’s a space between `0000 ` and `+05:30` in `2021-09-29T17:04:31.0000 +05:30`? Asking because your string is in [ISO 8601 format](https://en.wikipedia.org/wiki/ISO_8601) except ISO 8601 does not allow that space. – Ole V.V. Oct 06 '21 at 17:49

3 Answers3

4

Since you cannot derive a zone from an offset (reliably), you may want to use a workaround / different approach.

Here's an example that parses the input String to an OffsetDateTime using a suitable DateTimeFormatter and then creates the desired ZoneId which it applies to the OffsetDateTime in order to create a ZonedDateTime.

public static void main(String[] args) {
    // your example input
    String offsetTime = "2021-09-29T17:04:31.0000 +05:30";
    // define a formatter that parses a String of this format
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSS xxx");
    // then parse it to an object that knows date, time and offset
    OffsetDateTime odt = OffsetDateTime.parse(offsetTime, dtf);
    // print the result
    System.out.println(odt);

    // now define the desired zone
    ZoneId asiaCalcutta = ZoneId.of("Asia/Calcutta");
    // and use the offset-aware object to apply the zone
    ZonedDateTime zdt = odt.atZoneSameInstant(asiaCalcutta);
    // print it
    System.out.println(zdt);
}

This outputs

2021-09-29T17:04:31+05:30
2021-09-29T17:04:31+05:30[Asia/Calcutta]

Please note: This will only keep the same offset if the offset and the zone actually match. I don't know your concrete requirements, so only you can know if this approach is appropriate in your situation or not.

If you want to find out time zones that currently use a specific offset and then make your code decide which is the correct one, you may want to have a look at this question and its answers.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
deHaar
  • 17,687
  • 10
  • 38
  • 51
  • I want take [Asia/Calcutta] from +05:30. This +05:30 could be any valid offset its dynamically coming. that is why I can not do like this ZoneId asiaCalcutta = ZoneId.of("Asia/Calcutta"); // and use the offset-aware object to apply the zone ZonedDateTime zdt = odt.atZoneSameInstant(asiaCalcutta); // print it System.out.println(zdt); – Pravin Mangalam Oct 05 '21 at 14:47
  • 1
    @PravinMangalam Then follow the link at the end of my answer – deHaar Oct 05 '21 at 15:17
  • 1
    Thanks Solved the issue final TimeZone timeZone = TimeZone.getTimeZone(time.getZone()); // String str = Arrays.stream(TimeZone.getAvailableIDs(timeZone.getRawOffset())).peek(System.out::println).findFirst().get(); This returns me the timezone as String and I need that to put below as param. ZoneId asiaCalcutta = ZoneId.of("Asia/Calcutta"); – Pravin Mangalam Oct 05 '21 at 16:29
  • 1
    @PravinMangalam For a string from Europe/Paris time zone (offset +02:00 in September) your solution gave me Africa/Algiers. Also I recommend you don’t use `TimeZone`. That class is poorly designed and long outdated. Stick to the modern `ZoneId` and `ZoneRules`. They give you all the functionality you need. – Ole V.V. Oct 07 '21 at 10:52
1

I tried to write this code to cover three possibilities String parameter , or LocalDateTime parameter and ZonedDateTime Parameter :

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

      public class SpecialFormater {

   // parameter : ZonedDateTime
   public static String specialFormaterZonedDateTime(ZonedDateTime zdt) {

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSS");
    ZoneId zid = zdt.getZone();
    System.out.println("Your initial format                =" + zdt);
    String result = "Your expected format               =" + zdt.format(formatter) + " " + zid;

    return result;
}
  // parameter : LocalDateTime
 public static String specialFormaterLocalDateTime(LocalDateTime dt) {

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSS");

    ZoneId zid = ZoneId.of("Asia/Calcutta");

    System.out.println("Your initial format                =" + dt);
    ZonedDateTime zdt = ZonedDateTime.of(dt, zid);
    System.out.println("Your zoned dateTime default format =" + zdt);
    String result = "Your expected format               =" + dt.format(formatter) + " " + zid;

    return result;
}

// Parameter : String
public static String specialFormaterString(String localDateTime) {
    System.out.println("String before formatting   =" + localDateTime);
    String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSS xxx";
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
    LocalDateTime dt = LocalDateTime.parse(localDateTime, formatter);
    ZoneId zid = ZoneId.of("Asia/Calcutta");

    DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSS");
    String result = "String after  formatting   =" + dt.format(formatter2) + " " + zid;
    return result;
}

public static void main(String[] args) {
System.out.println("specialFormaterLocalDateTime");
    System.out.println(specialFormaterLocalDateTime(LocalDateTime.now()));
    System.out.println("***********");
    System.out.println();
    System.out.println("specialFormaterString");
    System.out.println(specialFormaterString("2021-09-29T17:04:31.0000 +05:30"));
    System.out.println("**********");       
    System.out.println();
    System.out.println("specialFormaterZonedDateTime");
    System.out.println(specialFormaterZonedDateTime(ZonedDateTime.now()));
}
}

Output :

  specialFormaterLocalDateTime
  Your initial format                =2021-10-06T12:35:45.029
  Your zoned dateTime default format =2021-10-06T12:35:45.029+05:30[Asia/Calcutta]
  Your expected format               =2021-10-06 12:35:45.0290000 Asia/Calcutta
  ***********

  specialFormaterString
  String before formatting   =2021-09-29T17:04:31.0000 +05:30
  String after  formatting   =2021-09-29 17:04:31.0000000 Asia/Calcutta
  **********

  specialFormaterZonedDateTime
  Your initial format                =2021-10-06T12:35:45.064+02:00[Europe/Paris]
  Your expected format               =2021-10-06 12:35:45.0640000 Europe/Paris
Oussama ZAGHDOUD
  • 1,767
  • 5
  • 15
1

How to get just some time zone that matches the offset using java.time

I tend to understand from your comment under Arvind Kumar Avinash’ answer that you have solved it by simply taking the first time zone that has the correct offset (or what you thought was the correct offset). Of course java.time, the modern Java date and time API, can do that. I wanted to show you a way.

    String input = "2021-09-29T17:04:31.0000 +05:30";
    
    // Remove space and parse
    OffsetDateTime dateTime = OffsetDateTime.parse(input.replace(" ", ""));
    ZoneOffset offset = dateTime.getOffset();
    
    // Find and convert to a zone that matches the offset (there will usually be many)
    ZonedDateTime zonedDateTime = ZoneId.getAvailableZoneIds()
            .stream()
            .map(ZoneId::of)
            .map(dateTime::atZoneSameInstant)
            .filter(zdt -> zdt.getOffset().equals(offset))
            .findFirst()
            // If all else fails, use the offset as time zone
            .orElse(dateTime.atZoneSameInstant(offset));
    
    // Convert to 2021-09-29 17:04:31.0000000 Asia/Calcutta format
    String result = zonedDateTime.format(FORMATTER);
    
    System.out.println(result);

I have used this formatter for formatting the output:

private static final DateTimeFormatter FORMATTER
        = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSSSSS VV", Locale.ROOT);

And the output is (on my Java 11):

2021-09-29 17:04:31.000000 Asia/Kolkata

Asia/Kolkata is the present-day name for the time zone formerly known as Asia/Calcutta. Is that close enough?

In my code I have taken the case into account where no suitable time zone exists. Let’s see this with an offset that I don’t think is used in any real time zone:

    String input = "2021-10-06T18:54:31.0000 +00:30";

2021-10-06 18:54:31.000000 +00:30

If you didn’t want this, you will at least need to change the line with the call to orElse().

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • In my case this is also not suitable because I need timezone from offset and offset is not unique. Actual date On oracle - 28-OCT-2021 02:36:08 AM Europe/Paris I saved this in MSSQL DatetimeOffset as 2021-10-28T02:36:08.000 +02:00 Now I want to show on the screen as **2021-10-28T02:36:08.000 +02:00 Europe/Paris** But when I convert using your code I get this 2021-10-28 02:36:08.000000 Africa/Cairo Where timezone is not matching to my. – Pravin Mangalam Oct 07 '21 at 04:02
  • 1
    Exactly. That’s what I also meant by my previous comments. – Ole V.V. Oct 07 '21 at 09:35
  • 1
    Sorry to say, but then your just found a flaw in your architecture: MySQL doesn't store all the data needed. Now you have to find out if it's possible to store the zone in any suitable datetime format of MySQL and if there is, then redesign your storage mechanism to also storing the zone. I think [this answer to a related question](https://stackoverflow.com/a/59004019/1712135) may be helpful here… – deHaar Oct 07 '21 at 09:36