예제 #1
0
 /**
  * Obtains an instance defining a transition between two offsets.
  *
  * <p>Applications should normally obtain an instance from {@link ZoneRules}. This factory is only
  * intended for use when creating {@link ZoneRules}.
  *
  * @param transition the transition date-time at the transition, which never actually occurs,
  *     expressed local to the before offset, not null
  * @param offsetBefore the offset before the transition, not null
  * @param offsetAfter the offset at and after the transition, not null
  * @return the transition, not null
  * @throws IllegalArgumentException if {@code offsetBefore} and {@code offsetAfter} are equal, or
  *     {@code transition.getNano()} returns non-zero value
  */
 public static ZoneOffsetTransition of(
     LocalDateTime transition, ZoneOffset offsetBefore, ZoneOffset offsetAfter) {
   Objects.requireNonNull(transition, "transition");
   Objects.requireNonNull(offsetBefore, "offsetBefore");
   Objects.requireNonNull(offsetAfter, "offsetAfter");
   if (offsetBefore.equals(offsetAfter)) {
     throw new IllegalArgumentException("Offsets must not be equal");
   }
   if (transition.getNano() != 0) {
     throw new IllegalArgumentException("Nano-of-second must be zero");
   }
   return new ZoneOffsetTransition(transition, offsetBefore, offsetAfter);
 }
예제 #2
0
 /**
  * Obtains an instance of {@code ZoneOffset} from a temporal object.
  *
  * <p>This obtains an offset based on the specified temporal. A {@code TemporalAccessor}
  * represents an arbitrary set of date and time information, which this factory converts to an
  * instance of {@code ZoneOffset}.
  *
  * <p>A {@code TemporalAccessor} represents some form of date and time information. This factory
  * converts the arbitrary temporal object to an instance of {@code ZoneOffset}.
  *
  * <p>The conversion uses the {@link TemporalQueries#offset()} query, which relies on extracting
  * the {@link ChronoField#OFFSET_SECONDS OFFSET_SECONDS} field.
  *
  * <p>This method matches the signature of the functional interface {@link TemporalQuery} allowing
  * it to be used in queries via method reference, {@code ZoneOffset::from}.
  *
  * @param temporal the temporal object to convert, not null
  * @return the zone-offset, not null
  * @throws DateTimeException if unable to convert to an {@code ZoneOffset}
  */
 public static ZoneOffset from(TemporalAccessor temporal) {
   Objects.requireNonNull(temporal, "temporal");
   ZoneOffset offset = temporal.query(TemporalQueries.offset());
   if (offset == null) {
     throw new DateTimeException(
         "Unable to obtain ZoneOffset from TemporalAccessor: "
             + temporal
             + " of type "
             + temporal.getClass().getName());
   }
   return offset;
 }
예제 #3
0
  /**
   * Obtains an instance of {@code ZoneOffset} using the ID.
   *
   * <p>This method parses the string ID of a {@code ZoneOffset} to return an instance. The parsing
   * accepts all the formats generated by {@link #getId()}, plus some additional formats:
   *
   * <ul>
   *   <li>{@code Z} - for UTC
   *   <li>{@code +h}
   *   <li>{@code +hh}
   *   <li>{@code +hh:mm}
   *   <li>{@code -hh:mm}
   *   <li>{@code +hhmm}
   *   <li>{@code -hhmm}
   *   <li>{@code +hh:mm:ss}
   *   <li>{@code -hh:mm:ss}
   *   <li>{@code +hhmmss}
   *   <li>{@code -hhmmss}
   * </ul>
   *
   * Note that &plusmn; means either the plus or minus symbol.
   *
   * <p>The ID of the returned offset will be normalized to one of the formats described by {@link
   * #getId()}.
   *
   * <p>The maximum supported range is from +18:00 to -18:00 inclusive.
   *
   * @param offsetId the offset ID, not null
   * @return the zone-offset, not null
   * @throws DateTimeException if the offset ID is invalid
   */
  @SuppressWarnings("fallthrough")
  public static ZoneOffset of(String offsetId) {
    Objects.requireNonNull(offsetId, "offsetId");
    // "Z" is always in the cache
    ZoneOffset offset = ID_CACHE.get(offsetId);
    if (offset != null) {
      return offset;
    }

    // parse - +h, +hh, +hhmm, +hh:mm, +hhmmss, +hh:mm:ss
    final int hours, minutes, seconds;
    switch (offsetId.length()) {
      case 2:
        offsetId = offsetId.charAt(0) + "0" + offsetId.charAt(1); // fallthru
      case 3:
        hours = parseNumber(offsetId, 1, false);
        minutes = 0;
        seconds = 0;
        break;
      case 5:
        hours = parseNumber(offsetId, 1, false);
        minutes = parseNumber(offsetId, 3, false);
        seconds = 0;
        break;
      case 6:
        hours = parseNumber(offsetId, 1, false);
        minutes = parseNumber(offsetId, 4, true);
        seconds = 0;
        break;
      case 7:
        hours = parseNumber(offsetId, 1, false);
        minutes = parseNumber(offsetId, 3, false);
        seconds = parseNumber(offsetId, 5, false);
        break;
      case 9:
        hours = parseNumber(offsetId, 1, false);
        minutes = parseNumber(offsetId, 4, true);
        seconds = parseNumber(offsetId, 7, true);
        break;
      default:
        throw new DateTimeException("Invalid ID for ZoneOffset, invalid format: " + offsetId);
    }
    char first = offsetId.charAt(0);
    if (first != '+' && first != '-') {
      throw new DateTimeException(
          "Invalid ID for ZoneOffset, plus/minus not found when expected: " + offsetId);
    }
    if (first == '-') {
      return ofHoursMinutesSeconds(-hours, -minutes, -seconds);
    } else {
      return ofHoursMinutesSeconds(hours, minutes, seconds);
    }
  }
예제 #4
0
  /**
   * Loads and processes the Hijrah calendar properties file for this calendarType. The starting
   * Hijrah date and the corresponding ISO date are extracted and used to calculate the epochDate
   * offset. The version number is identified and ignored. Everything else is the data for a year
   * with containing the length of each of 12 months.
   *
   * @throws DateTimeException if initialization of the calendar data from the resource fails
   */
  private void loadCalendarData() {
    try {
      String resourceName = calendarProperties.getProperty(PROP_PREFIX + typeId);
      Objects.requireNonNull(
          resourceName, "Resource missing for calendar: " + PROP_PREFIX + typeId);
      Properties props = readConfigProperties(resourceName);

      Map<Integer, int[]> years = new HashMap<>();
      int minYear = Integer.MAX_VALUE;
      int maxYear = Integer.MIN_VALUE;
      String id = null;
      String type = null;
      String version = null;
      int isoStart = 0;
      for (Map.Entry<Object, Object> entry : props.entrySet()) {
        String key = (String) entry.getKey();
        switch (key) {
          case KEY_ID:
            id = (String) entry.getValue();
            break;
          case KEY_TYPE:
            type = (String) entry.getValue();
            break;
          case KEY_VERSION:
            version = (String) entry.getValue();
            break;
          case KEY_ISO_START:
            {
              int[] ymd = parseYMD((String) entry.getValue());
              isoStart = (int) LocalDate.of(ymd[0], ymd[1], ymd[2]).toEpochDay();
              break;
            }
          default:
            try {
              // Everything else is either a year or invalid
              int year = Integer.valueOf(key);
              int[] months = parseMonths((String) entry.getValue());
              years.put(year, months);
              maxYear = Math.max(maxYear, year);
              minYear = Math.min(minYear, year);
            } catch (NumberFormatException nfe) {
              throw new IllegalArgumentException("bad key: " + key);
            }
        }
      }

      if (!getId().equals(id)) {
        throw new IllegalArgumentException("Configuration is for a different calendar: " + id);
      }
      if (!getCalendarType().equals(type)) {
        throw new IllegalArgumentException(
            "Configuration is for a different calendar type: " + type);
      }
      if (version == null || version.isEmpty()) {
        throw new IllegalArgumentException("Configuration does not contain a version");
      }
      if (isoStart == 0) {
        throw new IllegalArgumentException("Configuration does not contain a ISO start date");
      }

      // Now create and validate the array of epochDays indexed by epochMonth
      hijrahStartEpochMonth = minYear * 12;
      minEpochDay = isoStart;
      hijrahEpochMonthStartDays = createEpochMonths(minEpochDay, minYear, maxYear, years);
      maxEpochDay = hijrahEpochMonthStartDays[hijrahEpochMonthStartDays.length - 1];

      // Compute the min and max year length in days.
      for (int year = minYear; year < maxYear; year++) {
        int length = getYearLength(year);
        minYearLength = Math.min(minYearLength, length);
        maxYearLength = Math.max(maxYearLength, length);
      }
    } catch (Exception ex) {
      // Log error and throw a DateTimeException
      PlatformLogger logger = PlatformLogger.getLogger("j86.java.time.chrono");
      logger.severe("Unable to initialize Hijrah calendar proxy: " + typeId, ex);
      throw new DateTimeException("Unable to initialize HijrahCalendar: " + typeId, ex);
    }
  }