001 /* 002 * SonarQube, open source software quality management tool. 003 * Copyright (C) 2008-2013 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * SonarQube is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * SonarQube is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public License 017 * along with this program; if not, write to the Free Software Foundation, 018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 019 */ 020 021 package org.sonar.api.utils; 022 023 import com.google.common.annotations.VisibleForTesting; 024 import org.apache.commons.lang.builder.ToStringBuilder; 025 import org.apache.commons.lang.builder.ToStringStyle; 026 027 import javax.annotation.Nullable; 028 029 import java.io.Serializable; 030 031 /** 032 * @since 4.2 033 */ 034 public class WorkDuration implements Serializable { 035 036 static final int DAY_POSITION_IN_LONG = 10000; 037 static final int HOUR_POSITION_IN_LONG = 100; 038 static final int MINUTE_POSITION_IN_LONG = 1; 039 040 public static enum UNIT { 041 DAYS, HOURS, MINUTES 042 } 043 044 private int hoursInDay; 045 046 private long durationInSeconds; 047 private int days; 048 private int hours; 049 private int minutes; 050 051 private WorkDuration(long durationInSeconds, int days, int hours, int minutes, int hoursInDay) { 052 this.durationInSeconds = durationInSeconds; 053 this.days = days; 054 this.hours = hours; 055 this.minutes = minutes; 056 this.hoursInDay = hoursInDay; 057 } 058 059 public static WorkDuration create(int days, int hours, int minutes, int hoursInDay) { 060 long durationInSeconds = 3600L * days * hoursInDay; 061 durationInSeconds += 3600L * hours; 062 durationInSeconds += 60L * minutes; 063 return new WorkDuration(durationInSeconds, days, hours, minutes, hoursInDay); 064 } 065 066 public static WorkDuration createFromValueAndUnit(int value, UNIT unit, int hoursInDay) { 067 switch (unit) { 068 case DAYS: 069 return create(value, 0, 0, hoursInDay); 070 case HOURS: 071 return create(0, value, 0, hoursInDay); 072 case MINUTES: 073 return create(0, 0, value, hoursInDay); 074 default: 075 throw new IllegalStateException("Cannot create work duration"); 076 } 077 } 078 079 static WorkDuration createFromLong(long duration, int hoursInDay) { 080 int days = 0, hours = 0, minutes = 0; 081 082 long time = duration; 083 Long currentTime = time / WorkDuration.DAY_POSITION_IN_LONG; 084 if (currentTime > 0) { 085 days = (currentTime.intValue()); 086 time = time - (currentTime * WorkDuration.DAY_POSITION_IN_LONG); 087 } 088 089 currentTime = time / WorkDuration.HOUR_POSITION_IN_LONG; 090 if (currentTime > 0) { 091 hours = currentTime.intValue(); 092 time = time - (currentTime * WorkDuration.HOUR_POSITION_IN_LONG); 093 } 094 095 currentTime = time / WorkDuration.MINUTE_POSITION_IN_LONG; 096 if (currentTime > 0) { 097 minutes = currentTime.intValue(); 098 } 099 return WorkDuration.create(days, hours, minutes, hoursInDay); 100 } 101 102 static WorkDuration createFromSeconds(long seconds, int hoursInDay) { 103 int days = (int) (seconds / hoursInDay / 60f / 60f); 104 long currentDurationInSeconds = seconds - (3600L * days * hoursInDay); 105 int hours = (int) (currentDurationInSeconds / 60f / 60f); 106 currentDurationInSeconds = currentDurationInSeconds - (3600L * hours); 107 int minutes = (int) (currentDurationInSeconds / 60f); 108 return new WorkDuration(seconds, days, hours, minutes, hoursInDay); 109 } 110 111 /** 112 * Return the duration in number of working days. 113 * For instance, 3 days and 4 hours will return 3.5 days (if hoursIndDay is 8). 114 */ 115 public double toWorkingDays() { 116 return durationInSeconds / 60d / 60d / hoursInDay; 117 } 118 119 /** 120 * Return the duration using the following format DDHHMM, where DD is the number of days, HH is the number of months, and MM the number of minutes. 121 * For instance, 3 days and 4 hours will return 030400 (if hoursIndDay is 8). 122 */ 123 public long toLong() { 124 int workingDays = days; 125 int workingHours = hours; 126 if (hours >= hoursInDay) { 127 int nbAdditionalDays = hours / hoursInDay; 128 workingDays += nbAdditionalDays; 129 workingHours = hours - (nbAdditionalDays * hoursInDay); 130 } 131 return workingDays * DAY_POSITION_IN_LONG + workingHours * HOUR_POSITION_IN_LONG + minutes * MINUTE_POSITION_IN_LONG; 132 } 133 134 public long toSeconds() { 135 return durationInSeconds; 136 } 137 138 public WorkDuration add(@Nullable WorkDuration with) { 139 if (with != null) { 140 return WorkDuration.createFromSeconds(this.toSeconds() + with.toSeconds(), this.hoursInDay); 141 } else { 142 return this; 143 } 144 } 145 146 public WorkDuration subtract(@Nullable WorkDuration with) { 147 if (with != null) { 148 return WorkDuration.createFromSeconds(this.toSeconds() - with.toSeconds(), this.hoursInDay); 149 } else { 150 return this; 151 } 152 } 153 154 public WorkDuration multiply(int factor) { 155 return WorkDuration.createFromSeconds(this.toSeconds() * factor, this.hoursInDay); 156 } 157 158 public int days() { 159 return days; 160 } 161 162 public int hours() { 163 return hours; 164 } 165 166 public int minutes() { 167 return minutes; 168 } 169 170 @VisibleForTesting 171 int hoursInDay() { 172 return hoursInDay; 173 } 174 175 @Override 176 public boolean equals(Object o) { 177 if (this == o) { 178 return true; 179 } 180 if (o == null || getClass() != o.getClass()) { 181 return false; 182 } 183 184 WorkDuration that = (WorkDuration) o; 185 if (durationInSeconds != that.durationInSeconds) { 186 return false; 187 } 188 189 return true; 190 } 191 192 @Override 193 public int hashCode() { 194 return (int) (durationInSeconds ^ (durationInSeconds >>> 32)); 195 } 196 197 @Override 198 public String toString() { 199 return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); 200 } 201 }