001/* 002 * SonarQube, open source software quality management tool. 003 * Copyright (C) 2008-2014 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 021package org.sonar.api.utils.internal; 022 023import com.google.common.annotations.VisibleForTesting; 024import org.apache.commons.lang.builder.ToStringBuilder; 025import org.apache.commons.lang.builder.ToStringStyle; 026 027import javax.annotation.Nullable; 028 029import java.io.Serializable; 030 031/** 032 * @since 4.2 033 */ 034public 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 durationInMinutes; 047 private int days; 048 private int hours; 049 private int minutes; 050 051 private WorkDuration(long durationInMinutes, int days, int hours, int minutes, int hoursInDay) { 052 this.durationInMinutes = durationInMinutes; 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 = 60L * days * hoursInDay; 061 durationInSeconds += 60L * hours; 062 durationInSeconds += 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 createFromMinutes(long duration, int hoursInDay) { 103 int days = (int)(duration / (double)hoursInDay / 60.0); 104 Long currentDurationInMinutes = duration - (60L * days * hoursInDay); 105 int hours = (int)(currentDurationInMinutes / 60.0); 106 currentDurationInMinutes = currentDurationInMinutes - (60L * hours); 107 return new WorkDuration(duration, days, hours, currentDurationInMinutes.intValue(), hoursInDay); 108 } 109 110 /** 111 * Return the duration in number of working days. 112 * For instance, 3 days and 4 hours will return 3.5 days (if hoursIndDay is 8). 113 */ 114 public double toWorkingDays() { 115 return durationInMinutes / 60d / hoursInDay; 116 } 117 118 /** 119 * 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. 120 * For instance, 3 days and 4 hours will return 030400 (if hoursIndDay is 8). 121 */ 122 public long toLong() { 123 int workingDays = days; 124 int workingHours = hours; 125 if (hours >= hoursInDay) { 126 int nbAdditionalDays = hours / hoursInDay; 127 workingDays += nbAdditionalDays; 128 workingHours = hours - (nbAdditionalDays * hoursInDay); 129 } 130 return 1L * workingDays * DAY_POSITION_IN_LONG + workingHours * HOUR_POSITION_IN_LONG + minutes * MINUTE_POSITION_IN_LONG; 131 } 132 133 public long toMinutes() { 134 return durationInMinutes; 135 } 136 137 public WorkDuration add(@Nullable WorkDuration with) { 138 if (with != null) { 139 return WorkDuration.createFromMinutes(this.toMinutes() + with.toMinutes(), this.hoursInDay); 140 } else { 141 return this; 142 } 143 } 144 145 public WorkDuration subtract(@Nullable WorkDuration with) { 146 if (with != null) { 147 return WorkDuration.createFromMinutes(this.toMinutes() - with.toMinutes(), this.hoursInDay); 148 } else { 149 return this; 150 } 151 } 152 153 public WorkDuration multiply(int factor) { 154 return WorkDuration.createFromMinutes(this.toMinutes() * factor, this.hoursInDay); 155 } 156 157 public int days() { 158 return days; 159 } 160 161 public int hours() { 162 return hours; 163 } 164 165 public int minutes() { 166 return minutes; 167 } 168 169 @VisibleForTesting 170 int hoursInDay() { 171 return hoursInDay; 172 } 173 174 @Override 175 public boolean equals(Object o) { 176 if (this == o) { 177 return true; 178 } 179 if (o == null || getClass() != o.getClass()) { 180 return false; 181 } 182 183 WorkDuration that = (WorkDuration) o; 184 if (durationInMinutes != that.durationInMinutes) { 185 return false; 186 } 187 188 return true; 189 } 190 191 @Override 192 public int hashCode() { 193 return (int) (durationInMinutes ^ (durationInMinutes >>> 32)); 194 } 195 196 @Override 197 public String toString() { 198 return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); 199 } 200}