com.outerspacecat.icalendar.UtcOffsetType.java Source code

Java tutorial

Introduction

Here is the source code for com.outerspacecat.icalendar.UtcOffsetType.java

Source

/**
 * Copyright 2011 Caleb Richardson
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.outerspacecat.icalendar;

import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import java.io.Serializable;
import java.time.ZoneOffset;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.ThreadSafe;

/**
 * A representation of an iCalendar utc-offset type defined by <a
 * href="http://tools.ietf.org/html/rfc5545">RFC 5545</a>.
 * <p>
 * This class adds the additional restriction of requiring the offset to be
 * between -180000 and +180000, inclusive, to comply with
 * {@link java.time.ZoneOffset}.
 * 
 * @author Caleb Richardson
 */
@Immutable
@ThreadSafe
public final class UtcOffsetType implements HasICalendar, Serializable {
    private final static long serialVersionUID = 1L;

    private final static Pattern OFFSET_PATTERN = Pattern.compile("(\\-|\\+)(\\d\\d)(\\d\\d)(\\d\\d)?");

    public final static UtcOffsetType ZERO = new UtcOffsetType(false, 0, 0, 0);

    private final boolean negative;
    private final int hours;
    private final int minutes;
    private final int seconds;

    /**
     * Creates a new utc-offset. A negative zero utc-offset is not allowed
     * (-000000). The allowable range is -180000 to +180000, inclusive.
     * 
     * @param negative whether or not the utc-offset is negative
     * @param hours the hours of the utc-offset. Must be &gt;= 0 and &lt;= 18.
     * @param minutes the minutes of the utc-offset. Must be &gt;= 0 and &lt;= 59.
     * @param seconds the seconds of the utc-offset. Must be &gt;= 0 and &lt;= 59.
     */
    public UtcOffsetType(final boolean negative, final int hours, final int minutes, final int seconds) {
        Preconditions.checkArgument(hours >= 0 && hours <= 18, "invalid hours: " + hours);
        Preconditions.checkArgument(minutes >= 0 && minutes <= 59, "invalid minutes: " + minutes);
        Preconditions.checkArgument(seconds >= 0 && seconds <= 59, "invalid seconds: " + seconds);

        if (negative && hours == 0 && minutes == 0 && seconds == 0)
            throw new IllegalArgumentException("cannot have negative zero utc-offset");

        int totalSeconds = hours * 3600 + minutes * 60 + seconds;
        if (totalSeconds > 64800)
            throw new IllegalArgumentException("offset must be within -180000 and +180000, inclusive");

        this.negative = negative;
        this.hours = hours;
        this.minutes = minutes;
        this.seconds = seconds;
    }

    /**
     * Parses a utc-offset.
     * 
     * @param seq the value to parse. Must be non {@code null}.
     * @return an utc-offset. Never {@code null}.
     * @throws CalendarParseException if {@code seq} does not represent a valid
     *         utc-offset
     */
    public static UtcOffsetType parse(final CharSequence seq) throws CalendarParseException {
        Preconditions.checkNotNull(seq, "value required");

        Matcher m = OFFSET_PATTERN.matcher(seq);
        if (!m.matches())
            throw new CalendarParseException("invalid utc-offset: " + seq);

        try {
            int hours = Integer.parseInt(m.group(2));
            int minutes = Integer.parseInt(m.group(3));
            int seconds = m.group(4) != null ? Integer.parseInt(m.group(4)) : 0;

            if (minutes < 0 || minutes > 59 || seconds < 0 || seconds > 59)
                throw new CalendarParseException("invalid utc-offset: " + seq);

            int total = hours * 3600 + minutes * 60 + seconds;
            if (total > 64800)
                throw new CalendarParseException("invalid utc-offset: " + seq);

            return new UtcOffsetType(m.group(1).equals("-"), hours, minutes, seconds);
        } catch (NumberFormatException e) {
            throw new CalendarParseException("invalid utc-offset: " + seq);
        }
    }

    /**
     * Returns whether or not this utc-offset is negative.
     * 
     * @return whether or not this utc-offset is negative
     */
    public boolean isNegative() {
        return negative;
    }

    /**
     * Returns the number of hours in this utc-offset.
     * 
     * @return the number of hours in this utc-offset. &gt;= 0 and &lt;= 18.
     */
    public int getHours() {
        return hours;
    }

    /**
     * Returns the number of minutes in this utc-offset.
     * 
     * @return the number of minutes in this utc-offset. &gt;= 0 and &lt;= 59.
     */
    public int getMinutes() {
        return minutes;
    }

    /**
     * Returns the number of seconds in this utc-offset.
     * 
     * @return the number of seconds in this utc-offset. &gt;= 0 and &lt;= 59.
     */
    public int getSeconds() {
        return seconds;
    }

    /**
     * Returns the number of milliseconds in this utc-offset. Assumes 60 minute
     * hours and 60 second minutes.
     * 
     * @return the number of milliseconds in this utc-offset. &gt;= 0.
     */
    public int getMillis() {
        return getHours() * 3600000 + getMinutes() * 60000 + getSeconds() * 1000;
    }

    /**
     * Returns a {@link ZoneOffset}.
     * 
     * @return a {@link ZoneOffset}. Never {@code null}.
     */
    public ZoneOffset getZoneOffset() {
        return ZoneOffset.ofHoursMinutesSeconds(getHours() * (isNegative() ? -1 : 1), getMinutes(), getSeconds());
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(isNegative(), getHours(), getMinutes(), getSeconds());
    }

    @Override
    public boolean equals(final Object obj) {
        return obj instanceof UtcOffsetType && isNegative() == ((UtcOffsetType) obj).isNegative()
                && getHours() == ((UtcOffsetType) obj).getHours()
                && getMinutes() == ((UtcOffsetType) obj).getMinutes()
                && getSeconds() == ((UtcOffsetType) obj).getSeconds();
    }

    @Override
    public String toString() {
        return toICalendar();
    }

    @Override
    public String toICalendar() {
        return (isNegative() ? "-" : "+") + Strings.padStart(String.valueOf(getHours()), 2, '0')
                + Strings.padStart(String.valueOf(getMinutes()), 2, '0')
                + Strings.padStart(String.valueOf(getSeconds()), 2, '0');
    }
}