ZetCode

Java ZoneRulesProvider Class

Last modified: April 16, 2025

The java.time.zone.ZoneRulesProvider class provides time-zone rules to the system. It acts as a service provider for time-zone rules. The class is abstract and must be subclassed to provide custom time-zone rules.

ZoneRulesProvider manages the available time-zone IDs and their rules. The default provider uses the IANA Time Zone Database. Multiple providers can be registered, with later registrations taking precedence.

ZoneRulesProvider Class Overview

ZoneRulesProvider provides methods to register providers and access time-zone rules. Key operations include getting available zone IDs and rules for specific zones. The class is thread-safe and designed for extension.

public abstract class ZoneRulesProvider {
    public static Set<String> getAvailableZoneIds();
    public static ZoneRules getRules(String zoneId, boolean forCaching);
    public static void registerProvider(ZoneRulesProvider provider);
    public static void registerProvider(ZoneRulesProvider provider, int priority);
    protected abstract Set<String> provideZoneIds();
    protected abstract ZoneRules provideRules(String zoneId, boolean forCaching);
    protected abstract NavigableMap<String, ZoneRules> provideVersions(String zoneId);
}

The code above shows key methods of ZoneRulesProvider. Abstract methods must be implemented by concrete providers. The class supports versioned time-zone rules through the provideVersions method.

Getting Available Time-Zone IDs

The getAvailableZoneIds method returns all available time-zone IDs from all registered providers. This is useful for discovering what time-zones are supported by the system.

Main.java
package com.zetcode;

import java.time.zone.ZoneRulesProvider;
import java.util.Set;

public class Main {

    public static void main(String[] args) {
        
        Set<String> zoneIds = ZoneRulesProvider.getAvailableZoneIds();
        
        System.out.println("Total zones available: " + zoneIds.size());
        System.out.println("First 5 zones:");
        
        zoneIds.stream()
               .limit(5)
               .forEach(System.out::println);
    }
}

This example retrieves all available time-zone IDs and prints the total count. It then displays the first five zone IDs. The output will vary based on the registered providers and Java version.

Getting Rules for a Specific Time-Zone

The getRules method retrieves the rules for a specific time-zone. These rules include transitions, offsets, and daylight savings information.

Main.java
package com.zetcode;

import java.time.zone.ZoneRules;
import java.time.zone.ZoneRulesProvider;

public class Main {

    public static void main(String[] args) {
        
        String zoneId = "America/New_York";
        ZoneRules rules = ZoneRulesProvider.getRules(zoneId, false);
        
        System.out.println("Rules for " + zoneId + ":");
        System.out.println("Fixed offset: " + rules.isFixedOffset());
        System.out.println("Standard offset: " + rules.getStandardOffset(
            java.time.Instant.now()));
        System.out.println("Daylight savings active now: " + 
            rules.isDaylightSavings(java.time.Instant.now()));
    }
}

This example retrieves the rules for New York timezone and prints some key properties. The output shows whether the zone has a fixed offset and current daylight savings status.

Creating a Custom ZoneRulesProvider

Custom providers can be created by extending ZoneRulesProvider. This allows adding support for custom time-zone rules not in the IANA database.

Main.java
package com.zetcode;

import java.time.zone.ZoneRules;
import java.time.zone.ZoneRulesProvider;
import java.util.Collections;
import java.util.NavigableMap;
import java.util.Set;
import java.time.Instant;
import java.time.ZoneOffset;

public class CustomZoneProvider extends ZoneRulesProvider {

    @Override
    protected Set<String> provideZoneIds() {
        return Collections.singleton("CUSTOM/UTC+2");
    }

    @Override
    protected ZoneRules provideRules(String zoneId, boolean forCaching) {
        if ("CUSTOM/UTC+2".equals(zoneId)) {
            return ZoneRules.of(ZoneOffset.ofHours(2));
        }
        return null;
    }

    @Override
    protected NavigableMap<String, ZoneRules> provideVersions(String zoneId) {
        return null;
    }
}

public class Main {
    public static void main(String[] args) {
        ZoneRulesProvider.registerProvider(new CustomZoneProvider());
        
        ZoneRules rules = ZoneRulesProvider.getRules("CUSTOM/UTC+2", false);
        System.out.println("Custom zone offset: " + 
            rules.getOffset(Instant.now()));
    }
}

This example creates a custom provider for a simple fixed-offset timezone. The provider is registered and then used to get rules for the custom zone. Note that real-world providers would handle more complex scenarios.

Registering Multiple Providers

Multiple providers can be registered with different priorities. Higher priority providers are checked first when resolving time-zone rules.

Main.java
package com.zetcode;

import java.time.zone.ZoneRules;
import java.time.zone.ZoneRulesProvider;
import java.util.Collections;
import java.util.NavigableMap;
import java.util.Set;
import java.time.Instant;
import java.time.ZoneOffset;

class HighPriorityProvider extends ZoneRulesProvider {
    @Override protected Set<String> provideZoneIds() {
        return Collections.singleton("PRIORITY/TEST");
    }
    @Override protected ZoneRules provideRules(String zoneId, boolean forCaching) {
        return ZoneRules.of(ZoneOffset.ofHours(3));
    }
    @Override protected NavigableMap<String, ZoneRules> provideVersions(String zoneId) {
        return null;
    }
}

class LowPriorityProvider extends ZoneRulesProvider {
    @Override protected Set<String> provideZoneIds() {
        return Collections.singleton("PRIORITY/TEST");
    }
    @Override protected ZoneRules provideRules(String zoneId, boolean forCaching) {
        return ZoneRules.of(ZoneOffset.ofHours(4));
    }
    @Override protected NavigableMap<String, ZoneRules> provideVersions(String zoneId) {
        return null;
    }
}

public class Main {
    public static void main(String[] args) {
        ZoneRulesProvider.registerProvider(new LowPriorityProvider(), 1);
        ZoneRulesProvider.registerProvider(new HighPriorityProvider(), 2);
        
        ZoneRules rules = ZoneRulesProvider.getRules("PRIORITY/TEST", false);
        System.out.println("Effective offset: " + 
            rules.getOffset(Instant.now())); // Will show +03:00
    }
}

This example demonstrates provider priority. The high priority provider's rules take precedence. The output shows the offset from the higher priority provider.

Checking Provider Registration

While there's no direct API to list registered providers, we can infer their presence by checking available zone IDs and rule behavior.

Main.java
package com.zetcode;

import java.time.zone.ZoneRulesProvider;
import java.util.Set;

public class Main {

    public static void main(String[] args) {
        
        // Count zones before registration
        Set<String> beforeIds = ZoneRulesProvider.getAvailableZoneIds();
        System.out.println("Zones before: " + beforeIds.size());
        
        // Register a custom provider
        ZoneRulesProvider.registerProvider(new CustomZoneProvider());
        
        // Count zones after registration
        Set<String> afterIds = ZoneRulesProvider.getAvailableZoneIds();
        System.out.println("Zones after: " + afterIds.size());
        
        // Check if our custom zone is available
        if (afterIds.contains("CUSTOM/UTC+2")) {
            System.out.println("Custom provider is active");
        }
    }
    
    static class CustomZoneProvider extends ZoneRulesProvider {
        @Override protected Set<String> provideZoneIds() {
            return Set.of("CUSTOM/UTC+2");
        }
        @Override protected ZoneRules provideRules(String zoneId, boolean forCaching) {
            return null;
        }
        @Override protected NavigableMap<String, ZoneRules> provideVersions(String zoneId) {
            return null;
        }
    }
}

This example checks provider registration indirectly by comparing zone ID sets. It shows how to verify that a custom provider has been successfully registered.

Handling Time-Zone Versions

The provideVersions method allows providers to support multiple versions of time-zone rules. This is useful for historical accuracy.

Main.java
package com.zetcode;

import java.time.zone.ZoneRules;
import java.time.zone.ZoneRulesProvider;
import java.util.NavigableMap;
import java.util.Set;
import java.util.TreeMap;
import java.time.Instant;
import java.time.ZoneOffset;

public class VersionedZoneProvider extends ZoneRulesProvider {

    @Override
    protected Set<String> provideZoneIds() {
        return Set.of("VERSIONED/TEST");
    }

    @Override
    protected ZoneRules provideRules(String zoneId, boolean forCaching) {
        return ZoneRules.of(ZoneOffset.ofHours(2));
    }

    @Override
    protected NavigableMap<String, ZoneRules> provideVersions(String zoneId) {
        if ("VERSIONED/TEST".equals(zoneId)) {
            NavigableMap<String, ZoneRules> versions = new TreeMap<>();
            versions.put("2023", ZoneRules.of(ZoneOffset.ofHours(2)));
            versions.put("2024", ZoneRules.of(ZoneOffset.ofHours(3)));
            return versions;
        }
        return null;
    }
}

public class Main {
    public static void main(String[] args) {
        ZoneRulesProvider.registerProvider(new VersionedZoneProvider());
        
        NavigableMap<String, ZoneRules> versions = 
            ZoneRulesProvider.getVersions("VERSIONED/TEST");
        System.out.println("Available versions: " + versions.keySet());
    }
}

This example creates a provider with versioned rules. The provideVersions method returns different rules for different years. Note that the standard Java API doesn't directly use these versions.

Source

Java ZoneRulesProvider Class Documentation

In this article, we've covered the essential methods and features of the Java ZoneRulesProvider class. Understanding these concepts is crucial for advanced time-zone handling in Java applications.

Author

My name is Jan Bodnar, and I am a dedicated programmer with many years of experience in the field. I began writing programming articles in 2007 and have since authored over 1,400 articles and eight e-books. With more than eight years of teaching experience, I am committed to sharing my knowledge and helping others master programming concepts.

List all Java tutorials.