Get time zones using a specific offset for a given moment, in Java

59 Views Asked by At

I know:

  • An offset is merely a number of hours-minutes-seconds ahead/behind the temporal meridian of UTC.
  • A time zone is a named history of the past, present, and future changes to the offset used by the people of a specific region, as determined by their politicians.

So for any moment, a particular time zone is using one offset while in another moment that same time zone may be using a different offset.

And, of course, any number of time zones may share the same offset at any one point in time.

Is there a way to obtain a list of time zones using a particular offset at a particular moment?

1

There are 1 best solutions below

0
Basil Bourque On

tl;dr

Instant now = Instant.now ( );
ZoneOffset offsetTarget = ZoneOffset.ofHours ( -4 );  // -04:00

List < ZoneId > zoneIdsWithTargetOffset =
        ZoneId
                .getAvailableZoneIds ( )  // Returns List<String>, not List<ZoneId>. Text is in format: Continent/Region.
                .stream ( )
                .map ( ZoneId :: of )     // Make a `ZoneId` object of each `String` zone name, each Continent/Region. 
                .filter (
                        ( ZoneId zoneId ) -> zoneId.getRules ( ).getOffset ( now ).equals ( offsetTarget )  // Get the offset in effect for that zone at that moment. See if that offset matches our target offset. 
                )
                .toList ()                // Collect `ZoneId` objects.
;

Details

Yes, you can get such a list in Java 8+ using the java.time classes.

The ZoneId class represents each time zone, with a name in the format of Continent/Region. The rules in use by each time zone are contained in a ZoneRules object.

The ZoneOffset class represents a mere offset.

The Instant class represents a moment, a specific point on the time line, as seen with an offset of zero hours-minutes-seconds from UTC. To get the current moment, call Instant.now().

We can interrogate the zone rules for the offset in use by a zone at any particular moment. This means getting a ZoneId by its name, asking for its rules, and the passing an Instant to the getOffset method of the rules object.

final Instant now = Instant.now ( );
final ZoneOffset offsetTarget = ZoneOffset.ofHours ( -4 );  // -04:00

final Set < String > zoneNames = ZoneId.getAvailableZoneIds ( );
final Collection < ZoneId > zoneIdsWithTargetOffset = new ArrayList <> ( );
for ( String zoneName : zoneNames )
{
    ZoneId zoneId = ZoneId.of ( zoneName );
    ZoneRules rules = zoneId.getRules ( );
    ZoneOffset offset = rules.getOffset ( now );
    if ( offset.equals ( offsetTarget ) )
    {
        zoneIdsWithTargetOffset.add ( zoneId );
    }
}
System.out.println ( "At " + now + ", " + zoneIdsWithTargetOffset.size ( ) + " zones have an offset of " + offsetTarget + " ➡️ " + zoneIdsWithTargetOffset ); // ️

See this code run at Ideone.com.

At 2023-11-21T21:59:37.279097Z, 43 zones have an offset of -04:00 ➡️ [America/Cuiaba, America/Marigot, Canada/Atlantic, Etc/GMT+4, America/Manaus, America/St_Thomas, America/Anguilla, America/Barbados, America/Curacao, America/Guyana, America/Martinique, America/Puerto_Rico, America/Port_of_Spain, SystemV/AST4, America/Kralendijk, America/Antigua, America/Moncton, America/St_Vincent, America/Dominica, Atlantic/Bermuda, Brazil/West, America/Aruba, America/Halifax, America/La_Paz, America/Blanc-Sablon, America/Santo_Domingo, America/Glace_Bay, America/St_Barthelemy, America/St_Lucia, America/Montserrat, America/Lower_Princes, America/Thule, America/Tortola, America/Porto_Velho, America/Campo_Grande, America/Goose_Bay, America/Virgin, America/Boa_Vista, America/Grenada, America/St_Kitts, America/Caracas, America/Guadeloupe, SystemV/AST4ADT]

Beware: Politicians frequently change the rules of the time zone(s) within their jurisdiction. They sometimes make those changes with an alarming lack of forewarning. Be sure the tzdata within your JVM is current for the time zones of interest to you. You may need to update the tzdata yourself, as new versions arrive faster than updates to Java.