javadatedatetimetimezonetimezone-offset

Getting the TimeZoneIDs for a Time Zone


I am dealing with Time and Date in Java.

I am having date as : 2018-08-22T22:00:00-0500 My Time Zone offset here is -0500 How can I get the list of available Time Zone IDs?

My main objective here is to set a date to a particular Time Zone. However I do not know the time zone as it is embedded in this date format.

Update : My question is different from Java TimeZone offset as according to the accepted answer to that question, I need to have time zone info : "Europe/Oslo" . However I only have offset. See the accepted answer below which solves my problem.


Solution

  • tl;dr

    eachZoneId.getRules().getOffset(
        OffsetDateTime.parse( 
            "2018-08-22T22:00:00-0500" , 
            DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ssX" ) 
        ).toInstant()
    ).equals( myTargetZoneOffset )
    

    Offset versus Zone

    I do not know the time zone as it is embedded in this date format.

    No, your input string of 2018-08-22T22:00:00-0500 has no time zone. It has only a mere offset-from-UTC.

    An offset is simply a number of hours, minutes, and seconds of displacement ahead of, or behind, UTC. Yours shows an offset five hours behind UTC. In contrast, a time zone is a history of past, present, and future changes to the offset used by the people of a certain region.

    OffsetDateTime

    In java.time, we represent a moment with an offset as a OffsetDateTime class.

    Your input string is in standard ISO 8601 format. So we should be able to parse directly without specifying a formatting pattern, as the java.time classes use ISO 8601 formats by default when parsing/generating strings. However your input lacks a colon in the offset between hours and minutes. While allowed by the standard, the OffsetDateTime class a small bug in Java 8 & 9 that fails by default to parse such values. As a workaround, specify a DateTimeFormatter.

    String input = "2018-08-22T22:00:00-0500";
    DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ssX" );  // Specify formatting pattern to match input string.
    OffsetDateTime odt = OffsetDateTime.parse( input , f );  // Parse from dumb string to smart `OffsetDateTime` object.
    

    odt.toString(): 2018-08-22T22:00-05:00

    Time zone names

    How can I get the list of available Time Zone IDs?

    Not sure what you mean by “Time Zone IDs”. I am guessing that you are asking for a list of all the time zones using that particular offset-from-UTC at that particular moment.

    A proper time zone name has the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

    We represent the time zone using the ZoneId. The TimeZone class is now legacy, and should be avoided.

    To get our list of ZoneId objects with that offset in use on that date, we need to first extract the offset (ZoneOffset) from our OffsetDateTime.

    ZoneOffset offset = odt.getOffset() ;
    

    offset.toString(): -05:00

    Next phase is to interrogate all known time zones, asking each for the offset in effect at the moment of our OffsetDateTime. The argument for that moment must be in UTC, a Instant object. So we must extract an Instant from our OffsetDateTime. Still the same moment, the same point on the timeline, but seen through the lens of a different wall-clock time.

    Instant instant = odt.toInstant() ;  // Extract a UTC value (`Instant`) from our `OffsetDateTime` object.
    

    instant.toString(): 2018-08-23T03:00:00Z

    The Z on the end is short for Zulu and means UTC.

    Make an empty list to collect the desired zones.

    List< ZoneId > hits = new ArrayList<>() ;  // Make an empty list of `ZoneId` objects found to have our desired offset-from-UTC.
    

    Now get all known zones. A method exists giving a set of all zone names, but not the zone objects. So for each iteration we must instantiate the ZoneId. Then we ask the zone for its rules, the list of changes in effect over time for that region. To the rules we pass our moment (Instant), and get back the ZoneOffset in effect at that time. If this offset matches our target offset, we add the zone to our list.

    Be aware that many of the zones may be essentially duplicates or deprecated. The list of zones has had a fractured history, with many changes, and some are mere aliases to others.

        Set < String > names = ZoneId.getAvailableZoneIds();  // Get a collection of all known time zones’ names.
        for ( String name : names )                           // Loop each name.
        {
            ZoneId z = ZoneId.of( name );                     // Instantiate a `ZoneId` for that zone name.
            ZoneRules rules = z.getRules();                   // Get the history of past, present, and future changes in offset used by the people of this particular region (time zone).
            ZoneOffset o = rules.getOffset( instant );        // Get the offset-from-UTC in effect at this moment for the people of this region.
            if( o.equals( offset )) {                         // Compare this particular offset to see if it is the same number of hours, minutes, and seconds as our target offset.
                hits.add( z );                                // If we have a hit, add to our collection of `ZoneId` objects.
            }
        }
    

    Dump our hits collection to the console.

    [America/Panama, America/Chicago, America/Eirunepe, Etc/GMT+5, Pacific/Easter, Mexico/General, America/Porto_Acre, America/Guayaquil, America/Rankin_Inlet, US/Central, America/Rainy_River, America/Indiana/Knox, America/North_Dakota/Beulah, America/Monterrey, America/Jamaica, America/Atikokan, America/Coral_Harbour, America/North_Dakota/Center, America/Cayman, America/Indiana/Tell_City, Chile/EasterIsland, America/Mexico_City, America/Matamoros, CST6CDT, America/Knox_IN, America/Bogota, America/Menominee, America/Resolute, SystemV/EST5, Canada/Central, Brazil/Acre, America/Cancun, America/Lima, America/Bahia_Banderas, US/Indiana-Starke, America/Rio_Branco, SystemV/CST6CDT, Jamaica, America/Merida, America/North_Dakota/New_Salem, America/Winnipeg]

    Be aware that this list of zones is valid only for our chosen particular moment. In earlier times, or later times, some of these zones may be using some other offset-from-UTC. Conversely, at other moments some zones not on this list may be using our desired offset.


    About java.time

    The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

    The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

    To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

    You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

    Where to obtain the java.time classes?

    The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.