/** * 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. * * Copyright 2012-2016 the original author or authors. */ package org.assertj.db.type; import java.sql.Time; import java.text.ParseException; import java.util.Calendar; /** * This class represents a time value in the database. * * @author RĂ©gis Pouiller * */ public class TimeValue implements Comparable<TimeValue> { /** * Hours. */ private final int hours; /** * Minutes. */ private final int minutes; /** * Seconds. */ private final int seconds; /** * Nanoseconds. */ private final int nanoSeconds; /** * Indicates where there are the digits for {@code String} for {@link TimeValue#TimeValue(String)}. */ private static final String TIME_FORMAT = "\\d\\d:\\d\\d"; /** * Indicates where there are the digits in style with seconds for {@code String} for * {@link TimeValue#TimeValue(String)}. */ private static final String TIME_FORMAT_WITH_SECONDS = "\\d\\d:\\d\\d:\\d\\d"; /** * Indicates where there are the digits in style with nanoseconds for {@code String} for * {@link TimeValue#TimeValue(String)}. */ private static final String TIME_FORMAT_WITH_NANO = "\\d\\d:\\d\\d:\\d\\d.\\d\\d\\d\\d\\d\\d\\d\\d\\d"; /** * Makes an instance of time value from a hours, minutes, seconds and nanoseconds. * * @param hours Hours. * @param minutes Minutes. * @param seconds Seconds. * @param nanoSeconds Nanoseconds. * @return An instance of time value. */ public static TimeValue of(int hours, int minutes, int seconds, int nanoSeconds) { return new TimeValue(hours, minutes, seconds, nanoSeconds); } /** * Makes an instance of time value from a hours, minutes and seconds. * * @param hours Hours. * @param minutes Minutes. * @param seconds Seconds. * @return An instance of time value. */ public static TimeValue of(int hours, int minutes, int seconds) { return new TimeValue(hours, minutes, seconds); } /** * Makes an instance of time value from a hours and minutes. * * @param hours Hours. * @param minutes Minutes. * @return An instance of time value. */ public static TimeValue of(int hours, int minutes) { return new TimeValue(hours, minutes); } /** * Makes an instance of time value from a {@code String} in {@code hh:mm}, {@code hh:mm:ss} or * {@code hh:mm:ss.nnnnnnnnn} format. * * @param time Time in {@code String} format ({@code hh:mm}, {@code hh:mm:ss} or {@code hh:mm:ss.nnnnnnnnn}). * @return An instance of time value. * @throws NullPointerException If {@code time} is {@code null}. * @throws ParseException If {@code time} don't respect the {@code hh:mm}, {@code hh:mm:ss} or * {@code hh:mm:ss.nnnnnnnnn} format. */ public static TimeValue parse(String time) throws ParseException { return new TimeValue(time); } /** * Makes an instance of time value from a {@link Time}. * * @param time Time. * @throws NullPointerException If {@code time} is {@code null}. * @return An instance of time value. */ public static TimeValue from(Time time) { return new TimeValue(time); } /** * Makes an instance of time value from a {@link Calendar}. * * @param calendar Calendar. * @throws NullPointerException If {@code calendar} is {@code null}. * @return An instance of time value. * @since 1.1.0 */ public static TimeValue from(Calendar calendar) { return new TimeValue(calendar); } /** * Makes an instance of the time value corresponding to now. * * @return An instance of time value. * @since 1.1.0 */ public static TimeValue now() { return from(Calendar.getInstance()); } /** * Constructor. * * @param hours Hours. * @param minutes Minutes. * @param seconds Seconds. * @param nanoSeconds Nanoseconds. */ public TimeValue(int hours, int minutes, int seconds, int nanoSeconds) { this.hours = hours; this.minutes = minutes; this.seconds = seconds; this.nanoSeconds = nanoSeconds; } /** * Constructor. * * @param hours Hours. * @param minutes Minutes. * @param seconds Seconds. */ public TimeValue(int hours, int minutes, int seconds) { this(hours, minutes, seconds, 0); } /** * Constructor. * * @param hours Hours. * @param minutes Minutes. */ public TimeValue(int hours, int minutes) { this(hours, minutes, 0, 0); } /** * Constructor. * * @param time Time in {@code String} format ({@code hh:mm}, {@code hh:mm:ss} or {@code hh:mm:ss.nnnnnnnnn}). * @throws NullPointerException If {@code time} is {@code null}. * @throws ParseException If {@code time} don't respect the {@code hh:mm}, {@code hh:mm:ss} or * {@code hh:mm:ss.nnnnnnnnn} format. */ public TimeValue(String time) throws ParseException { if (time == null) { throw new NullPointerException("time should be not null"); } if (time.matches(TIME_FORMAT)) { hours = Integer.parseInt(time.substring(0, 2)); minutes = Integer.parseInt(time.substring(3)); seconds = 0; nanoSeconds = 0; } else if (time.matches(TIME_FORMAT_WITH_SECONDS)) { hours = Integer.parseInt(time.substring(0, 2)); minutes = Integer.parseInt(time.substring(3, 5)); seconds = Integer.parseInt(time.substring(6)); nanoSeconds = 0; } else if (time.matches(TIME_FORMAT_WITH_NANO)) { hours = Integer.parseInt(time.substring(0, 2)); minutes = Integer.parseInt(time.substring(3, 5)); seconds = Integer.parseInt(time.substring(6, 8)); nanoSeconds = Integer.parseInt(time.substring(9)); } else { throw new ParseException("time must respect hh:mm, hh:mm:ss or hh:mm:ss.nnnnnnnnn format", time.length()); } } /** * Constructor. * * @param time Time. * @throws NullPointerException If {@code time} is {@code null}. */ public TimeValue(Time time) { if (time == null) { throw new NullPointerException("time should be not null"); } Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(time.getTime()); hours = calendar.get(Calendar.HOUR_OF_DAY); minutes = calendar.get(Calendar.MINUTE); seconds = calendar.get(Calendar.SECOND); nanoSeconds = calendar.get(Calendar.MILLISECOND) * 1000000; } /** * Constructor. * * @param calendar Calendar. * @throws NullPointerException If {@code calendar} is {@code null}. */ public TimeValue(Calendar calendar) { if (calendar == null) { throw new NullPointerException("time should be not null"); } hours = calendar.get(Calendar.HOUR_OF_DAY); minutes = calendar.get(Calendar.MINUTE); seconds = calendar.get(Calendar.SECOND); nanoSeconds = calendar.get(Calendar.MILLISECOND) * 1000000; } /** * Returns the hours. * * @return The hours. */ public int getHours() { return hours; } /** * Returns the minutes. * * @return The minutes. */ public int getMinutes() { return minutes; } /** * Returns the seconds. * * @return The seconds. */ public int getSeconds() { return seconds; } /** * Returns the nanoseconds. * * @return The nanoseconds. */ public int getNanoSeconds() { return nanoSeconds; } @Override public String toString() { return String.format("%02d:%02d:%02d.%09d", hours, minutes, seconds, nanoSeconds); } @Override public boolean equals(Object obj) { if (obj instanceof TimeValue) { TimeValue timeValue = (TimeValue) obj; return hours == timeValue.hours && minutes == timeValue.minutes && seconds == timeValue.seconds && nanoSeconds == timeValue.nanoSeconds; } return false; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + hours; result = prime * result + minutes; result = prime * result + nanoSeconds; result = prime * result + seconds; return result; } @Override public int compareTo(TimeValue other) { if (hours < other.hours) { return -1; } else if (hours > other.hours) { return 1; } else if (minutes < other.minutes) { return -1; } else if (minutes > other.minutes) { return 1; } else if (seconds < other.seconds) { return -1; } else if (seconds > other.seconds) { return 1; } else if (nanoSeconds < other.nanoSeconds) { return -1; } else if (nanoSeconds > other.nanoSeconds) { return 1; } return 0; } /** * Returns if this time value is before the time value in parameter. * @param time The time value to compare to. * @return If this time value is before the time value in parameter. */ public boolean isBefore(TimeValue time) { return compareTo(time) == -1; } /** * Returns if this time value is after the time value in parameter. * @param time The time value to compare to. * @return If this time value is after the time value in parameter. */ public boolean isAfter(TimeValue time) { return compareTo(time) == 1; } /** * Moves the time with the value in parameter. * @param time Value to move the date. * @return The date/time moved. */ public TimeValue move(TimeValue time) { int thisHours = this.hours; int thisMinutes = this.minutes; int thisSeconds = this.seconds; int thisNanoSeconds = this.nanoSeconds; int hours = time.getHours(); int minutes = time.getMinutes(); int seconds = time.getSeconds(); int nanoSeconds = time.getNanoSeconds(); if (nanoSeconds >= 0 || thisNanoSeconds >= -nanoSeconds) { thisNanoSeconds += nanoSeconds; } else { thisNanoSeconds += 1000000000 + nanoSeconds; seconds--; } if (seconds >= 0 || thisSeconds >= -seconds) { thisSeconds += seconds; } else { thisSeconds += 60 + seconds; minutes--; } if (minutes >= 0 || thisMinutes >= -minutes) { thisMinutes += minutes; } else { thisMinutes += 60 + minutes; hours--; } thisHours += hours; return of(thisHours, thisMinutes, thisSeconds, thisNanoSeconds); } /** * Returns the reverse of the time. * @return The reverse. */ public TimeValue reverse() { return of(-getHours(), -getMinutes(), -getSeconds(), -getNanoSeconds()); } }