1 /* 2 * Copyright 2001-2010 Stephen Colebourne 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package org.joda.time; 17 18 import org.joda.convert.FromString; 19 import org.joda.convert.ToString; 20 import org.joda.time.base.BaseSingleFieldPeriod; 21 import org.joda.time.field.FieldUtils; 22 import org.joda.time.format.ISOPeriodFormat; 23 import org.joda.time.format.PeriodFormatter; 24 25 /** 26 * An immutable time period representing a number of minutes. 27 * <p> 28 * <code>Minutes</code> is an immutable period that can only store minutes. 29 * It does not store years, months or hours for example. As such it is a 30 * type-safe way of representing a number of minutes in an application. 31 * <p> 32 * The number of minutes is set in the constructor, and may be queried using 33 * <code>getMinutes()</code>. Basic mathematical operations are provided - 34 * <code>plus()</code>, <code>minus()</code>, <code>multipliedBy()</code> and 35 * <code>dividedBy()</code>. 36 * <p> 37 * <code>Minutes</code> is thread-safe and immutable. 38 * 39 * @author Stephen Colebourne 40 * @since 1.4 41 */ 42 public final class Minutes extends BaseSingleFieldPeriod { 43 44 /** Constant representing zero minutes. */ 45 public static final Minutes ZERO = new Minutes(0); 46 /** Constant representing one minute. */ 47 public static final Minutes ONE = new Minutes(1); 48 /** Constant representing two minutes. */ 49 public static final Minutes TWO = new Minutes(2); 50 /** Constant representing three minutes. */ 51 public static final Minutes THREE = new Minutes(3); 52 /** Constant representing the maximum number of minutes that can be stored in this object. */ 53 public static final Minutes MAX_VALUE = new Minutes(Integer.MAX_VALUE); 54 /** Constant representing the minimum number of minutes that can be stored in this object. */ 55 public static final Minutes MIN_VALUE = new Minutes(Integer.MIN_VALUE); 56 57 /** The paser to use for this class. */ 58 private static final PeriodFormatter PARSER = ISOPeriodFormat.standard().withParseType(PeriodType.minutes()); 59 /** Serialization version. */ 60 private static final long serialVersionUID = 87525275727380863L; 61 62 //----------------------------------------------------------------------- 63 /** 64 * Obtains an instance of <code>Minutes</code> that may be cached. 65 * <code>Minutes</code> is immutable, so instances can be cached and shared. 66 * This factory method provides access to shared instances. 67 * 68 * @param minutes the number of minutes to obtain an instance for 69 * @return the instance of Minutes 70 */ 71 public static Minutes minutes(int minutes) { 72 switch (minutes) { 73 case 0: 74 return ZERO; 75 case 1: 76 return ONE; 77 case 2: 78 return TWO; 79 case 3: 80 return THREE; 81 case Integer.MAX_VALUE: 82 return MAX_VALUE; 83 case Integer.MIN_VALUE: 84 return MIN_VALUE; 85 default: 86 return new Minutes(minutes); 87 } 88 } 89 90 //----------------------------------------------------------------------- 91 /** 92 * Creates a <code>Minutes</code> representing the number of whole minutes 93 * between the two specified datetimes. 94 * 95 * @param start the start instant, must not be null 96 * @param end the end instant, must not be null 97 * @return the period in minutes 98 * @throws IllegalArgumentException if the instants are null or invalid 99 */ 100 public static Minutes minutesBetween(ReadableInstant start, ReadableInstant end) { 101 int amount = BaseSingleFieldPeriod.between(start, end, DurationFieldType.minutes()); 102 return Minutes.minutes(amount); 103 } 104 105 /** 106 * Creates a <code>Minutes</code> representing the number of whole minutes 107 * between the two specified partial datetimes. 108 * <p> 109 * The two partials must contain the same fields, for example you can specify 110 * two <code>LocalTime</code> objects. 111 * 112 * @param start the start partial date, must not be null 113 * @param end the end partial date, must not be null 114 * @return the period in minutes 115 * @throws IllegalArgumentException if the partials are null or invalid 116 */ 117 public static Minutes minutesBetween(ReadablePartial start, ReadablePartial end) { 118 if (start instanceof LocalTime && end instanceof LocalTime) { 119 Chronology chrono = DateTimeUtils.getChronology(start.getChronology()); 120 int minutes = chrono.minutes().getDifference( 121 ((LocalTime) end).getLocalMillis(), ((LocalTime) start).getLocalMillis()); 122 return Minutes.minutes(minutes); 123 } 124 int amount = BaseSingleFieldPeriod.between(start, end, ZERO); 125 return Minutes.minutes(amount); 126 } 127 128 /** 129 * Creates a <code>Minutes</code> representing the number of whole minutes 130 * in the specified interval. 131 * 132 * @param interval the interval to extract minutes from, null returns zero 133 * @return the period in minutes 134 * @throws IllegalArgumentException if the partials are null or invalid 135 */ 136 public static Minutes minutesIn(ReadableInterval interval) { 137 if (interval == null) { 138 return Minutes.ZERO; 139 } 140 int amount = BaseSingleFieldPeriod.between(interval.getStart(), interval.getEnd(), DurationFieldType.minutes()); 141 return Minutes.minutes(amount); 142 } 143 144 /** 145 * Creates a new <code>Minutes</code> representing the number of complete 146 * standard length minutes in the specified period. 147 * <p> 148 * This factory method converts all fields from the period to minutes using standardised 149 * durations for each field. Only those fields which have a precise duration in 150 * the ISO UTC chronology can be converted. 151 * <ul> 152 * <li>One week consists of 7 days. 153 * <li>One day consists of 24 hours. 154 * <li>One hour consists of 60 minutes. 155 * <li>One minute consists of 60 seconds. 156 * <li>One second consists of 1000 milliseconds. 157 * </ul> 158 * Months and Years are imprecise and periods containing these values cannot be converted. 159 * 160 * @param period the period to get the number of minutes from, null returns zero 161 * @return the period in minutes 162 * @throws IllegalArgumentException if the period contains imprecise duration values 163 */ 164 public static Minutes standardMinutesIn(ReadablePeriod period) { 165 int amount = BaseSingleFieldPeriod.standardPeriodIn(period, DateTimeConstants.MILLIS_PER_MINUTE); 166 return Minutes.minutes(amount); 167 } 168 169 /** 170 * Creates a new <code>Minutes</code> by parsing a string in the ISO8601 format 'PTnM'. 171 * <p> 172 * The parse will accept the full ISO syntax of PnYnMnWnDTnHnMnS however only the 173 * minutes component may be non-zero. If any other component is non-zero, an exception 174 * will be thrown. 175 * 176 * @param periodStr the period string, null returns zero 177 * @return the period in minutes 178 * @throws IllegalArgumentException if the string format is invalid 179 */ 180 @FromString 181 public static Minutes parseMinutes(String periodStr) { 182 if (periodStr == null) { 183 return Minutes.ZERO; 184 } 185 Period p = PARSER.parsePeriod(periodStr); 186 return Minutes.minutes(p.getMinutes()); 187 } 188 189 //----------------------------------------------------------------------- 190 /** 191 * Creates a new instance representing a number of minutes. 192 * You should consider using the factory method {@link #minutes(int)} 193 * instead of the constructor. 194 * 195 * @param minutes the number of minutes to represent 196 */ 197 private Minutes(int minutes) { 198 super(minutes); 199 } 200 201 /** 202 * Resolves singletons. 203 * 204 * @return the singleton instance 205 */ 206 private Object readResolve() { 207 return Minutes.minutes(getValue()); 208 } 209 210 //----------------------------------------------------------------------- 211 /** 212 * Gets the duration field type, which is <code>minutes</code>. 213 * 214 * @return the period type 215 */ 216 public DurationFieldType getFieldType() { 217 return DurationFieldType.minutes(); 218 } 219 220 /** 221 * Gets the period type, which is <code>minutes</code>. 222 * 223 * @return the period type 224 */ 225 public PeriodType getPeriodType() { 226 return PeriodType.minutes(); 227 } 228 229 //----------------------------------------------------------------------- 230 /** 231 * Converts this period in minutes to a period in weeks assuming a 232 * 7 days week, 24 hour day and 60 minute hour. 233 * <p> 234 * This method allows you to convert between different types of period. 235 * However to achieve this it makes the assumption that all weeks are 236 * 7 days long, all days are 24 hours long and all hours are 60 minutes long. 237 * This is not true when daylight savings is considered and may also not 238 * be true for some unusual chronologies. However, it is included 239 * as it is a useful operation for many applications and business rules. 240 * 241 * @return a period representing the number of whole weeks for this number of minutes 242 */ 243 public Weeks toStandardWeeks() { 244 return Weeks.weeks(getValue() / DateTimeConstants.MINUTES_PER_WEEK); 245 } 246 247 /** 248 * Converts this period in minutes to a period in days assuming a 249 * 24 hour day and 60 minute hour. 250 * <p> 251 * This method allows you to convert between different types of period. 252 * However to achieve this it makes the assumption that all days are 253 * 24 hours long and all hours are 60 minutes long. 254 * This is not true when daylight savings is considered and may also not 255 * be true for some unusual chronologies. However, it is included 256 * as it is a useful operation for many applications and business rules. 257 * 258 * @return a period representing the number of whole days for this number of minutes 259 */ 260 public Days toStandardDays() { 261 return Days.days(getValue() / DateTimeConstants.MINUTES_PER_DAY); 262 } 263 264 /** 265 * Converts this period in minutes to a period in hours assuming a 266 * 60 minute hour. 267 * <p> 268 * This method allows you to convert between different types of period. 269 * However to achieve this it makes the assumption that all hours are 270 * 60 minutes long. 271 * This may not be true for some unusual chronologies. However, it is included 272 * as it is a useful operation for many applications and business rules. 273 * 274 * @return a period representing the number of hours for this number of minutes 275 */ 276 public Hours toStandardHours() { 277 return Hours.hours(getValue() / DateTimeConstants.MINUTES_PER_HOUR); 278 } 279 280 /** 281 * Converts this period in minutes to a period in seconds assuming a 282 * 60 second minute. 283 * <p> 284 * This method allows you to convert between different types of period. 285 * However to achieve this it makes the assumption that all minutes are 286 * 60 seconds long. 287 * This may not be true for some unusual chronologies. However, it is included 288 * as it is a useful operation for many applications and business rules. 289 * 290 * @return a period representing the number of seconds for this number of minutes 291 * @throws ArithmeticException if the number of seconds is too large to be represented 292 */ 293 public Seconds toStandardSeconds() { 294 return Seconds.seconds(FieldUtils.safeMultiply(getValue(), DateTimeConstants.SECONDS_PER_MINUTE)); 295 } 296 297 //----------------------------------------------------------------------- 298 /** 299 * Converts this period in minutes to a duration in milliseconds assuming a 300 * 60 second minute. 301 * <p> 302 * This method allows you to convert from a period to a duration. 303 * However to achieve this it makes the assumption that all minutes are 304 * 60 seconds long. This might not be true for an unusual chronology, 305 * for example one that takes leap seconds into account. 306 * However, the method is included as it is a useful operation for many 307 * applications and business rules. 308 * 309 * @return a duration equivalent to this number of minutes 310 */ 311 public Duration toStandardDuration() { 312 long minutes = getValue(); // assign to a long 313 return new Duration(minutes * DateTimeConstants.MILLIS_PER_MINUTE); 314 } 315 316 //----------------------------------------------------------------------- 317 /** 318 * Gets the number of minutes that this period represents. 319 * 320 * @return the number of minutes in the period 321 */ 322 public int getMinutes() { 323 return getValue(); 324 } 325 326 //----------------------------------------------------------------------- 327 /** 328 * Returns a new instance with the specified number of minutes added. 329 * <p> 330 * This instance is immutable and unaffected by this method call. 331 * 332 * @param minutes the amount of minutes to add, may be negative 333 * @return the new period plus the specified number of minutes 334 * @throws ArithmeticException if the result overflows an int 335 */ 336 public Minutes plus(int minutes) { 337 if (minutes == 0) { 338 return this; 339 } 340 return Minutes.minutes(FieldUtils.safeAdd(getValue(), minutes)); 341 } 342 343 /** 344 * Returns a new instance with the specified number of minutes added. 345 * <p> 346 * This instance is immutable and unaffected by this method call. 347 * 348 * @param minutes the amount of minutes to add, may be negative, null means zero 349 * @return the new period plus the specified number of minutes 350 * @throws ArithmeticException if the result overflows an int 351 */ 352 public Minutes plus(Minutes minutes) { 353 if (minutes == null) { 354 return this; 355 } 356 return plus(minutes.getValue()); 357 } 358 359 //----------------------------------------------------------------------- 360 /** 361 * Returns a new instance with the specified number of minutes taken away. 362 * <p> 363 * This instance is immutable and unaffected by this method call. 364 * 365 * @param minutes the amount of minutes to take away, may be negative 366 * @return the new period minus the specified number of minutes 367 * @throws ArithmeticException if the result overflows an int 368 */ 369 public Minutes minus(int minutes) { 370 return plus(FieldUtils.safeNegate(minutes)); 371 } 372 373 /** 374 * Returns a new instance with the specified number of minutes taken away. 375 * <p> 376 * This instance is immutable and unaffected by this method call. 377 * 378 * @param minutes the amount of minutes to take away, may be negative, null means zero 379 * @return the new period minus the specified number of minutes 380 * @throws ArithmeticException if the result overflows an int 381 */ 382 public Minutes minus(Minutes minutes) { 383 if (minutes == null) { 384 return this; 385 } 386 return minus(minutes.getValue()); 387 } 388 389 //----------------------------------------------------------------------- 390 /** 391 * Returns a new instance with the minutes multiplied by the specified scalar. 392 * <p> 393 * This instance is immutable and unaffected by this method call. 394 * 395 * @param scalar the amount to multiply by, may be negative 396 * @return the new period multiplied by the specified scalar 397 * @throws ArithmeticException if the result overflows an int 398 */ 399 public Minutes multipliedBy(int scalar) { 400 return Minutes.minutes(FieldUtils.safeMultiply(getValue(), scalar)); 401 } 402 403 /** 404 * Returns a new instance with the minutes divided by the specified divisor. 405 * The calculation uses integer division, thus 3 divided by 2 is 1. 406 * <p> 407 * This instance is immutable and unaffected by this method call. 408 * 409 * @param divisor the amount to divide by, may be negative 410 * @return the new period divided by the specified divisor 411 * @throws ArithmeticException if the divisor is zero 412 */ 413 public Minutes dividedBy(int divisor) { 414 if (divisor == 1) { 415 return this; 416 } 417 return Minutes.minutes(getValue() / divisor); 418 } 419 420 //----------------------------------------------------------------------- 421 /** 422 * Returns a new instance with the minutes value negated. 423 * 424 * @return the new period with a negated value 425 * @throws ArithmeticException if the result overflows an int 426 */ 427 public Minutes negated() { 428 return Minutes.minutes(FieldUtils.safeNegate(getValue())); 429 } 430 431 //----------------------------------------------------------------------- 432 /** 433 * Is this minutes instance greater than the specified number of minutes. 434 * 435 * @param other the other period, null means zero 436 * @return true if this minutes instance is greater than the specified one 437 */ 438 public boolean isGreaterThan(Minutes other) { 439 if (other == null) { 440 return getValue() > 0; 441 } 442 return getValue() > other.getValue(); 443 } 444 445 /** 446 * Is this minutes instance less than the specified number of minutes. 447 * 448 * @param other the other period, null means zero 449 * @return true if this minutes instance is less than the specified one 450 */ 451 public boolean isLessThan(Minutes other) { 452 if (other == null) { 453 return getValue() < 0; 454 } 455 return getValue() < other.getValue(); 456 } 457 458 //----------------------------------------------------------------------- 459 /** 460 * Gets this instance as a String in the ISO8601 duration format. 461 * <p> 462 * For example, "PT4M" represents 4 minutes. 463 * 464 * @return the value as an ISO8601 string 465 */ 466 @ToString 467 public String toString() { 468 return "PT" + String.valueOf(getValue()) + "M"; 469 } 470 471 }