jdk/src/share/classes/java/time/ZoneRegion.java
changeset 16852 60207b2b4b42
parent 15658 55b829ca2334
child 17474 8c100beabcc0
equal deleted inserted replaced
16851:3bbdae468b05 16852:60207b2b4b42
    93     /**
    93     /**
    94      * Serialization version.
    94      * Serialization version.
    95      */
    95      */
    96     private static final long serialVersionUID = 8386373296231747096L;
    96     private static final long serialVersionUID = 8386373296231747096L;
    97     /**
    97     /**
    98      * The regex pattern for region IDs.
       
    99      */
       
   100     private static final Pattern PATTERN = Pattern.compile("[A-Za-z][A-Za-z0-9~/._+-]+");
       
   101 
       
   102     /**
       
   103      * The time-zone ID, not null.
    98      * The time-zone ID, not null.
   104      */
    99      */
   105     private final String id;
   100     private final String id;
   106     /**
   101     /**
   107      * The time-zone rules, null if zone ID was loaded leniently.
   102      * The time-zone rules, null if zone ID was loaded leniently.
   108      */
   103      */
   109     private final transient ZoneRules rules;
   104     private final transient ZoneRules rules;
   110 
       
   111     /**
       
   112      * Obtains an instance of {@code ZoneRegion} from an identifier without checking
       
   113      * if the time-zone has available rules.
       
   114      * <p>
       
   115      * This method parses the ID and applies any appropriate normalization.
       
   116      * It does not validate the ID against the known set of IDs for which rules are available.
       
   117      * <p>
       
   118      * This method is intended for advanced use cases.
       
   119      * For example, consider a system that always retrieves time-zone rules from a remote server.
       
   120      * Using this factory would allow a {@code ZoneRegion}, and thus a {@code ZonedDateTime},
       
   121      * to be created without loading the rules from the remote server.
       
   122      *
       
   123      * @param zoneId  the time-zone ID, not null
       
   124      * @return the zone ID, not null
       
   125      * @throws DateTimeException if the ID format is invalid
       
   126      */
       
   127     private static ZoneRegion ofLenient(String zoneId) {
       
   128         return ofId(zoneId, false);
       
   129     }
       
   130 
   105 
   131     /**
   106     /**
   132      * Obtains an instance of {@code ZoneId} from an identifier.
   107      * Obtains an instance of {@code ZoneId} from an identifier.
   133      *
   108      *
   134      * @param zoneId  the time-zone ID, not null
   109      * @param zoneId  the time-zone ID, not null
   137      * @throws DateTimeException if the ID format is invalid
   112      * @throws DateTimeException if the ID format is invalid
   138      * @throws ZoneRulesException if checking availability and the ID cannot be found
   113      * @throws ZoneRulesException if checking availability and the ID cannot be found
   139      */
   114      */
   140     static ZoneRegion ofId(String zoneId, boolean checkAvailable) {
   115     static ZoneRegion ofId(String zoneId, boolean checkAvailable) {
   141         Objects.requireNonNull(zoneId, "zoneId");
   116         Objects.requireNonNull(zoneId, "zoneId");
   142         if (zoneId.length() < 2 ||
   117         checkName(zoneId);
   143                 zoneId.startsWith("UT") ||  // includes UTC
       
   144                 zoneId.startsWith("GMT") ||
       
   145                 (PATTERN.matcher(zoneId).matches() == false)) {
       
   146             throw new DateTimeException("Invalid ID for region-based ZoneId, invalid format: " + zoneId);
       
   147         }
       
   148         ZoneRules rules = null;
   118         ZoneRules rules = null;
   149         try {
   119         try {
   150             // always attempt load for better behavior after deserialization
   120             // always attempt load for better behavior after deserialization
   151             rules = ZoneRulesProvider.getRules(zoneId, true);
   121             rules = ZoneRulesProvider.getRules(zoneId, true);
   152         } catch (ZoneRulesException ex) {
   122         } catch (ZoneRulesException ex) {
   155             }
   125             }
   156         }
   126         }
   157         return new ZoneRegion(zoneId, rules);
   127         return new ZoneRegion(zoneId, rules);
   158     }
   128     }
   159 
   129 
       
   130     /**
       
   131      * Checks that the given string is a legal ZondId name.
       
   132      *
       
   133      * @param zoneId  the time-zone ID, not null
       
   134      * @throws DateTimeException if the ID format is invalid
       
   135      */
       
   136     private static void checkName(String zoneId) {
       
   137         int n = zoneId.length();
       
   138         if (n < 2) {
       
   139            throw new DateTimeException("Invalid ID for region-based ZoneId, invalid format: " + zoneId);
       
   140         }
       
   141         for (int i = 0; i < n; i++) {
       
   142             char c = zoneId.charAt(i);
       
   143             if (c >= 'a' && c <= 'z') continue;
       
   144             if (c >= 'A' && c <= 'Z') continue;
       
   145             if (c == '/' && i != 0) continue;
       
   146             if (c >= '0' && c <= '9' && i != 0) continue;
       
   147             if (c == '~' && i != 0) continue;
       
   148             if (c == '.' && i != 0) continue;
       
   149             if (c == '_' && i != 0) continue;
       
   150             if (c == '+' && i != 0) continue;
       
   151             if (c == '-' && i != 0) continue;
       
   152             throw new DateTimeException("Invalid ID for region-based ZoneId, invalid format: " + zoneId);
       
   153         }
       
   154     }
       
   155 
       
   156     /**
       
   157      * Obtains an instance of {@code ZoneId} wrapping an offset.
       
   158      * <p>
       
   159      * For example, zone IDs like 'UTC', 'GMT', 'UT' and 'UTC+01:30' will be setup here.
       
   160      *
       
   161      * @param zoneId  the time-zone ID, not null
       
   162      * @param offset  the offset, not null
       
   163      * @return the zone ID, not null
       
   164      */
       
   165     static ZoneRegion ofPrefixedOffset(String zoneId, ZoneOffset offset) {
       
   166         return new ZoneRegion(zoneId, offset.getRules());
       
   167     }
       
   168 
   160     //-------------------------------------------------------------------------
   169     //-------------------------------------------------------------------------
   161     /**
   170     /**
   162      * Constructor.
   171      * Constructor.
   163      *
   172      *
   164      * @param id  the time-zone ID, not null
   173      * @param id  the time-zone ID, not null
   216         out.writeUTF(id);
   225         out.writeUTF(id);
   217     }
   226     }
   218 
   227 
   219     static ZoneId readExternal(DataInput in) throws IOException {
   228     static ZoneId readExternal(DataInput in) throws IOException {
   220         String id = in.readUTF();
   229         String id = in.readUTF();
   221         return ofLenient(id);
   230         return ZoneId.of(id, false);
   222     }
   231     }
   223 
   232 
   224 }
   233 }