    //@include lib_Class.js
    /* eslint-disable */
    //@include lib_moment.js
    /* eslint-enable */

    /**
     * Utils for handling dates. This allows e.g. converting ELO ISO dates to moment.js date-objects.
     *
     * Uses moment.js for converting and handling date strings. Please refer to the official documentation of
     * moment.js for further information. http://momentjs.com/docs/
     *
     *     var momentDate = sol.common.DateUtils.isoToDate('20151203');
     *
     *     // add 7 days with moment.js
     *     var oneWeekAfter = momentDate.add(7, 'days');
     *
     * @eloall
     * @author PZ, ELO Digital Office GmbH
     *
     */
     sol.define("sol.common.DateUtils", {
      singleton: true,
      alternateClassName: "sol.Date",

      /**
       * @property
       * @private
       * Internal date formats used for checking and parsing
       */
      ISO_CONFIGS: {
        ISODATE: { format: "YYYYMMDD", regex: /^\d{8}$/ },
        ISODATETIME: { format: "YYYYMMDDHHmmss", regex: /^\d{14}$/ },
        ELOTSTAMP: { format: "YYYY.MM.DD.HH.mm.ss", regex: /^\d{4}(\.\d{2}){5}$/ },
        ISODATEMILLISECONDS: { format: "YYYYMMDDHHmmssSSS", regex: /^\d{17}$/ }
      },

      TIME_CONFIGS: {
        TIME: { format: "HH:mm", regex: /(\d\d?):(\d\d?)/ }
      },

      /**
       * Converts an iso date string to a date object
       * @param {String} isoDate The iso date string
       * @param {Object} config Configuration
       * @param {Boolean} config.startOfDay Return the start of the day
       * @param {Boolean} config.endOfDay Return the end of the day
       * @return {Date} A JavaScript Date object
       */
      isoToDate: function (isoDate, config) {
        var me = this,
            mom;

        if (!isoDate) {
          return;
        }

        mom = me.isoToMoment(isoDate, config);

        return mom.toDate();
      },

      /**
       * Converts an iso date string to a moment object
       * @param {String} isoDate The iso date string
       * @param {Object} config Configuration
       * @param {Boolean} config.asUtc Parse as UTC
       * @param {Boolean} config.startOfDay Return the start of the day
       * @param {Boolean} config.endOfDay Return the end of the day
       * @return {Moment} A Moment Date object
       *
       * https://momentjs.com/docs/#/parsing/
       */
      isoToMoment: function (isoDate, config) {
        var mom, cfg;

        if (!isoDate) {
          return;
        }

        config = config || {};

        for (cfg in this.ISO_CONFIGS) {
          if (this.ISO_CONFIGS.hasOwnProperty(cfg) && this.ISO_CONFIGS[cfg].regex.test(isoDate)) {
            if (config.asUtc) {
              mom = moment.utc(isoDate, this.ISO_CONFIGS[cfg].format, true);
            } else {
              mom = moment(isoDate, this.ISO_CONFIGS[cfg].format, true);
            }
            break;
          }
        }

        if (config.startOfDay) {
          mom = mom.startOf("day");
        } else if (config.endOfDay) {
          mom = mom.endOf("day");
        }

        if (!mom) {
          throw "sol.common.DateUtils.isoToDate: Wrong input format, must be an ELO iso date string: " + isoDate;
        }

        return mom;
      },

      /**
       * Converts a date object to an iso string
       * @param {Date} date The date object
       * @param {Object} params (optional)
       * @param {Boolean} [params.withoutTime=false] (optional) If set to `true`, the time will be omitted from the ISO string
       * @param {Boolean} [params.startOfDay=false] (optional) Start of day
       * @param {String|Number} params.utcOffset (optional) UTC offset
       * @param {Boolean} params.pattern Pattern
       * @return {String} The resulting iso date
       */
      dateToIso: function (date, params) {
        var me = this,
            isoDate, mo;

        params = params || {};
        mo = moment(date);

        isoDate = me.momentToIso(mo, params);

        return isoDate;
      },

      /**
       * Converts a moment object to an iso string
       * @param {Moment} mo The moment object
       * @param {Object} params (optional)
       * @param {Boolean} [params.withoutTime=false] (optional) If set to `true`, the time will be omitted from the ISO string
       * @param {Object} [params.add] (optional) Add timespan, e.g. `{ days: 1 }`, see moment.js documentation
       * @param {Boolean} [params.startOfDay=false] (optional) Start of day
       * @param {Boolean} [params.endOfDay=false] (optional) End of day
       * @param {String|Number} params.utcOffset (optional) UTC offset
       * @param {Boolean} params.pattern Pattern
       * @return {String} The resulting iso date
       */
      momentToIso: function (mo, params) {
        var me = this,
            isoDate;

        params = params || {};

        if (typeof params.utcOffset != "undefined") {
          mo.utcOffset(params.utcOffset);
        }

        if (params.add) {
          mo.add(params.add);
        }

        if (params.startOfDay) {
          mo.startOf("d");
        }

        if (params.endOfDay) {
          mo.endOf("d");
        }

        if (!params.pattern) {
          params.pattern = (params.withoutTime === true) ? me.ISO_CONFIGS.ISODATE.format : me.ISO_CONFIGS.ISODATETIME.format;
        }

        isoDate = mo.format(params.pattern);

        return isoDate;
      },

      /**
       * Returns now as iso string
       * @param {Object} params (optional)
       * @param {String} params.withMilliseconds
       * @param {String|Number} params.utcOffset
       * @return {String}
       */
      nowIso: function (params) {
        var me = this,
            now;

        params = params || {};

        if (params.withMilliseconds === true) {
          return String(moment().format(this.ISO_CONFIGS.ISODATEMILLISECONDS.format));
        }
        now = me.dateToIso(new Date(), params);
        return now;
      },

      /**
       * Adds or removes time units from a date object.
       *
       * The following example will substracts 3 days from myDate and returns a Date
       *
       *     sol.common.DateUtils.shift(myDate, -3)
       *
       * The following example will adds 7 hours to myDate and returns a String with the specified pattern:
       *
       *     sol.common.DateUtils.shift(myDate, 7, { pattern: "YYYY.MM.DD HH:mm:ss", unit: "h" })
       *
       * Supported `unit` patterns:
       *
       * - years: y
       * - half years: hy
       * - quarters: Q
       * - months: M
       * - weeks: w
       * - days: d
       * - hours: h
       * - minutes: m
       * - seconds: s
       * - milliseconds: ms
       *
       * @param {Date} date The date object which should be used as base for the shift
       * @param {Number} value The amount which should be shifted
       * @param {Object} params (optional) Additional parameters
       * @param {String} params.pattern (optional) Format string (see [moment.js](http://momentjs.com/) for formating options)
       * @param {String} [params.unit="d"] (optional) The unit which should be added/substracted
       * @return {Date|String} Returns a `String` if a params.pattern is defined and a `Date` if not.
       */
      shift: function (date, value, params) {
        var shifted, unit;

        shifted = moment(date.getTime());
        unit = (params && params.unit) ? params.unit : "d";

        if (unit == "hy") {
          unit = "M";
          value *= 6;
        }

        if (!(/^[yQMwdhms]$|^ms$|^hy$/.test(unit))) {
          throw "IllegalArgumentException: unsupported unit for shift: " + unit;
        }

        shifted.add(value, unit);

        return (params && params.pattern) ? shifted.format(params.pattern) : shifted.toDate();
      },

      /**
       * Formats a Date object.
       *
       *      sol.common.DateUtils.format(new Date(), "YYYY.MM.DD HH:mm:ss.SSS")
       *
       * @param {Date} date The date object
       * @param {String} pattern Format string (see [moment.js](http://momentjs.com/) for formating options)
       * @return {String}
       */
      format: function (date, pattern) {
        return moment(date.getTime()).format(pattern);
      },

      /**
       * Parses a date string with a given pattern.
       *
       *     var maythefourth = sol.common.DateUtils.parse("1977-05-04");
       *
       *     var maythefourth = sol.common.DateUtils.parse("04.05.1977", "DD.MM.YYYY");
       *
       *     var maythefourth = sol.common.DateUtils.parse("05/04/1977", "MM/DD/YYYY");
       *
       * If no `pattern` is defined the function tries to figure out the format by using various standards (see [moment.js/parsing](https://momentjs.com/docs/#/parsing/string/)).
       * For consistent results the use of `pattern` is encouraged.
       *
       * @param {String} dateString
       * @param {String} pattern (optional) Parse string (see [moment.js](http://momentjs.com/) for parsing options)
       * @return {Date} Returns `null` if date could not be determined
       */
      parse: function (dateString, pattern) {
        var mom, me = this;

        mom = me.createMoment(dateString, pattern);
        return (mom.isValid()) ? mom.toDate() : null;
      },

      /**
       * Create a moment object of the given dateString
       * @param {*} dateString
       * @param {String} pattern (optional) Parse string (see [moment.js](http://momentjs.com/) for parsing options)
       * @returns {Moment} Returns Moment object (Attention: the moment object could be invalid)
       */
      createMoment: function (dateString, pattern) {
        return (pattern) ? moment(dateString, pattern, true) : moment(dateString);
      },

      /**
       * Create a new fresh moment object by usage copy constructor of moment
       * @param {Moment} mom
       * @returns {Moment} Clone of the copy object, when the given moment obj was invalid it will be returned null
       */
      of: function (mom) {
        return mom && mom.isValid() ? moment(mom) : null;
      },

      /**
       * Calculates a difference between to dates
       * @param {Date} startDate Start date
       * @param {Date} endDate End date
       * @param {String} unit Unit
       * @param {Object} config Configuration
       * @param {Boolean} config.roundUp Round up
       * @return {Number}
       */
      diff: function (startDate, endDate, unit, config) {
        var number, isQuarter, isHalfYear;

        number;
        isQuarter = false;

        if (!startDate) {
          throw "Start date is empty";
        }

        if (!endDate) {
          throw "End date is empty";
        }

        if (!unit) {
          throw "Unit is empty";
        }

        if (unit == "O") {
          return 1;
        }

        if (unit == "Q") {
          isQuarter = true;
          unit = "M";
        }

        if (unit == "hy") {
          isHalfYear = true;
          unit = "M";
        }

        config = config || {};

        number = moment(endDate.getTime()).diff(startDate.getTime(), unit, true);

        number = isQuarter ? (number / 3) : number;
        number = isHalfYear ? (number / 6) : number;

        if (config.roundUp) {
          number = Math.ceil(number);
        }
        return number;
      },

      /**
       * Checks whether a date is between a start date and an end end date
       * @param {Date} [startDate=now] Start date
       * @param {Date} [endDate=now] End date
       * @param {Date} [checkDate=now] Check date
       * @return {Boolean}
       */
      isBetween: function (startDate, endDate, checkDate) {
        var checkMoment, startMoment, endMoment;

        startMoment = startDate ? moment(startDate.getTime()) : moment();
        endMoment = endDate ? moment(endDate.getTime()) : moment();
        checkMoment = checkDate ? moment(checkDate.getTime()) : moment();

        return checkMoment.isBetween(startMoment, endMoment);
      },

      /**
       * Prepare duration
       * @param {Number} number Duration
       * @param {String} unit Duration unit
       * @return {Object} Duration
       */
      prepareDuration: function (number, unit) {
        var duration, splitParts;

        if ((typeof number == "undefined") || (number == "")) {
          return;
        }

        unit += "";

        splitParts = unit.split(" ");
        unit = splitParts[0];

        unit = unit || "d";

        switch (unit) {
          case "y":
            duration = { years: number };
            break;

          case "hy":
            duration = { months: number * 6 };
            break;

          case "Q":
            duration = { months: number * 3 };
            break;

          case "M":
            duration = { months: number };
            break;

          case "w":
            duration = { weeks: number };
            break;

          case "d":
            duration = { days: number };
            break;

          case "h":
            duration = { hours: number };
            break;

          case "m":
            duration = { minutes: number };
            break;

          case "seconds":
            duration = { seconds: number };
            break;

          default:
            throw "Invalid duration unit: " + unit;
        }

        return duration;
      },

      /**
       * Returns the `end of` time of a specified period
       * @param {Moment} moment Moment
       * @param {String} unit Unit
       * @return {Moment} Moment
       */
      endOf: function (moment, unit) {
        var month;

        if (!unit) {
          return moment;
        }

        if (unit == "hy") {
          month = moment.month();
          while ((month != 5) && (month != 11)) {
            moment = moment.add({ month: 1 });
            month = moment.month();
          }
          moment = moment.endOf("M");
          return moment;
        }

        moment.endOf(unit);

        return moment;
      },

      /**
       * Transforms an ISO date
       * @param {String} isoDate ISO date
       * @param {Object} config Configuration
       * @param {Boolean} config.asUtc Parse as UTC
       * @param {String|Number} config.utcOffset UTC offset
       */
      transformIsoDate: function (isoDate, config) {
        var mo;
        if (!isoDate) {
          return "";
        }
        mo = sol.common.DateUtils.isoToMoment(isoDate, config);
        isoDate = sol.common.DateUtils.momentToIso(mo, config);

        return isoDate;
      },

      /**
       * Checks whether the given moment represents the last day of the month
       * @param {Moment} mom Moment
       * @param {Object} params Parameters
       * @param {Number} [config.toleranceDays==0] Tolerance days
       */
      isLastDayOfMonth: function (mom, params) {
        if (!mom) {
          return false;
        }

        params = params || {};
        params.toleranceDays = params.toleranceDays || 0;

        if ((mom.get("date") + params.toleranceDays) >= mom.daysInMonth()) {
          return true;
        }

        return false;
      },

      /**
       * Checks whether time is potentially a time string.
       * This means the time value has only digits except a colon in the middle
       * of the string. This corresponds to the Time format HH:mm
       * @param {*} time value to check
       * @returns true when time (without colon) has 4 characters at least and
       *   the whole timeString (without colon) is convertable to number
       */
      couldBeTime: function (time) {
        var val = time.replace(":", "");
        return !!(val.length && (val.length < 5) && isNaN(+val) === false);
      },

      /**
       * Checks whether the hour and minutes are in range.
       * This function is used the 24h by default.
       * @param {string|number} hour must be in range (0 <= hour < 25)
       * @param {string|number} minute must be in range (0 <= minute < 60)
       * @returns true then the passed values are in range
       */
      isValidTime: function (hour, minute) {
        return ((hour = +(hour)) >= 0 && hour < 25) && ((minute = +(minute)) >= 0 && minute < 60);
      },

      /**
       * Determines from the transferred time and completes missing temporal information
       *
       * For example, the function calculates from 01 -> 01:00
       * Times that are specified as 24:00 are converted to 00:00.
       *
       * If the value passed does not correspond to a potential time,
       * then an empty string is returned.
       *
       * Output format is HH:mm
       *
       * @param {string} time
       * @returns an expanded time valid time string (format: HH:mm)
       */
      fillTime: function (time) {
        var me = this, hours, minutes, match, padded,
          regex = me.TIME_CONFIGS.TIME.regex;

        if (!time || time.trim().length === 0) {
          return time;
        }

        function pad2(s) {
          return s.length === 1 ? "0" + s : s;
        }

        function pad4(s) {
          var len = s.length;
          // this function is sued when currente time string length is 3
          function decide3() {
            var h = s.substr(0, 2), m = s.substr(2, 1);
            return me.isValidTime(h, m)
              ? h + ("0" + m)
              : ("0" + h) + m;
          }
          // this function is used when current time string length is 2
          function decide2() {
            return (me.isValidTime(s, 0) && s + "00")
                  || (me.isValidTime(0, s) && "00" + s)
                  || ("0" + s[0] + "0" + s[1]);
          };

          return (len === 4 && s)
            || (len === 3 && decide3(s))
            || (len === 2 && decide2(s))
            || ("0" + s + "00");
        }

        function sanitizeHour(hour) {
          return hour === "24" ? "00" : hour;
        }

        if (time.indexOf(":") > 0) {
          if (match = time.match(regex)) {
            hours = pad2(match[1]);
            minutes = pad2(match[2]);
          } else {
            return "";
          }
        } else {
          // time is without colon
          padded = pad4(time);
          hours = padded.substr(0, 2);
          minutes = padded.substr(2, 2);
        }
        // when we detect hour=24 we have to convert it to zero
        hours = sanitizeHour(hours);
        if (me.isValidTime(hours, minutes)) {
          return hours + ":" + minutes;
        } else {
          return "";
        }
      }

    });

    //# sourceURL=lib_sol.common.DateUtils.js