content: // Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
  // for details. All rights reserved. Use of this source code is governed by a
  // BSD-style license that can be found in the LICENSE file.
  
  part of dart.core;
  
  /**
   * A span of time, such as 27 days, 4 hours, 12 minutes, and 3 seconds.
   *
   * To create a new Duration object, use this class's single constructor
   * giving the appropriate arguments:
   *
   *     Duration fastestMarathon = new Duration(hours:2, minutes:3, seconds:2);
   *
   * The Duration is the sum of all individual parts.
   * This means that individual parts can be larger than the next-bigger unit.
   * For example, [minutes] can be greater than 59.
   *
   *     assert(fastestMarathon.inMinutes == 123);
   *
   * All individual parts are allowed to be negative.
   *
   * Use one of the properties, such as [inDays],
   * to retrieve the integer value of the Duration in the specified time unit.
   * Note that the returned value is rounded down.
   * For example, 
   *
   *     Duration aLongWeekend = new Duration(hours:88);
   *     assert(aLongWeekend.inDays == 3);
   *
   * This class provides a collection of arithmetic
   * and comparison operators,
   * plus a set of constants useful for converting time units.
   *
   * See [DateTime] to represent a point in time.
   * See [Stopwatch] to measure time-spans.
   *
   */
  class Duration implements Comparable<Duration> {
    static const int MICROSECONDS_PER_MILLISECOND = 1000;
    static const int MILLISECONDS_PER_SECOND = 1000;
    static const int SECONDS_PER_MINUTE = 60;
    static const int MINUTES_PER_HOUR = 60;
    static const int HOURS_PER_DAY = 24;
  
    static const int MICROSECONDS_PER_SECOND =
        MICROSECONDS_PER_MILLISECOND * MILLISECONDS_PER_SECOND;
    static const int MICROSECONDS_PER_MINUTE =
        MICROSECONDS_PER_SECOND * SECONDS_PER_MINUTE;
    static const int MICROSECONDS_PER_HOUR =
        MICROSECONDS_PER_MINUTE * MINUTES_PER_HOUR;
    static const int MICROSECONDS_PER_DAY =
        MICROSECONDS_PER_HOUR * HOURS_PER_DAY;
  
  
    static const int MILLISECONDS_PER_MINUTE =
        MILLISECONDS_PER_SECOND * SECONDS_PER_MINUTE;
    static const int MILLISECONDS_PER_HOUR =
        MILLISECONDS_PER_MINUTE * MINUTES_PER_HOUR;
    static const int MILLISECONDS_PER_DAY =
        MILLISECONDS_PER_HOUR * HOURS_PER_DAY;
  
    static const int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
    static const int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
  
    static const int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY;
  
    static const Duration ZERO = const Duration(seconds: 0);
  
    /*
     * The value of this Duration object in microseconds.
     */
    final int _duration;
  
    /**
     * Creates a new Duration object whose value
     * is the sum of all individual parts.
     *
     * Individual parts can be larger than the next-bigger unit.
     * For example, [hours] can be greater than 23.
     *
     * All individual parts are allowed to be negative.
     * All arguments are 0 by default.
     */
    const Duration({int days: 0,
                    int hours: 0,
                    int minutes: 0,
                    int seconds: 0,
                    int milliseconds: 0,
                    int microseconds: 0})
        : _duration = days * MICROSECONDS_PER_DAY +
                      hours * MICROSECONDS_PER_HOUR +
                      minutes * MICROSECONDS_PER_MINUTE +
                      seconds * MICROSECONDS_PER_SECOND +
                      milliseconds * MICROSECONDS_PER_MILLISECOND +
                      microseconds;
  
    /**
     * Adds this Duration and [other] and
     * returns the sum as a new Duration object.
     */
    Duration operator +(Duration other) {
      return new Duration(microseconds: _duration + other._duration);
    }
  
    /**
     * Subtracts [other] from this Duration and
     * returns the difference as a new Duration object.
     */
    Duration operator -(Duration other) {
      return new Duration(microseconds: _duration - other._duration);
    }
  
    /**
     * Multiplies this Duration by the given [factor] and returns the result
     * as a new Duration object.
     *
     * Note that when [factor] is a double, and the duration is greater than
     * 53 bits, precision is lost because of double-precision arithmetic.
     */
    Duration operator *(num factor) {
      return new Duration(microseconds: (_duration * factor).round());
    }
  
    /**
     * Divides this Duration by the given [quotient] and returns the truncated
     * result as a new Duration object.
     *
     * Throws an [IntegerDivisionByZeroException] if [quotient] is `0`.
     */
    Duration operator ~/(int quotient) {
      // By doing the check here instead of relying on "~/" below we get the
      // exception even with dart2js.
      if (quotient == 0) throw new IntegerDivisionByZeroException();
      return new Duration(microseconds: _duration ~/ quotient);
    }
  
    /**
     * Returns `true` if the value of this Duration
     * is less than the value of [other].
     */
    bool operator <(Duration other) => this._duration < other._duration;
  
    /**
     * Returns `true` if the value of this Duration
     * is greater than the value of [other].
     */
    bool operator >(Duration other) => this._duration > other._duration;
  
    /**
     * Returns `true` if the value of this Duration
     * is less than or equal to the value of [other].
     */
    bool operator <=(Duration other) => this._duration <= other._duration;
  
    /**
     * Returns `true` if the value of this Duration
     * is greater than or equal to the value of [other].
     */
    bool operator >=(Duration other) => this._duration >= other._duration;
  
    /**
     * Returns the number of whole days spanned by this Duration.
     */
    int get inDays => _duration ~/ Duration.MICROSECONDS_PER_DAY;
  
    /**
     * Returns the number of whole hours spanned by this Duration.
     *
     * The returned value can be greater than 23.
     */
    int get inHours => _duration ~/ Duration.MICROSECONDS_PER_HOUR;
  
    /**
     * Returns the number of whole minutes spanned by this Duration.
     *
     * The returned value can be greater than 59.
     */
    int get inMinutes => _duration ~/ Duration.MICROSECONDS_PER_MINUTE;
  
    /**
     * Returns the number of whole seconds spanned by this Duration.
     *
     * The returned value can be greater than 59.
     */
    int get inSeconds => _duration ~/ Duration.MICROSECONDS_PER_SECOND;
  
    /**
     * Returns number of whole milliseconds spanned by this Duration.
     *
     * The returned value can be greater than 999.
     */
    int get inMilliseconds => _duration ~/ Duration.MICROSECONDS_PER_MILLISECOND;
  
    /**
     * Returns number of whole microseconds spanned by this Duration.
     */
    int get inMicroseconds => _duration;
  
    /**
     * Returns `true` if this Duration is the same object as [other].
     */
    bool operator ==(other) {
      if (other is !Duration) return false;
      return _duration == other._duration;
    }
  
    int get hashCode => _duration.hashCode;
  
    /**
     * Compares this Duration to [other],
     * returning zero if the values are equal.
     *
     * This function returns a negative integer
     * if this Duration is smaller than [other],
     * or a positive integer if it is greater.
     */
    int compareTo(Duration other) => _duration.compareTo(other._duration);
  
    String toString() {
      String sixDigits(int n) {
        if (n >= 100000) return "$n";
        if (n >= 10000) return "0$n";
        if (n >= 1000) return "00$n";
        if (n >= 100) return "000$n";
        if (n > 10) return "0000$n";
        return "00000$n";
      }
      String twoDigits(int n) {
        if (n >= 10) return "$n";
        return "0$n";
      }
  
      if (inMicroseconds < 0) {
        Duration duration =
            new Duration(microseconds: -inMicroseconds);
        return "-$duration";
      }
      String twoDigitMinutes = twoDigits(inMinutes.remainder(MINUTES_PER_HOUR));
      String twoDigitSeconds = twoDigits(inSeconds.remainder(SECONDS_PER_MINUTE));
      String sixDigitUs =
          sixDigits(inMicroseconds.remainder(MICROSECONDS_PER_SECOND));
      return "$inHours:$twoDigitMinutes:$twoDigitSeconds.$sixDigitUs";
    }
  }
  