001/* 002 * SonarQube 003 * Copyright (C) 2009-2016 SonarSource SA 004 * mailto:contact AT sonarsource DOT com 005 * 006 * This program 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 * This program 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 */ 020package org.sonar.api.utils.internal; 021 022import com.google.common.annotations.VisibleForTesting; 023import java.io.Serializable; 024import javax.annotation.Nullable; 025import org.apache.commons.lang.builder.ToStringBuilder; 026import org.apache.commons.lang.builder.ToStringStyle; 027 028/** 029 * @since 4.2 030 */ 031public class WorkDuration implements Serializable { 032 033 static final int DAY_POSITION_IN_LONG = 10_000; 034 static final int HOUR_POSITION_IN_LONG = 100; 035 static final int MINUTE_POSITION_IN_LONG = 1; 036 037 public enum UNIT { 038 DAYS, HOURS, MINUTES 039 } 040 041 private int hoursInDay; 042 043 private long durationInMinutes; 044 private int days; 045 private int hours; 046 private int minutes; 047 048 private WorkDuration(long durationInMinutes, int days, int hours, int minutes, int hoursInDay) { 049 this.durationInMinutes = durationInMinutes; 050 this.days = days; 051 this.hours = hours; 052 this.minutes = minutes; 053 this.hoursInDay = hoursInDay; 054 } 055 056 public static WorkDuration create(int days, int hours, int minutes, int hoursInDay) { 057 long durationInSeconds = 60L * days * hoursInDay; 058 durationInSeconds += 60L * hours; 059 durationInSeconds += minutes; 060 return new WorkDuration(durationInSeconds, days, hours, minutes, hoursInDay); 061 } 062 063 public static WorkDuration createFromValueAndUnit(int value, UNIT unit, int hoursInDay) { 064 switch (unit) { 065 case DAYS: 066 return create(value, 0, 0, hoursInDay); 067 case HOURS: 068 return create(0, value, 0, hoursInDay); 069 case MINUTES: 070 return create(0, 0, value, hoursInDay); 071 default: 072 throw new IllegalStateException("Cannot create work duration"); 073 } 074 } 075 076 static WorkDuration createFromLong(long duration, int hoursInDay) { 077 int days = 0; 078 int hours = 0; 079 int minutes = 0; 080 081 long time = duration; 082 Long currentTime = time / WorkDuration.DAY_POSITION_IN_LONG; 083 if (currentTime > 0) { 084 days = currentTime.intValue(); 085 time = time - (currentTime * WorkDuration.DAY_POSITION_IN_LONG); 086 } 087 088 currentTime = time / WorkDuration.HOUR_POSITION_IN_LONG; 089 if (currentTime > 0) { 090 hours = currentTime.intValue(); 091 time = time - (currentTime * WorkDuration.HOUR_POSITION_IN_LONG); 092 } 093 094 currentTime = time / WorkDuration.MINUTE_POSITION_IN_LONG; 095 if (currentTime > 0) { 096 minutes = currentTime.intValue(); 097 } 098 return WorkDuration.create(days, hours, minutes, hoursInDay); 099 } 100 101 static WorkDuration createFromMinutes(long duration, int hoursInDay) { 102 int days = (int)(duration / (double)hoursInDay / 60.0); 103 Long currentDurationInMinutes = duration - (60L * days * hoursInDay); 104 int hours = (int)(currentDurationInMinutes / 60.0); 105 currentDurationInMinutes = currentDurationInMinutes - (60L * hours); 106 return new WorkDuration(duration, days, hours, currentDurationInMinutes.intValue(), hoursInDay); 107 } 108 109 /** 110 * Return the duration in number of working days. 111 * For instance, 3 days and 4 hours will return 3.5 days (if hoursIndDay is 8). 112 */ 113 public double toWorkingDays() { 114 return durationInMinutes / 60d / hoursInDay; 115 } 116 117 /** 118 * 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. 119 * For instance, 3 days and 4 hours will return 030400 (if hoursIndDay is 8). 120 */ 121 public long toLong() { 122 int workingDays = days; 123 int workingHours = hours; 124 if (hours >= hoursInDay) { 125 int nbAdditionalDays = hours / hoursInDay; 126 workingDays += nbAdditionalDays; 127 workingHours = hours - (nbAdditionalDays * hoursInDay); 128 } 129 return 1L * workingDays * DAY_POSITION_IN_LONG + workingHours * HOUR_POSITION_IN_LONG + minutes * MINUTE_POSITION_IN_LONG; 130 } 131 132 public long toMinutes() { 133 return durationInMinutes; 134 } 135 136 public WorkDuration add(@Nullable WorkDuration with) { 137 if (with != null) { 138 return WorkDuration.createFromMinutes(this.toMinutes() + with.toMinutes(), this.hoursInDay); 139 } else { 140 return this; 141 } 142 } 143 144 public WorkDuration subtract(@Nullable WorkDuration with) { 145 if (with != null) { 146 return WorkDuration.createFromMinutes(this.toMinutes() - with.toMinutes(), this.hoursInDay); 147 } else { 148 return this; 149 } 150 } 151 152 public WorkDuration multiply(int factor) { 153 return WorkDuration.createFromMinutes(this.toMinutes() * factor, this.hoursInDay); 154 } 155 156 public int days() { 157 return days; 158 } 159 160 public int hours() { 161 return hours; 162 } 163 164 public int minutes() { 165 return minutes; 166 } 167 168 @VisibleForTesting 169 int hoursInDay() { 170 return hoursInDay; 171 } 172 173 @Override 174 public boolean equals(Object o) { 175 if (this == o) { 176 return true; 177 } 178 if (o == null || getClass() != o.getClass()) { 179 return false; 180 } 181 182 WorkDuration that = (WorkDuration) o; 183 return durationInMinutes == that.durationInMinutes; 184 185 } 186 187 @Override 188 public int hashCode() { 189 return (int) (durationInMinutes ^ (durationInMinutes >>> 32)); 190 } 191 192 @Override 193 public String toString() { 194 return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); 195 } 196}