{
    "file_diffs": [
        {
            "old_file_content": "import calendar\nimport re\nimport time\nfrom typing import NamedTuple, List, Union, Callable\nimport datetime\nfrom itertools import count\n\nimport numpy as np\nimport scipy.sparse as sp\n\nfrom Orange.data import DiscreteVariable, Domain\nfrom Orange.data.sql.table import SqlTable\nfrom Orange.statistics import distribution, contingency, util as ut\nfrom Orange.statistics.basic_stats import BasicStats\nfrom Orange.util import Reprable\nfrom .transformation import Transformation\nfrom . import _discretize\n\n__all__ = [\"EqualFreq\", \"EqualWidth\", \"EntropyMDL\", \"DomainDiscretizer\",\n           \"decimal_binnings\", \"time_binnings\", \"short_time_units\",\n           \"BinDefinition\"]\n\n\nclass Discretizer(Transformation):\n    \"\"\"Value transformer that returns an index of the bin for the given value.\n    \"\"\"\n    def __init__(self, variable, points):\n        super().__init__(variable)\n        self.points = points\n\n    @staticmethod\n    def digitize(x, bins):\n        if sp.issparse(x):\n            if len(bins):\n                x.data = np.digitize(x.data, bins)\n            else:\n                x = sp.csr_matrix(x.shape)\n            return x\n        else:\n            return np.digitize(x, bins) if len(bins) else [0]*len(x)\n\n    def transform(self, c):\n        if sp.issparse(c):\n            return self.digitize(c, self.points)\n        elif c.size:\n            return np.where(np.isnan(c), np.NaN, self.digitize(c, self.points))\n        else:\n            return np.array([], dtype=int)\n\n    @staticmethod\n    def _fmt_interval(low, high, formatter):\n        assert low is not None or high is not None\n        assert low is None or high is None or low < high\n        if low is None or np.isinf(low):\n            return f\"< {formatter(high)}\"\n        if high is None or np.isinf(high):\n            return f\"≥ {formatter(low)}\"\n        return f\"{formatter(low)} - {formatter(high)}\"\n\n    @classmethod\n    def create_discretized_var(cls, var, points):\n        def fmt(val):\n            sval = var.str_val(val)\n            # For decimal numbers, remove trailing 0's and . if no decimals left\n            if re.match(r\"^\\d+\\.\\d+\", sval):\n                return sval.rstrip(\"0\").rstrip(\".\")\n            return sval\n\n        lpoints = list(points)\n        if lpoints:\n            values = [\n                cls._fmt_interval(low, high, fmt)\n                for low, high in zip([-np.inf] + lpoints, lpoints + [np.inf])]\n            to_sql = BinSql(var, lpoints)\n        else:\n            values = [\"single_value\"]\n            to_sql = SingleValueSql(values[0])\n\n        dvar = DiscreteVariable(name=var.name, values=values,\n                                compute_value=cls(var, points),\n                                sparse=var.sparse)\n        dvar.source_variable = var\n        dvar.to_sql = to_sql\n        return dvar\n\n\nclass BinSql:\n    def __init__(self, var, points):\n        self.var = var\n        self.points = points\n\n    def __call__(self):\n        return 'width_bucket(%s, ARRAY%s::double precision[])' % (\n            self.var.to_sql(), str(self.points))\n\n\nclass SingleValueSql:\n    def __init__(self, value):\n        self.value = value\n\n    def __call__(self):\n        return \"'%s'\" % self.value\n\n\nclass Discretization(Reprable):\n    \"\"\"Abstract base class for discretization classes.\"\"\"\n    def __call__(self, data, variable):\n        \"\"\"\n        Compute discretization of the given variable on the given data.\n        Return a new variable with the appropriate domain\n        (:obj:`Orange.data.DiscreteVariable.values`) and transformer\n        (:obj:`Orange.data.Variable.compute_value`).\n        \"\"\"\n        raise NotImplementedError(\n            \"Subclasses of 'Discretization' need to implement \"\n            \"the call operator\")\n\n\nclass EqualFreq(Discretization):\n    \"\"\"Discretization into bins with approximately equal number of data\n    instances.\n\n    .. attribute:: n\n\n        Number of bins (default: 4). The actual number may be lower if the\n        variable has less than n distinct values.\n    \"\"\"\n    def __init__(self, n=4):\n        self.n = n\n\n    # noinspection PyProtectedMember\n    def __call__(self, data, attribute):\n        if type(data) == SqlTable:\n            att = attribute.to_sql()\n            quantiles = [(i + 1) / self.n for i in range(self.n - 1)]\n            query = data._sql_query(\n                ['quantile(%s, ARRAY%s)' % (att, str(quantiles))],\n                use_time_sample=1000)\n            with data._execute_sql_query(query) as cur:\n                points = sorted(set(cur.fetchone()[0]))\n        else:\n            d = distribution.get_distribution(data, attribute)\n            points = _discretize.split_eq_freq(d, self.n)\n        return Discretizer.create_discretized_var(\n            data.domain[attribute], points)\n\nclass EqualWidth(Discretization):\n    \"\"\"Discretization into a fixed number of bins with equal widths.\n\n    .. attribute:: n\n\n        Number of bins (default: 4).\n    \"\"\"\n    def __init__(self, n=4):\n        self.n = n\n\n    # noinspection PyProtectedMember\n    def __call__(self, data, attribute, fixed=None):\n        if fixed:\n            min, max = fixed[attribute.name]\n            points = self._split_eq_width(min, max)\n        else:\n            if type(data) == SqlTable:\n                stats = BasicStats(data, attribute)\n                points = self._split_eq_width(stats.min, stats.max)\n            else:\n                values = data[:, attribute]\n                values = values.X if values.X.size else values.Y\n                min, max = ut.nanmin(values), ut.nanmax(values)\n                points = self._split_eq_width(min, max)\n        return Discretizer.create_discretized_var(\n            data.domain[attribute], points)\n\n    def _split_eq_width(self, min, max):\n        if np.isnan(min) or np.isnan(max) or min == max:\n            return []\n        dif = (max - min) / self.n\n        return [min + (i + 1) * dif for i in range(self.n - 1)]\n\n\nclass BinDefinition(NamedTuple):\n    thresholds: np.ndarray  # thresholds, including the top\n    labels: List[str]  # friendly-formatted thresholds\n    short_labels: List[str]  # shorter labels (e.g. simplified dates)\n    width: Union[float, None]  # widths, if uniform; otherwise None\n    width_label: str  # friendly-formatted width (e.g. '50' or '2 weeks')\n\n\n# NamedTupleMeta doesn't allow to define __new__ so we need a subclass\n# Name of the class has to be the same to match the namedtuple name\n# pylint: disable=function-redefined\nclass BinDefinition(BinDefinition):\n    def __new__(cls, thresholds, labels=\"%g\",\n                short_labels=None, width=None, width_label=\"\"):\n\n        def get_labels(fmt, default=None):\n            if fmt is None:\n                return default\n            if isinstance(fmt, str):\n                return [fmt % x for x in thresholds]\n            elif isinstance(fmt, Callable):\n                return [fmt(x) for x in thresholds]\n            else:\n                return fmt\n\n        labels = get_labels(labels)\n        short_labels = get_labels(short_labels, labels)\n        if not width_label and width is not None:\n            width_label = f\"{width:g}\"\n        return super().__new__(\n            cls, thresholds, labels, short_labels, width, width_label)\n\n    @property\n    def start(self) -> float:\n        return self.thresholds[0]\n\n    @property\n    def nbins(self) -> int:\n        return len(self.thresholds) - 1\n\n\ndef decimal_binnings(\n        data, *, min_width=0, min_bins=2, max_bins=50,\n        min_unique=5, add_unique=0,\n        factors=(0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20),\n        label_fmt=\"%g\"):\n    \"\"\"\n    Find a set of nice splits of data into bins\n\n    The function first computes the scaling factor that is, the power of 10\n    that brings the interval of values within [0, 1]. For instances, if the\n    numbers come from interaval 10004001 and 10007005, the width of the\n    interval is 3004, so the scaling factor is 1000.\n\n    The function next considers bin widths that are products of scaling and\n    different factors from 20 to 0.01 that make sense in decimal scale\n    (see default value for argument `factors`). For each width, it rounds the\n    minimal value down to this width and the maximal value up, and it computes\n    the number of bins of that width that fit between these two values.\n    If the number of bins is between `min_bins` and `max_bins`, and the width\n    is at least `min_width`, this is a valid interval.\n\n    If the data has no more than `min_unique` unique values, the function will\n    add a set of bins that put each value into its own bin.\n\n    If the data has no more than `add_unique` values, that last bins will put\n    each value into its own bin.\n\n    Args:\n        data (np.ndarray):\n            vector of data points; values may repeat, and nans and infs are\n            filtered out.\n        min_width (float): minimal bin width\n        min_bins (int): minimal number of bins\n        max_bins (int):\n            maximal number of bins; the number of bins will never exceed the\n            number of unique values\n        min_unique (int):\n            if the number of unique values are less or equal to `min_unique`,\n            the function returns a single binning that matches that values in\n            the data\n        add_unique (int):\n            similar to `min_unique` except that such bins are added to the list;\n            set to 0 to disable\n        factors (list of float):\n            The factors with which the scaling is multiplied. Default is\n            `(0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20)`,\n            so if scaling is 1000, considered bin widths are 20000, 10000,\n            5000, 2000, 1000, 500, 250, 200, 100, 50, 25, 20 and 10.\n        label_fmt (str or Callable):\n            A format string (default: \"%g\") used for threshold labels,\n            or a function for formatting thresholds (e.g. var.str_val)\n\n    Returns:\n        bin_boundaries (list of np.ndarray): a list of bin boundaries,\n            including the top boundary of the last interval, hence the list\n            size equals the number bins + 1. These array match the `bin`\n            argument of `numpy.histogram`.\n\n            This is returned if `return_defs` is left `True`.\n\n        bin_definition (list of BinDefinition):\n            `BinDefinition` is a named tuple containing the beginning of the\n            first bin (`start`), number of bins (`nbins`) and their widths\n            (`width`). The last value can also be a `nd.array` with `nbins + 1`\n            elements, which describes bins of unequal width and is used for\n            binnings that match the unique values in the data (see `min_unique`\n            and `add_unique`).\n\n            This is returned if `return_defs` is `False`.\n    \"\"\"\n    bins = []\n\n    mn, mx, unique = _min_max_unique(data)\n    if len(unique) <= max(min_unique, add_unique):\n        bins.append(BinDefinition(_unique_thresholds(unique), label_fmt))\n        if len(unique) <= min_unique:\n            return bins\n\n    diff = mx - mn\n    f10 = 10 ** -np.floor(np.log10(diff))\n    max_bins = min(max_bins, len(unique))\n    for f in factors:\n        width = f / f10\n        if width < min_width:\n            continue\n        mn_ = np.floor(mn / width) * width\n        mx_ = np.ceil(mx / width) * width\n        nbins = np.round((mx_ - mn_) / width)\n        if min_bins <= nbins <= max_bins \\\n                and (not bins or bins[-1].nbins != nbins):\n            bin_def = BinDefinition(mn_ + width * np.arange(nbins + 1),\n                                    label_fmt, None, width)\n            bins.append(bin_def)\n    return bins\n\n\ndef time_binnings(data, *, min_bins=2, max_bins=50, min_unique=5, add_unique=0):\n    \"\"\"\n    Find a set of nice splits of time variable data into bins\n\n    The function considers bin widths of\n\n    - 1, 5, 10, 15, 30 seconds.\n    - 1, 5, 10, 15, 30 minutes,\n    - 1, 2, 3, 6, 12 hours,\n    - 1 day,\n    - 1, 2 weeks,\n    - 1, 2, 3, 6 months,\n    - 1, 2, 5, 10, 25, 50, 100 years,\n\n    and returns those that yield between `min_bins` and `max_bins` intervals.\n\n    Args:\n        data (np.ndarray):\n            vector of data points; values may repeat, and nans and infs are\n            filtered out.\n        min_bins (int): minimal number of bins\n        max_bins (int):\n            maximal number of bins; the number of bins will never exceed the\n            number of unique values\n\n    Returns:\n        bin_boundaries (list): a list of possible binning.\n            Each element of `bin_boundaries` is a tuple consisting of a label\n            describing the bin size (e.g. `2 weeks`) and a list of thresholds.\n            Thresholds are given as pairs\n            (number_of_seconds_since_epoch, label).\n    \"\"\"\n    mn, mx, unique = _min_max_unique(data)\n    mn, mx = time.gmtime(mn), time.gmtime(mx)\n    bins = []\n    if len(unique) <= max(min_unique, add_unique):\n        bins.append(_unique_time_bins(unique))\n    if len(unique) > min_unique:\n        bins += _time_binnings(mn, mx, min_bins + 1, max_bins + 1)\n    return bins\n\n\ndef _time_binnings(mn, mx, min_pts, max_pts):\n    yfmt = \"%y \" if mn.tm_year >= 1950 else \"%Y \"\n    bins = []\n    for place, step, fmt, unit in (\n            [(5, x, \"%H:%M:%S\", \"second\") for x in (1, 5, 10, 15, 30)] +\n            [(4, x, \"%b %d %H:%M\", \"minute\") for x in (1, 5, 10, 15, 30)] +\n            [(3, x, yfmt + \"%b %d %H:%M\", \"hour\") for x in (1, 2, 3, 6, 12)] +\n            [(2, 1, yfmt + \"%b %d\", \"day\")] +\n            [(2, x, yfmt + \"%b %d\", \"week\") for x in (7, 14)] +\n            [(1, x, yfmt + \"%b\", \"month\") for x in (1, 2, 3, 6)] +\n            [(0, x, yfmt.strip(), \"year\") for x in (1, 2, 5, 10, 25, 50, 100)]):\n        times = _time_range(mn, mx, place, step, min_pts, max_pts)\n        if not times:\n            continue\n        times = [time.struct_time(t + (0, 0, 0)) for t in times]\n        thresholds = [calendar.timegm(t) for t in times]\n        labels = [time.strftime(fmt, t) for t in times]\n        short_labels = _simplified_labels(labels)\n        if place == 2 and step >= 7:\n            unit_label = f\"{step // 7} week{'s' * (step > 7)}\"\n        else:\n            unit_label = f\"{step} {unit}{'s' * (step > 1)}\"\n        new_bins = BinDefinition(\n            thresholds, labels, short_labels, None, unit_label)\n        if not bins or new_bins.nbins != bins[-1].nbins:\n            bins.append(new_bins)\n    return bins\n\n\n# datetime + deltatime is not very useful here because deltatime is\n# given a number of days, not years or months, so it doesn't allow\n# for specifying a step of 1 month\ndef _time_range(start, end, place, step, min_pts, max_pts,\n                _zeros=(0, 1, 1, 0, 0, 0)):\n    if place == 2 and step % 7 == 0:\n        startd = datetime.date(*start[:3])\n        startd -= datetime.timedelta(days=-startd.weekday())\n        start = [startd.year, startd.month, startd.day, 0, 0, 0]\n    else:\n        start = list(\n            start[:place]\n            + ((start[place] - _zeros[place]) // step * step + _zeros[place], )\n            + _zeros[place + 1:])\n    end = list(end[:place + 1] + _zeros[place + 1:])\n    s = [tuple(start)]\n    for _ in range(max_pts - 1):\n        start[place] += step\n        if place >= 3:  # hours, minutes, seconds\n            for pos, maxval in enumerate((60, 60, 24), start=1):\n                if start[-pos] >= maxval:\n                    start[-pos - 1] += 1\n                    start[-pos] %= maxval\n        if place >= 2:\n            md = _month_days(*start[:2])\n            if start[2] > md:\n                start[1] += 1\n                start[2] %= md\n        if start[1] > 12:\n            start[0] += 1\n            start[1] %= 12\n        s.append(tuple(start))\n        if start > end:\n            return s if len(s) >= min_pts else None\n    return None\n\n\ndef _month_days(year, month,\n                _md=(None, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)):\n    return _md[month] + (\n        month == 2 and (year % 400 == 0 or year % 4 == 0 and year % 100 != 0))\n\n\ndef _simplified_labels(labels):\n    labels = labels[:]\n    to_remove = \"42\"\n    while True:\n        firsts = {f for f, *_ in (lab.split() for lab in labels)}\n        if len(firsts) > 1:\n            break\n        to_remove = firsts.pop()\n        flen = len(to_remove) + 1\n        if any(len(lab) == flen for lab in labels):\n            break\n        labels = [lab[flen:] for lab in labels]\n    for i in range(len(labels) - 1, 0, -1):\n        for k, c, d in zip(count(), labels[i].split(), labels[i - 1].split()):\n            if c != d:\n                labels[i] = \" \".join(labels[i].split()[k:])\n                break\n    # If the last thing removed were month names and the labels continues with\n    # hours, keep month name in the first label; \"08 12:29\" looks awkward.\n    if not to_remove[0].isdigit() and \":\" in labels[0]:\n        labels[0] = f\"{to_remove} {labels[0]}\"\n    return labels\n\n\ndef _unique_time_bins(unique):\n    times = [time.gmtime(x) for x in unique]\n    fmt = f'{\"%y \" if times[0][0] >= 1950 else \"%Y \"} %b %d'\n    fmt += \" %H:%M\" * (len({t[2:] for t in times}) > 1)\n    fmt += \":%S\" * bool(np.all(unique % 60 == 0))\n    labels = [time.strftime(fmt, x) for x in times]\n    short_labels = _simplified_labels(labels)\n    return BinDefinition(_unique_thresholds(unique), labels, short_labels)\n\n\ndef _unique_thresholds(unique):\n    if len(unique) >= 2:\n        # make the last bin the same width as the one before\n        last_boundary = 2 * unique[-1] - unique[-2]\n    else:\n        last_boundary = unique[0] + 1\n    return np.hstack((unique, [last_boundary]))\n\n\ndef _min_max_unique(data):\n    unique = np.unique(data)\n    unique = unique[np.isfinite(unique)]\n    if not unique.size:\n        raise ValueError(\"no valid (non-nan) data\")\n    return unique[0], unique[-1], unique\n\n\nshort_time_units = dict(seconds=\"sec\", minutes=\"min\", hours=\"hrs\",\n                        weeks=\"wks\", months=\"mon\", years=\"yrs\",\n                        second=\"sec\", minute=\"min\", month=\"mon\")\n\n\n# noinspection PyPep8Naming\nclass EntropyMDL(Discretization):\n    \"\"\"\n    Discretization into bins inferred by recursively splitting the values to\n    minimize the class-entropy. The procedure stops when further splits would\n    decrease the entropy for less than the corresponding increase of minimal\n    description length (MDL). [FayyadIrani93].\n\n    If there are no suitable cut-off points, the procedure returns a single bin,\n    which means that the new feature is constant and can be removed.\n\n    .. attribute:: force\n\n        Induce at least one cut-off point, even when its information\n        gain is lower than MDL (default: False).\n\n    \"\"\"\n    def __init__(self, force=False):\n        self.force = force\n\n    def __call__(self, data, attribute):\n        cont = contingency.get_contingency(data, attribute)\n        values, I = cont.values, cont.counts.T\n        cut_ind = np.array(self._entropy_discretize_sorted(I, self.force))\n        if len(cut_ind) > 0:\n            # \"the midpoint between each successive pair of examples\" (FI p.1)\n            points = (values[cut_ind] + values[cut_ind - 1]) / 2.\n        else:\n            points = []\n        return Discretizer.create_discretized_var(\n            data.domain[attribute], points)\n\n    @classmethod\n    def _normalize(cls, X, axis=None, out=None):\n        \"\"\"\n        Normalize `X` array so it sums to 1.0 over the `axis`.\n\n        Parameters\n        ----------\n        X : array\n            Array to normalize.\n        axis : optional int\n            Axis over which the resulting array sums to 1.\n        out : optional array\n            Output array of the same shape as X.\n        \"\"\"\n        X = np.asarray(X, dtype=float)\n        scale = np.sum(X, axis=axis, keepdims=True)\n        if out is None:\n            return X / scale\n        else:\n            if out is not X:\n                assert out.shape == X.shape\n                out[:] = X\n            out /= scale\n            return out\n\n    @classmethod\n    def _entropy_normalized(cls, D, axis=None):\n        \"\"\"\n        Compute the entropy of distribution array `D`.\n\n        `D` must be a distribution (i.e. sum to 1.0 over `axis`)\n\n        Parameters\n        ----------\n        D : array\n            Distribution.\n        axis : optional int\n            Axis of `D` along which to compute the entropy.\n\n        \"\"\"\n        # req: (np.sum(D, axis=axis) >= 0).all()\n        # req: (np.sum(D, axis=axis) <= 1).all()\n        # req: np.all(np.abs(np.sum(D, axis=axis) - 1) < 1e-9)\n\n        D = np.asarray(D)\n        Dc = np.clip(D, np.finfo(D.dtype).eps, 1.0)\n        return - np.sum(D * np.log2(Dc), axis=axis)\n\n    @classmethod\n    def _entropy(cls, D, axis=None):\n        \"\"\"\n        Compute the entropy of distribution `D`.\n\n        Parameters\n        ----------\n        D : array\n            Distribution.\n        axis : optional int\n            Axis of `D` along which to compute the entropy.\n\n        \"\"\"\n        D = cls._normalize(D, axis=axis)\n        return cls._entropy_normalized(D, axis=axis)\n\n    @classmethod\n    def _entropy1(cls, D):\n        \"\"\"\n        Compute the entropy of distributions in `D`\n        (one per each row).\n        \"\"\"\n        D = cls._normalize(D)\n        return _discretize.entropy_normalized1(D)\n\n    @classmethod\n    def _entropy2(cls, D):\n        \"\"\"\n        Compute the entropy of distributions in `D`\n        (one per each row).\n        \"\"\"\n        D = cls._normalize(D, axis=1)\n        return _discretize.entropy_normalized2(D)\n\n    @classmethod\n    def _entropy_cuts_sorted(cls, CS):\n        \"\"\"\n        Return the class information entropy induced by partitioning\n        the `CS` distribution at all N-1 candidate cut points.\n\n        Parameters\n        ----------\n        CS : (N, K) array of class distributions.\n        \"\"\"\n        CS = np.asarray(CS)\n        # |--|-------|--------|\n        #  S1    ^       S2\n        # S1 contains all points which are <= to cut point\n        # Cumulative distributions for S1 and S2 (left right set)\n        # i.e. a cut at index i separates the CS into S1Dist[i] and S2Dist[i]\n        S1Dist = np.cumsum(CS, axis=0)[:-1]\n        S2Dist = np.cumsum(CS[::-1], axis=0)[-2::-1]\n\n        # Entropy of S1[i] and S2[i] sets\n        ES1 = cls._entropy2(S1Dist)\n        ES2 = cls._entropy2(S2Dist)\n\n        # Number of cases in S1[i] and S2[i] sets\n        S1_count = np.sum(S1Dist, axis=1)\n        S2_count = np.sum(S2Dist, axis=1)\n\n        # Number of all cases\n        S_count = np.sum(CS)\n\n        ES1w = ES1 * S1_count / S_count\n        ES2w = ES2 * S2_count / S_count\n\n        # E(A, T; S) Class information entropy of the partition S\n        E = ES1w + ES2w\n\n        return E, ES1, ES2\n\n    @classmethod\n    def _entropy_discretize_sorted(cls, C, force=False):\n        \"\"\"\n        Entropy discretization on a sorted C.\n\n        :param C: (N, K) array of class distributions.\n\n        \"\"\"\n        E, ES1, ES2 = cls._entropy_cuts_sorted(C)\n        # TODO: Also get the left right distribution counts from\n        # entropy_cuts_sorted,\n\n        # Note the + 1\n        if len(E) == 0:\n            return []\n        cut_index = np.argmin(E) + 1\n\n        # Distribution of classed in S1, S2 and S\n        S1_c = np.sum(C[:cut_index], axis=0)\n        S2_c = np.sum(C[cut_index:], axis=0)\n        S_c = S1_c + S2_c\n\n        ES = cls._entropy1(np.sum(C, axis=0))\n        ES1, ES2 = ES1[cut_index - 1], ES2[cut_index - 1]\n\n        # Information gain of the best split\n        Gain = ES - E[cut_index - 1]\n        # Number of different classes in S, S1 and S2\n        k = float(np.sum(S_c > 0))\n        k1 = float(np.sum(S1_c > 0))\n        k2 = float(np.sum(S2_c > 0))\n\n        assert k > 0\n        delta = np.log2(3 ** k - 2) - (k * ES - k1 * ES1 - k2 * ES2)\n        N = float(np.sum(S_c))\n\n        if Gain > np.log2(N - 1) / N + delta / N:\n            # Accept the cut point and recursively split the subsets.\n            left, right = [], []\n            if k1 > 1 and cut_index > 1:\n                left = cls._entropy_discretize_sorted(C[:cut_index, :])\n            if k2 > 1 and cut_index < len(C) - 1:\n                right = cls._entropy_discretize_sorted(C[cut_index:, :])\n            return left + [cut_index] + [i + cut_index for i in right]\n        elif force:\n            return [cut_index]\n        else:\n            return []\n\n\nclass DomainDiscretizer(Reprable):\n    \"\"\"Discretizes all continuous features in the data.\n\n    .. attribute:: method\n\n        Feature discretization method (instance of\n        :obj:`Orange.preprocess.Discretization`). If `None` (default),\n        :class:`Orange.preprocess.EqualFreq` with 4 intervals is\n        used.\n\n    .. attribute:: clean\n\n        If `True`, features discretized into a single interval constant are\n        removed. This is useful for discretization methods that infer the\n        number of intervals from the data, such as\n        :class:`Orange.preprocess.EntropyMDL` (default: `True`).\n\n    .. attribute:: discretize_class\n\n        Determines whether a target is also discretized if it is continuous.\n        (default: `False`)\n    \"\"\"\n    def __init__(self, discretize_class=False, method=None, clean=True,\n                 fixed=None):\n        self.discretize_class = discretize_class\n        self.method = method\n        self.clean = clean\n        self.fixed = fixed\n\n    def __call__(self, data, fixed=None):\n        \"\"\"\n        Compute and return discretized domain.\n\n        :param data: Data to discretize.\n        \"\"\"\n\n        def transform_list(s, fixed=None):\n            new_vars = []\n            for var in s:\n                if var.is_continuous:\n                    if fixed and var.name in fixed.keys():\n                        nv = method(data, var, fixed)\n                    else:\n                        nv = method(data, var)\n                    if not self.clean or len(nv.values) > 1:\n                        new_vars.append(nv)\n                else:\n                    new_vars.append(var)\n            return new_vars\n        if self.method is None:\n            method = EqualFreq(n=4)\n        else:\n            method = self.method\n        domain = data.domain\n        new_attrs = transform_list(domain.attributes, fixed or self.fixed)\n        if self.discretize_class:\n            new_classes = transform_list(domain.class_vars)\n        else:\n            new_classes = domain.class_vars\n        return Domain(new_attrs, new_classes)\n",
            "new_file_content": "import calendar\nimport re\nimport time\nfrom typing import NamedTuple, List, Union, Callable\nimport datetime\nfrom itertools import count\n\nimport numpy as np\nimport scipy.sparse as sp\n\nfrom Orange.data import DiscreteVariable, Domain\nfrom Orange.data.sql.table import SqlTable\nfrom Orange.statistics import distribution, contingency, util as ut\nfrom Orange.statistics.basic_stats import BasicStats\nfrom Orange.util import Reprable\nfrom .transformation import Transformation\nfrom . import _discretize\n\n__all__ = [\"EqualFreq\", \"EqualWidth\", \"EntropyMDL\", \"DomainDiscretizer\",\n           \"decimal_binnings\", \"time_binnings\", \"short_time_units\",\n           \"BinDefinition\"]\n\n\nclass Discretizer(Transformation):\n    \"\"\"Value transformer that returns an index of the bin for the given value.\n    \"\"\"\n    def __init__(self, variable, points):\n        super().__init__(variable)\n        self.points = points\n\n    @staticmethod\n    def digitize(x, bins):\n        if sp.issparse(x):\n            if len(bins):\n                x.data = np.digitize(x.data, bins)\n            else:\n                x = sp.csr_matrix(x.shape)\n            return x\n        else:\n            return np.digitize(x, bins) if len(bins) else [0]*len(x)\n\n    def transform(self, c):\n        if sp.issparse(c):\n            return self.digitize(c, self.points)\n        elif c.size:\n            return np.where(np.isnan(c), np.NaN, self.digitize(c, self.points))\n        else:\n            return np.array([], dtype=int)\n\n    @staticmethod\n    def _fmt_interval(low, high, formatter):\n        assert low is not None or high is not None\n        assert low is None or high is None or low < high\n        if low is None or np.isinf(low):\n            return f\"< {formatter(high)}\"\n        if high is None or np.isinf(high):\n            return f\"≥ {formatter(low)}\"\n        return f\"{formatter(low)} - {formatter(high)}\"\n\n    @classmethod\n    def create_discretized_var(cls, var, points):\n        def fmt(val):\n            sval = var.str_val(val)\n            # For decimal numbers, remove trailing 0's and . if no decimals left\n            if re.match(r\"^\\d+\\.\\d+\", sval):\n                return sval.rstrip(\"0\").rstrip(\".\")\n            return sval\n\n        lpoints = list(points)\n        if lpoints:\n            values = [\n                cls._fmt_interval(low, high, fmt)\n                for low, high in zip([-np.inf] + lpoints, lpoints + [np.inf])]\n            to_sql = BinSql(var, lpoints)\n        else:\n            values = [\"single_value\"]\n            to_sql = SingleValueSql(values[0])\n\n        dvar = DiscreteVariable(name=var.name, values=values,\n                                compute_value=cls(var, points),\n                                sparse=var.sparse)\n        dvar.source_variable = var\n        dvar.to_sql = to_sql\n        return dvar\n\n\nclass BinSql:\n    def __init__(self, var, points):\n        self.var = var\n        self.points = points\n\n    def __call__(self):\n        return 'width_bucket(%s, ARRAY%s::double precision[])' % (\n            self.var.to_sql(), str(self.points))\n\n\nclass SingleValueSql:\n    def __init__(self, value):\n        self.value = value\n\n    def __call__(self):\n        return \"'%s'\" % self.value\n\n\nclass Discretization(Reprable):\n    \"\"\"Abstract base class for discretization classes.\"\"\"\n    def __call__(self, data, variable):\n        \"\"\"\n        Compute discretization of the given variable on the given data.\n        Return a new variable with the appropriate domain\n        (:obj:`Orange.data.DiscreteVariable.values`) and transformer\n        (:obj:`Orange.data.Variable.compute_value`).\n        \"\"\"\n        raise NotImplementedError(\n            \"Subclasses of 'Discretization' need to implement \"\n            \"the call operator\")\n\n\nclass EqualFreq(Discretization):\n    \"\"\"Discretization into bins with approximately equal number of data\n    instances.\n\n    .. attribute:: n\n\n        Number of bins (default: 4). The actual number may be lower if the\n        variable has less than n distinct values.\n    \"\"\"\n    def __init__(self, n=4):\n        self.n = n\n\n    # noinspection PyProtectedMember\n    def __call__(self, data, attribute):\n        if type(data) == SqlTable:\n            att = attribute.to_sql()\n            quantiles = [(i + 1) / self.n for i in range(self.n - 1)]\n            query = data._sql_query(\n                ['quantile(%s, ARRAY%s)' % (att, str(quantiles))],\n                use_time_sample=1000)\n            with data._execute_sql_query(query) as cur:\n                points = sorted(set(cur.fetchone()[0]))\n        else:\n            d = distribution.get_distribution(data, attribute)\n            points = _discretize.split_eq_freq(d, self.n)\n        return Discretizer.create_discretized_var(\n            data.domain[attribute], points)\n\nclass EqualWidth(Discretization):\n    \"\"\"Discretization into a fixed number of bins with equal widths.\n\n    .. attribute:: n\n\n        Number of bins (default: 4).\n    \"\"\"\n    def __init__(self, n=4):\n        self.n = n\n\n    # noinspection PyProtectedMember\n    def __call__(self, data, attribute, fixed=None):\n        if fixed:\n            min, max = fixed[attribute.name]\n            points = self._split_eq_width(min, max)\n        else:\n            if type(data) == SqlTable:\n                stats = BasicStats(data, attribute)\n                points = self._split_eq_width(stats.min, stats.max)\n            else:\n                values = data[:, attribute]\n                values = values.X if values.X.size else values.Y\n                min, max = ut.nanmin(values), ut.nanmax(values)\n                points = self._split_eq_width(min, max)\n        return Discretizer.create_discretized_var(\n            data.domain[attribute], points)\n\n    def _split_eq_width(self, min, max):\n        if np.isnan(min) or np.isnan(max) or min == max:\n            return []\n        dif = (max - min) / self.n\n        return [min + (i + 1) * dif for i in range(self.n - 1)]\n\n\nclass BinDefinition(NamedTuple):\n    thresholds: np.ndarray  # thresholds, including the top\n    labels: List[str]  # friendly-formatted thresholds\n    short_labels: List[str]  # shorter labels (e.g. simplified dates)\n    width: Union[float, None]  # widths, if uniform; otherwise None\n    width_label: str  # friendly-formatted width (e.g. '50' or '2 weeks')\n\n\n# NamedTupleMeta doesn't allow to define __new__ so we need a subclass\n# Name of the class has to be the same to match the namedtuple name\n# pylint: disable=function-redefined\nclass BinDefinition(BinDefinition):\n    def __new__(cls, thresholds, labels=\"%g\",\n                short_labels=None, width=None, width_label=\"\"):\n\n        def get_labels(fmt, default=None):\n            if fmt is None:\n                return default\n            if isinstance(fmt, str):\n                return [fmt % x for x in thresholds]\n            elif isinstance(fmt, Callable):\n                return [fmt(x) for x in thresholds]\n            else:\n                return fmt\n\n        labels = get_labels(labels)\n        short_labels = get_labels(short_labels, labels)\n        if not width_label and width is not None:\n            width_label = f\"{width:g}\"\n        return super().__new__(\n            cls, thresholds, labels, short_labels, width, width_label)\n\n    @property\n    def start(self) -> float:\n        return self.thresholds[0]\n\n    @property\n    def nbins(self) -> int:\n        return len(self.thresholds) - 1\n\n\ndef decimal_binnings(\n        data, *, min_width=0, min_bins=2, max_bins=50,\n        min_unique=5, add_unique=0,\n        factors=(0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20),\n        label_fmt=\"%g\"):\n    \"\"\"\n    Find a set of nice splits of data into bins\n\n    The function first computes the scaling factor that is, the power of 10\n    that brings the interval of values within [0, 1]. For instances, if the\n    numbers come from interaval 10004001 and 10007005, the width of the\n    interval is 3004, so the scaling factor is 1000.\n\n    The function next considers bin widths that are products of scaling and\n    different factors from 20 to 0.01 that make sense in decimal scale\n    (see default value for argument `factors`). For each width, it rounds the\n    minimal value down to this width and the maximal value up, and it computes\n    the number of bins of that width that fit between these two values.\n    If the number of bins is between `min_bins` and `max_bins`, and the width\n    is at least `min_width`, this is a valid interval.\n\n    If the data has no more than `min_unique` unique values, the function will\n    add a set of bins that put each value into its own bin.\n\n    If the data has no more than `add_unique` values, that last bins will put\n    each value into its own bin.\n\n    Args:\n        data (np.ndarray):\n            vector of data points; values may repeat, and nans and infs are\n            filtered out.\n        min_width (float): minimal bin width\n        min_bins (int): minimal number of bins\n        max_bins (int):\n            maximal number of bins; the number of bins will never exceed the\n            number of unique values\n        min_unique (int):\n            if the number of unique values are less or equal to `min_unique`,\n            the function returns a single binning that matches that values in\n            the data\n        add_unique (int):\n            similar to `min_unique` except that such bins are added to the list;\n            set to 0 to disable\n        factors (list of float):\n            The factors with which the scaling is multiplied. Default is\n            `(0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20)`,\n            so if scaling is 1000, considered bin widths are 20000, 10000,\n            5000, 2000, 1000, 500, 250, 200, 100, 50, 25, 20 and 10.\n        label_fmt (str or Callable):\n            A format string (default: \"%g\") used for threshold labels,\n            or a function for formatting thresholds (e.g. var.str_val)\n\n    Returns:\n        bin_boundaries (list of np.ndarray): a list of bin boundaries,\n            including the top boundary of the last interval, hence the list\n            size equals the number bins + 1. These array match the `bin`\n            argument of `numpy.histogram`.\n\n            This is returned if `return_defs` is left `True`.\n\n        bin_definition (list of BinDefinition):\n            `BinDefinition` is a named tuple containing the beginning of the\n            first bin (`start`), number of bins (`nbins`) and their widths\n            (`width`). The last value can also be a `nd.array` with `nbins + 1`\n            elements, which describes bins of unequal width and is used for\n            binnings that match the unique values in the data (see `min_unique`\n            and `add_unique`).\n\n            This is returned if `return_defs` is `False`.\n    \"\"\"\n    bins = []\n\n    mn, mx, unique = _min_max_unique(data)\n    if len(unique) <= max(min_unique, add_unique):\n        bins.append(BinDefinition(_unique_thresholds(unique), label_fmt))\n        if len(unique) <= min_unique:\n            return bins\n\n    diff = mx - mn\n    f10 = 10 ** -np.floor(np.log10(diff))\n    max_bins = min(max_bins, len(unique))\n    for f in factors:\n        width = f / f10\n        if width < min_width:\n            continue\n        mn_ = np.floor(mn / width) * width\n        mx_ = np.ceil(mx / width) * width\n        nbins = np.round((mx_ - mn_) / width)\n        if min_bins <= nbins <= max_bins \\\n                and (not bins or bins[-1].nbins != nbins):\n            bin_def = BinDefinition(mn_ + width * np.arange(nbins + 1),\n                                    label_fmt, None, width)\n            bins.append(bin_def)\n    return bins\n\n\ndef time_binnings(data, *, min_bins=2, max_bins=50, min_unique=5, add_unique=0):\n    \"\"\"\n    Find a set of nice splits of time variable data into bins\n\n    The function considers bin widths of\n\n    - 1, 5, 10, 15, 30 seconds.\n    - 1, 5, 10, 15, 30 minutes,\n    - 1, 2, 3, 6, 12 hours,\n    - 1 day,\n    - 1, 2 weeks,\n    - 1, 2, 3, 6 months,\n    - 1, 2, 5, 10, 25, 50, 100 years,\n\n    and returns those that yield between `min_bins` and `max_bins` intervals.\n\n    Args:\n        data (np.ndarray):\n            vector of data points; values may repeat, and nans and infs are\n            filtered out.\n        min_bins (int): minimal number of bins\n        max_bins (int):\n            maximal number of bins; the number of bins will never exceed the\n            number of unique values\n\n    Returns:\n        bin_boundaries (list): a list of possible binning.\n            Each element of `bin_boundaries` is a tuple consisting of a label\n            describing the bin size (e.g. `2 weeks`) and a list of thresholds.\n            Thresholds are given as pairs\n            (number_of_seconds_since_epoch, label).\n    \"\"\"\n    mn, mx, unique = _min_max_unique(data)\n    mn, mx = time.gmtime(mn), time.gmtime(mx)\n    bins = []\n    if len(unique) <= max(min_unique, add_unique):\n        bins.append(_unique_time_bins(unique))\n    if len(unique) > min_unique:\n        bins += _time_binnings(mn, mx, min_bins + 1, max_bins + 1)\n    return bins\n\n\ndef _time_binnings(mn, mx, min_pts, max_pts):\n    bins = []\n    for place, step, fmt, unit in (\n            [(5, x, \"%H:%M:%S\", \"second\") for x in (1, 5, 10, 15, 30)] +\n            [(4, x, \"%b %d %H:%M\", \"minute\") for x in (1, 5, 10, 15, 30)] +\n            [(3, x, \"%y %b %d %H:%M\", \"hour\") for x in (1, 2, 3, 6, 12)] +\n            [(2, 1, \"%y %b %d\", \"day\")] +\n            [(2, x, \"%y %b %d\", \"week\") for x in (7, 14)] +\n            [(1, x, \"%y %b\", \"month\") for x in (1, 2, 3, 6)] +\n            [(0, x, \"%Y\", \"year\") for x in (1, 2, 5, 10, 25, 50, 100)]):\n        times = _time_range(mn, mx, place, step, min_pts, max_pts)\n        if not times:\n            continue\n        times = [time.struct_time(t + (0, 0, 0)) for t in times]\n        thresholds = [calendar.timegm(t) for t in times]\n        labels = [time.strftime(fmt, t) for t in times]\n        short_labels = _simplified_labels(labels)\n        if place == 2 and step >= 7:\n            unit_label = f\"{step // 7} week{'s' * (step > 7)}\"\n        else:\n            unit_label = f\"{step} {unit}{'s' * (step > 1)}\"\n        new_bins = BinDefinition(\n            thresholds, labels, short_labels, None, unit_label)\n        if not bins or new_bins.nbins != bins[-1].nbins:\n            bins.append(new_bins)\n    return bins\n\n\n# datetime + deltatime is not very useful here because deltatime is\n# given a number of days, not years or months, so it doesn't allow\n# for specifying a step of 1 month\ndef _time_range(start, end, place, step, min_pts, max_pts,\n                _zeros=(0, 1, 1, 0, 0, 0)):\n    if place == 2 and step % 7 == 0:\n        startd = datetime.date(*start[:3])\n        startd -= datetime.timedelta(days=-startd.weekday())\n        start = [startd.year, startd.month, startd.day, 0, 0, 0]\n    else:\n        start = list(\n            start[:place]\n            + ((start[place] - _zeros[place]) // step * step + _zeros[place], )\n            + _zeros[place + 1:])\n    end = list(end[:place + 1] + _zeros[place + 1:])\n    s = [tuple(start)]\n    for _ in range(max_pts - 1):\n        start[place] += step\n        if place >= 3:  # hours, minutes, seconds\n            for pos, maxval in enumerate((60, 60, 24), start=1):\n                if start[-pos] >= maxval:\n                    start[-pos - 1] += 1\n                    start[-pos] %= maxval\n        if place >= 2:\n            md = _month_days(*start[:2])\n            if start[2] > md:\n                start[1] += 1\n                start[2] %= md\n        if start[1] > 12:\n            start[0] += 1\n            start[1] %= 12\n        s.append(tuple(start))\n        if start > end:\n            return s if len(s) >= min_pts else None\n    return None\n\n\ndef _month_days(year, month,\n                _md=(None, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)):\n    return _md[month] + (\n        month == 2 and (year % 400 == 0 or year % 4 == 0 and year % 100 != 0))\n\n\ndef _simplified_labels(labels):\n    labels = labels[:]\n    to_remove = \"42\"\n    while True:\n        firsts = {f for f, *_ in (lab.split() for lab in labels)}\n        if len(firsts) > 1:\n            break\n        to_remove = firsts.pop()\n        flen = len(to_remove)\n        if any(len(lab) == flen for lab in labels):\n            break\n        labels = [lab[flen+1:] for lab in labels]\n    for i in range(len(labels) - 1, 0, -1):\n        for k, c, d in zip(count(), labels[i].split(), labels[i - 1].split()):\n            if c != d:\n                labels[i] = \" \".join(labels[i].split()[k:])\n                break\n    # If the last thing removed were month names and the labels continues with\n    # hours, keep month name in the first label; \"08 12:29\" looks awkward.\n    if not to_remove[0].isdigit() and \":\" in labels[0]:\n        labels[0] = f\"{to_remove} {labels[0]}\"\n    return labels\n\n\ndef _unique_time_bins(unique):\n    times = [time.gmtime(x) for x in unique]\n    fmt = f'%y %b %d'\n    fmt += \" %H:%M\" * (len({t[2:] for t in times}) > 1)\n    fmt += \":%S\" * bool(np.all(unique % 60 == 0))\n    labels = [time.strftime(fmt, x) for x in times]\n    short_labels = _simplified_labels(labels)\n    return BinDefinition(_unique_thresholds(unique), labels, short_labels)\n\n\ndef _unique_thresholds(unique):\n    if len(unique) >= 2:\n        # make the last bin the same width as the one before\n        last_boundary = 2 * unique[-1] - unique[-2]\n    else:\n        last_boundary = unique[0] + 1\n    return np.hstack((unique, [last_boundary]))\n\n\ndef _min_max_unique(data):\n    unique = np.unique(data)\n    unique = unique[np.isfinite(unique)]\n    if not unique.size:\n        raise ValueError(\"no valid (non-nan) data\")\n    return unique[0], unique[-1], unique\n\n\nshort_time_units = dict(seconds=\"sec\", minutes=\"min\", hours=\"hrs\",\n                        weeks=\"wks\", months=\"mon\", years=\"yrs\",\n                        second=\"sec\", minute=\"min\", month=\"mon\")\n\n\n# noinspection PyPep8Naming\nclass EntropyMDL(Discretization):\n    \"\"\"\n    Discretization into bins inferred by recursively splitting the values to\n    minimize the class-entropy. The procedure stops when further splits would\n    decrease the entropy for less than the corresponding increase of minimal\n    description length (MDL). [FayyadIrani93].\n\n    If there are no suitable cut-off points, the procedure returns a single bin,\n    which means that the new feature is constant and can be removed.\n\n    .. attribute:: force\n\n        Induce at least one cut-off point, even when its information\n        gain is lower than MDL (default: False).\n\n    \"\"\"\n    def __init__(self, force=False):\n        self.force = force\n\n    def __call__(self, data, attribute):\n        cont = contingency.get_contingency(data, attribute)\n        values, I = cont.values, cont.counts.T\n        cut_ind = np.array(self._entropy_discretize_sorted(I, self.force))\n        if len(cut_ind) > 0:\n            # \"the midpoint between each successive pair of examples\" (FI p.1)\n            points = (values[cut_ind] + values[cut_ind - 1]) / 2.\n        else:\n            points = []\n        return Discretizer.create_discretized_var(\n            data.domain[attribute], points)\n\n    @classmethod\n    def _normalize(cls, X, axis=None, out=None):\n        \"\"\"\n        Normalize `X` array so it sums to 1.0 over the `axis`.\n\n        Parameters\n        ----------\n        X : array\n            Array to normalize.\n        axis : optional int\n            Axis over which the resulting array sums to 1.\n        out : optional array\n            Output array of the same shape as X.\n        \"\"\"\n        X = np.asarray(X, dtype=float)\n        scale = np.sum(X, axis=axis, keepdims=True)\n        if out is None:\n            return X / scale\n        else:\n            if out is not X:\n                assert out.shape == X.shape\n                out[:] = X\n            out /= scale\n            return out\n\n    @classmethod\n    def _entropy_normalized(cls, D, axis=None):\n        \"\"\"\n        Compute the entropy of distribution array `D`.\n\n        `D` must be a distribution (i.e. sum to 1.0 over `axis`)\n\n        Parameters\n        ----------\n        D : array\n            Distribution.\n        axis : optional int\n            Axis of `D` along which to compute the entropy.\n\n        \"\"\"\n        # req: (np.sum(D, axis=axis) >= 0).all()\n        # req: (np.sum(D, axis=axis) <= 1).all()\n        # req: np.all(np.abs(np.sum(D, axis=axis) - 1) < 1e-9)\n\n        D = np.asarray(D)\n        Dc = np.clip(D, np.finfo(D.dtype).eps, 1.0)\n        return - np.sum(D * np.log2(Dc), axis=axis)\n\n    @classmethod\n    def _entropy(cls, D, axis=None):\n        \"\"\"\n        Compute the entropy of distribution `D`.\n\n        Parameters\n        ----------\n        D : array\n            Distribution.\n        axis : optional int\n            Axis of `D` along which to compute the entropy.\n\n        \"\"\"\n        D = cls._normalize(D, axis=axis)\n        return cls._entropy_normalized(D, axis=axis)\n\n    @classmethod\n    def _entropy1(cls, D):\n        \"\"\"\n        Compute the entropy of distributions in `D`\n        (one per each row).\n        \"\"\"\n        D = cls._normalize(D)\n        return _discretize.entropy_normalized1(D)\n\n    @classmethod\n    def _entropy2(cls, D):\n        \"\"\"\n        Compute the entropy of distributions in `D`\n        (one per each row).\n        \"\"\"\n        D = cls._normalize(D, axis=1)\n        return _discretize.entropy_normalized2(D)\n\n    @classmethod\n    def _entropy_cuts_sorted(cls, CS):\n        \"\"\"\n        Return the class information entropy induced by partitioning\n        the `CS` distribution at all N-1 candidate cut points.\n\n        Parameters\n        ----------\n        CS : (N, K) array of class distributions.\n        \"\"\"\n        CS = np.asarray(CS)\n        # |--|-------|--------|\n        #  S1    ^       S2\n        # S1 contains all points which are <= to cut point\n        # Cumulative distributions for S1 and S2 (left right set)\n        # i.e. a cut at index i separates the CS into S1Dist[i] and S2Dist[i]\n        S1Dist = np.cumsum(CS, axis=0)[:-1]\n        S2Dist = np.cumsum(CS[::-1], axis=0)[-2::-1]\n\n        # Entropy of S1[i] and S2[i] sets\n        ES1 = cls._entropy2(S1Dist)\n        ES2 = cls._entropy2(S2Dist)\n\n        # Number of cases in S1[i] and S2[i] sets\n        S1_count = np.sum(S1Dist, axis=1)\n        S2_count = np.sum(S2Dist, axis=1)\n\n        # Number of all cases\n        S_count = np.sum(CS)\n\n        ES1w = ES1 * S1_count / S_count\n        ES2w = ES2 * S2_count / S_count\n\n        # E(A, T; S) Class information entropy of the partition S\n        E = ES1w + ES2w\n\n        return E, ES1, ES2\n\n    @classmethod\n    def _entropy_discretize_sorted(cls, C, force=False):\n        \"\"\"\n        Entropy discretization on a sorted C.\n\n        :param C: (N, K) array of class distributions.\n\n        \"\"\"\n        E, ES1, ES2 = cls._entropy_cuts_sorted(C)\n        # TODO: Also get the left right distribution counts from\n        # entropy_cuts_sorted,\n\n        # Note the + 1\n        if len(E) == 0:\n            return []\n        cut_index = np.argmin(E) + 1\n\n        # Distribution of classed in S1, S2 and S\n        S1_c = np.sum(C[:cut_index], axis=0)\n        S2_c = np.sum(C[cut_index:], axis=0)\n        S_c = S1_c + S2_c\n\n        ES = cls._entropy1(np.sum(C, axis=0))\n        ES1, ES2 = ES1[cut_index - 1], ES2[cut_index - 1]\n\n        # Information gain of the best split\n        Gain = ES - E[cut_index - 1]\n        # Number of different classes in S, S1 and S2\n        k = float(np.sum(S_c > 0))\n        k1 = float(np.sum(S1_c > 0))\n        k2 = float(np.sum(S2_c > 0))\n\n        assert k > 0\n        delta = np.log2(3 ** k - 2) - (k * ES - k1 * ES1 - k2 * ES2)\n        N = float(np.sum(S_c))\n\n        if Gain > np.log2(N - 1) / N + delta / N:\n            # Accept the cut point and recursively split the subsets.\n            left, right = [], []\n            if k1 > 1 and cut_index > 1:\n                left = cls._entropy_discretize_sorted(C[:cut_index, :])\n            if k2 > 1 and cut_index < len(C) - 1:\n                right = cls._entropy_discretize_sorted(C[cut_index:, :])\n            return left + [cut_index] + [i + cut_index for i in right]\n        elif force:\n            return [cut_index]\n        else:\n            return []\n\n\nclass DomainDiscretizer(Reprable):\n    \"\"\"Discretizes all continuous features in the data.\n\n    .. attribute:: method\n\n        Feature discretization method (instance of\n        :obj:`Orange.preprocess.Discretization`). If `None` (default),\n        :class:`Orange.preprocess.EqualFreq` with 4 intervals is\n        used.\n\n    .. attribute:: clean\n\n        If `True`, features discretized into a single interval constant are\n        removed. This is useful for discretization methods that infer the\n        number of intervals from the data, such as\n        :class:`Orange.preprocess.EntropyMDL` (default: `True`).\n\n    .. attribute:: discretize_class\n\n        Determines whether a target is also discretized if it is continuous.\n        (default: `False`)\n    \"\"\"\n    def __init__(self, discretize_class=False, method=None, clean=True,\n                 fixed=None):\n        self.discretize_class = discretize_class\n        self.method = method\n        self.clean = clean\n        self.fixed = fixed\n\n    def __call__(self, data, fixed=None):\n        \"\"\"\n        Compute and return discretized domain.\n\n        :param data: Data to discretize.\n        \"\"\"\n\n        def transform_list(s, fixed=None):\n            new_vars = []\n            for var in s:\n                if var.is_continuous:\n                    if fixed and var.name in fixed.keys():\n                        nv = method(data, var, fixed)\n                    else:\n                        nv = method(data, var)\n                    if not self.clean or len(nv.values) > 1:\n                        new_vars.append(nv)\n                else:\n                    new_vars.append(var)\n            return new_vars\n        if self.method is None:\n            method = EqualFreq(n=4)\n        else:\n            method = self.method\n        domain = data.domain\n        new_attrs = transform_list(domain.attributes, fixed or self.fixed)\n        if self.discretize_class:\n            new_classes = transform_list(domain.class_vars)\n        else:\n            new_classes = domain.class_vars\n        return Domain(new_attrs, new_classes)\n",
            "header": {
                "file": {
                    "path": "Orange/preprocess/discretize.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "7b0e9e224",
                "new_commit_hash": "8b02bab1d",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/Orange/preprocess/discretize.py"
            },
            "plus_file": {
                "path": "b/Orange/preprocess/discretize.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 358,
                            "length": 16
                        },
                        "new_range": {
                            "start": 358,
                            "length": 15
                        },
                        "section": "def time_binnings(data, *, min_bins=2, max_bins=50, min_unique=5, add_unique=0):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "def _time_binnings(mn, mx, min_pts, max_pts):",
                                "type": "context"
                            },
                            {
                                "content": "    yfmt = \"%y \" if mn.tm_year >= 1950 else \"%Y \"",
                                "type": "deleted"
                            },
                            {
                                "content": "    bins = []",
                                "type": "context"
                            },
                            {
                                "content": "    for place, step, fmt, unit in (",
                                "type": "context"
                            },
                            {
                                "content": "            [(5, x, \"%H:%M:%S\", \"second\") for x in (1, 5, 10, 15, 30)] +",
                                "type": "context"
                            },
                            {
                                "content": "            [(4, x, \"%b %d %H:%M\", \"minute\") for x in (1, 5, 10, 15, 30)] +",
                                "type": "context"
                            },
                            {
                                "content": "            [(3, x, yfmt + \"%b %d %H:%M\", \"hour\") for x in (1, 2, 3, 6, 12)] +",
                                "type": "deleted"
                            },
                            {
                                "content": "            [(2, 1, yfmt + \"%b %d\", \"day\")] +",
                                "type": "deleted"
                            },
                            {
                                "content": "            [(2, x, yfmt + \"%b %d\", \"week\") for x in (7, 14)] +",
                                "type": "deleted"
                            },
                            {
                                "content": "            [(1, x, yfmt + \"%b\", \"month\") for x in (1, 2, 3, 6)] +",
                                "type": "deleted"
                            },
                            {
                                "content": "            [(0, x, yfmt.strip(), \"year\") for x in (1, 2, 5, 10, 25, 50, 100)]):",
                                "type": "deleted"
                            },
                            {
                                "content": "            [(3, x, \"%y %b %d %H:%M\", \"hour\") for x in (1, 2, 3, 6, 12)] +",
                                "type": "added"
                            },
                            {
                                "content": "            [(2, 1, \"%y %b %d\", \"day\")] +",
                                "type": "added"
                            },
                            {
                                "content": "            [(2, x, \"%y %b %d\", \"week\") for x in (7, 14)] +",
                                "type": "added"
                            },
                            {
                                "content": "            [(1, x, \"%y %b\", \"month\") for x in (1, 2, 3, 6)] +",
                                "type": "added"
                            },
                            {
                                "content": "            [(0, x, \"%Y\", \"year\") for x in (1, 2, 5, 10, 25, 50, 100)]):",
                                "type": "added"
                            },
                            {
                                "content": "        times = _time_range(mn, mx, place, step, min_pts, max_pts)",
                                "type": "context"
                            },
                            {
                                "content": "        if not times:",
                                "type": "context"
                            },
                            {
                                "content": "            continue",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/preprocess/discretize.py",
                            "type": "function",
                            "name": "_time_binnings",
                            "content": "def _time_binnings(mn, mx, min_pts, max_pts):\n    yfmt = \"%y \" if mn.tm_year >= 1950 else \"%Y \"\n    bins = []\n    for place, step, fmt, unit in (\n            [(5, x, \"%H:%M:%S\", \"second\") for x in (1, 5, 10, 15, 30)] +\n            [(4, x, \"%b %d %H:%M\", \"minute\") for x in (1, 5, 10, 15, 30)] +\n            [(3, x, yfmt + \"%b %d %H:%M\", \"hour\") for x in (1, 2, 3, 6, 12)] +\n            [(2, 1, yfmt + \"%b %d\", \"day\")] +\n            [(2, x, yfmt + \"%b %d\", \"week\") for x in (7, 14)] +\n            [(1, x, yfmt + \"%b\", \"month\") for x in (1, 2, 3, 6)] +\n            [(0, x, yfmt.strip(), \"year\") for x in (1, 2, 5, 10, 25, 50, 100)]):\n        times = _time_range(mn, mx, place, step, min_pts, max_pts)\n        if not times:\n            continue\n        times = [time.struct_time(t + (0, 0, 0)) for t in times]\n        thresholds = [calendar.timegm(t) for t in times]\n        labels = [time.strftime(fmt, t) for t in times]\n        short_labels = _simplified_labels(labels)\n        if place == 2 and step >= 7:\n            unit_label = f\"{step // 7} week{'s' * (step > 7)}\"\n        else:\n            unit_label = f\"{step} {unit}{'s' * (step > 1)}\"\n        new_bins = BinDefinition(\n            thresholds, labels, short_labels, None, unit_label)\n        if not bins or new_bins.nbins != bins[-1].nbins:\n            bins.append(new_bins)\n    return bins",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 360,
                            "end_lineno": 386,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 437,
                            "length": 10
                        },
                        "new_range": {
                            "start": 436,
                            "length": 10
                        },
                        "section": "def _simplified_labels(labels):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        if len(firsts) > 1:",
                                "type": "context"
                            },
                            {
                                "content": "            break",
                                "type": "context"
                            },
                            {
                                "content": "        to_remove = firsts.pop()",
                                "type": "context"
                            },
                            {
                                "content": "        flen = len(to_remove) + 1",
                                "type": "deleted"
                            },
                            {
                                "content": "        flen = len(to_remove)",
                                "type": "added"
                            },
                            {
                                "content": "        if any(len(lab) == flen for lab in labels):",
                                "type": "context"
                            },
                            {
                                "content": "            break",
                                "type": "context"
                            },
                            {
                                "content": "        labels = [lab[flen:] for lab in labels]",
                                "type": "deleted"
                            },
                            {
                                "content": "        labels = [lab[flen+1:] for lab in labels]",
                                "type": "added"
                            },
                            {
                                "content": "    for i in range(len(labels) - 1, 0, -1):",
                                "type": "context"
                            },
                            {
                                "content": "        for k, c, d in zip(count(), labels[i].split(), labels[i - 1].split()):",
                                "type": "context"
                            },
                            {
                                "content": "            if c != d:",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/preprocess/discretize.py",
                            "type": "function",
                            "name": "_simplified_labels",
                            "content": "def _simplified_labels(labels):\n    labels = labels[:]\n    to_remove = \"42\"\n    while True:\n        firsts = {f for f, *_ in (lab.split() for lab in labels)}\n        if len(firsts) > 1:\n            break\n        to_remove = firsts.pop()\n        flen = len(to_remove) + 1\n        if any(len(lab) == flen for lab in labels):\n            break\n        labels = [lab[flen:] for lab in labels]\n    for i in range(len(labels) - 1, 0, -1):\n        for k, c, d in zip(count(), labels[i].split(), labels[i - 1].split()):\n            if c != d:\n                labels[i] = \" \".join(labels[i].split()[k:])\n                break\n    # If the last thing removed were month names and the labels continues with\n    # hours, keep month name in the first label; \"08 12:29\" looks awkward.\n    if not to_remove[0].isdigit() and \":\" in labels[0]:\n        labels[0] = f\"{to_remove} {labels[0]}\"\n    return labels",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 432,
                            "end_lineno": 453,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 455,
                            "length": 7
                        },
                        "new_range": {
                            "start": 454,
                            "length": 7
                        },
                        "section": "def _simplified_labels(labels):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "def _unique_time_bins(unique):",
                                "type": "context"
                            },
                            {
                                "content": "    times = [time.gmtime(x) for x in unique]",
                                "type": "context"
                            },
                            {
                                "content": "    fmt = f'{\"%y \" if times[0][0] >= 1950 else \"%Y \"} %b %d'",
                                "type": "deleted"
                            },
                            {
                                "content": "    fmt = f'%y %b %d'",
                                "type": "added"
                            },
                            {
                                "content": "    fmt += \" %H:%M\" * (len({t[2:] for t in times}) > 1)",
                                "type": "context"
                            },
                            {
                                "content": "    fmt += \":%S\" * bool(np.all(unique % 60 == 0))",
                                "type": "context"
                            },
                            {
                                "content": "    labels = [time.strftime(fmt, x) for x in times]",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/preprocess/discretize.py",
                            "type": "function",
                            "name": "_unique_time_bins",
                            "content": "def _unique_time_bins(unique):\n    times = [time.gmtime(x) for x in unique]\n    fmt = f'{\"%y \" if times[0][0] >= 1950 else \"%Y \"} %b %d'\n    fmt += \" %H:%M\" * (len({t[2:] for t in times}) > 1)\n    fmt += \":%S\" * bool(np.all(unique % 60 == 0))\n    labels = [time.strftime(fmt, x) for x in times]\n    short_labels = _simplified_labels(labels)\n    return BinDefinition(_unique_thresholds(unique), labels, short_labels)",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 456,
                            "end_lineno": 463,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "# File contains some long lines; breaking them would decrease readability\n# pylint: disable=line-too-long\nimport unittest\nfrom time import struct_time, mktime\n\nimport numpy as np\nfrom Orange.preprocess.discretize import \\\n    _time_binnings, time_binnings, BinDefinition\n\n\n# pylint: disable=redefined-builtin\ndef create(year=1970, month=1, day=1, hour=0, min=0, sec=0):\n    return struct_time((year, month, day, hour, min, sec, 0, 0, 0))\n\n\nclass TestTimeBinning(unittest.TestCase):\n    def setUp(self):\n        self.dates = [mktime(x) for x in\n            [(1975, 6, 9, 10, 0, 0, 0, 161, 0),\n             (1975, 6, 9, 10, 50, 0, 0, 161, 0),\n             (1975, 6, 9, 11, 40, 0, 0, 161, 0),\n             (1975, 6, 9, 12, 30, 0, 0, 161, 0),\n             (1975, 6, 9, 13, 20, 0, 0, 161, 0),\n             (1975, 6, 9, 14, 10, 0, 0, 161, 0)]]\n\n    def test_binning(self):\n        def testbin(start, end):\n            bins = _time_binnings(create(*start), create(*end), 3, 51)\n            return [(bin.width_label, bin.short_labels, bin.thresholds)\n                    for bin in reversed(bins)]\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1989, 3, 1)),\n            [('10 years',\n              ['70', '80', '90'],\n              [0, 315532800, 631152000]),\n             ('5 years',\n              ['75', '80', '85', '90'],\n              [157766400, 315532800, 473385600, 631152000]),\n             ('2 years',\n              ['74', '76', '78', '80', '82', '84', '86', '88', '90'],\n              [126230400, 189302400, 252460800, 315532800, 378691200, 441763200,\n               504921600, 567993600, 631152000]),\n             ('1 year',\n              ['75', '76', '77', '78', '79', '80', '81', '82', '83', '84', '85',\n               '86', '87', '88', '89', '90'],\n              [157766400, 189302400, 220924800, 252460800, 283996800, 315532800,\n               347155200, 378691200, 410227200, 441763200, 473385600, 504921600,\n               536457600, 567993600, 599616000, 631152000]),\n             ('6 months',\n              ['75 Jan', 'Jul', '76 Jan', 'Jul', '77 Jan', 'Jul', '78 Jan',\n               'Jul', '79 Jan', 'Jul', '80 Jan', 'Jul', '81 Jan', 'Jul',\n               '82 Jan', 'Jul', '83 Jan', 'Jul', '84 Jan', 'Jul', '85 Jan',\n               'Jul', '86 Jan', 'Jul', '87 Jan', 'Jul', '88 Jan', 'Jul',\n               '89 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200, 283996800, 299635200, 315532800, 331257600,\n               347155200, 362793600, 378691200, 394329600, 410227200, 425865600,\n               441763200, 457488000, 473385600, 489024000, 504921600, 520560000,\n               536457600, 552096000, 567993600, 583718400, 599616000,\n               615254400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1978, 3, 1)),\n            [('2 years',\n              ['74', '76', '78', '80'],\n              [126230400, 189302400, 252460800, 315532800]),\n             ('1 year',\n              ['75', '76', '77', '78', '79'],\n              [157766400, 189302400, 220924800, 252460800, 283996800]),\n             ('6 months',\n              ['75 Jan', 'Jul',\n               '76 Jan', 'Jul',\n               '77 Jan', 'Jul',\n               '78 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200]),\n             ('3 months',\n              ['75 Apr', 'Jul', 'Oct',\n               '76 Jan', 'Apr', 'Jul', 'Oct',\n               '77 Jan', 'Apr', 'Jul', 'Oct',\n               '78 Jan', 'Apr'],\n              [165542400, 173404800, 181353600, 189302400, 197164800, 205027200,\n               212976000, 220924800, 228700800, 236563200, 244512000, 252460800,\n               260236800]),\n             ('2 months',\n              ['75 Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '76 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '77 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '78 Jan', 'Mar', 'May'],\n              [162864000, 168134400, 173404800, 178761600, 184032000, 189302400,\n               194486400, 199756800, 205027200, 210384000, 215654400, 220924800,\n               226022400, 231292800, 236563200, 241920000, 247190400, 252460800,\n               257558400, 262828800]),\n             ('1 month',\n              ['75 Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '76 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '77 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '78 Jan', 'Feb', 'Mar', 'Apr'],\n              [165542400, 168134400, 170812800, 173404800, 176083200, 178761600,\n               181353600, 184032000, 186624000, 189302400, 191980800, 194486400,\n               197164800, 199756800, 202435200, 205027200, 207705600, 210384000,\n               212976000, 215654400, 218246400, 220924800, 223603200, 226022400,\n               228700800, 231292800, 233971200, 236563200, 239241600, 241920000,\n               244512000, 247190400, 249782400, 252460800, 255139200, 257558400,\n               260236800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 2), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('2 weeks',\n              ['75 Dec 03', '17', '31', '76 Jan 14'],\n              [186796800, 188006400, 189216000, 190425600]),\n             ('1 week',\n              ['75 Dec 03', '10', '17', '24', '31',\n               '76 Jan 07'],\n              [186796800, 187401600, 188006400, 188611200, 189216000,\n               189820800]),\n             ('1 day',\n              ['75 Dec 02', '03', '04', '05', '06', '07', '08', '09', '10',\n               '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21',\n               '22', '23', '24', '25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [186710400, 186796800, 186883200, 186969600, 187056000, 187142400,\n               187228800, 187315200, 187401600, 187488000, 187574400, 187660800,\n               187747200, 187833600, 187920000, 188006400, 188092800, 188179200,\n               188265600, 188352000, 188438400, 188524800, 188611200, 188697600,\n               188784000, 188870400, 188956800, 189043200, 189129600, 189216000,\n               189302400, 189388800, 189475200, 189561600])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 25), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [188697600, 188784000, 188870400, 188956800, 189043200, 189129600,\n               189216000, 189302400, 189388800, 189475200, 189561600]),\n             ('12 hours',\n              ['75 Dec 25 00:00', '12:00',\n               '26 00:00', '12:00',\n               '27 00:00', '12:00',\n               '28 00:00', '12:00',\n               '29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [188697600, 188740800, 188784000, 188827200, 188870400, 188913600,\n               188956800, 189000000, 189043200, 189086400, 189129600, 189172800,\n               189216000, 189259200, 189302400, 189345600, 189388800, 189432000,\n               189475200, 189518400]),\n             ('6 hours',\n              ['75 Dec 25 00:00', '06:00', '12:00', '18:00',\n               '26 00:00', '06:00', '12:00', '18:00',\n               '27 00:00', '06:00', '12:00', '18:00',\n               '28 00:00', '06:00', '12:00', '18:00',\n               '29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [188697600, 188719200, 188740800, 188762400, 188784000, 188805600,\n               188827200, 188848800, 188870400, 188892000, 188913600, 188935200,\n               188956800, 188978400, 189000000, 189021600, 189043200, 189064800,\n               189086400, 189108000, 189129600, 189151200, 189172800, 189194400,\n               189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200, 189388800, 189410400, 189432000, 189453600,\n               189475200, 189496800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 29), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [189043200, 189129600, 189216000, 189302400, 189388800, 189475200,\n               189561600]),\n             ('12 hours',\n              ['75 Dec 29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [189043200, 189086400, 189129600, 189172800, 189216000, 189259200,\n               189302400, 189345600, 189388800, 189432000, 189475200,\n               189518400]),\n             ('6 hours',\n              ['75 Dec 29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [189043200, 189064800, 189086400, 189108000, 189129600, 189151200,\n               189172800, 189194400, 189216000, 189237600, 189259200, 189280800,\n               189302400, 189324000, 189345600, 189367200, 189388800, 189410400,\n               189432000, 189453600, 189475200, 189496800]),\n             ('3 hours',\n              ['75 Dec 29 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '30 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '02 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '03 00:00', '03:00'],\n              [189043200, 189054000, 189064800, 189075600, 189086400, 189097200,\n               189108000, 189118800, 189129600, 189140400, 189151200, 189162000,\n               189172800, 189183600, 189194400, 189205200, 189216000, 189226800,\n               189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200, 189324000, 189334800, 189345600, 189356400,\n               189367200, 189378000, 189388800, 189399600, 189410400, 189421200,\n               189432000, 189442800, 189453600, 189464400, 189475200,\n               189486000])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 0, 0, 0), (1976, 1, 1, 14, 30)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00'],\n              [189216000, 189259200, 189302400, 189345600, 189388800]),\n             ('6 hours',\n              ['75 Dec 31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00'],\n              [189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200]),\n             ('3 hours',\n              ['75 Dec 31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00'],\n              [189216000, 189226800, 189237600, 189248400, 189259200, 189270000,\n               189280800, 189291600, 189302400, 189313200, 189324000, 189334800,\n               189345600, 189356400]),\n             ('2 hours',\n              ['75 Dec 31 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00'],\n              [189216000, 189223200, 189230400, 189237600, 189244800, 189252000,\n               189259200, 189266400, 189273600, 189280800, 189288000, 189295200,\n               189302400, 189309600, 189316800, 189324000, 189331200, 189338400,\n               189345600, 189352800, 189360000]),\n             ('1 hour',\n              ['75 Dec 31 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00',\n               '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00'],\n              [189216000, 189219600, 189223200, 189226800, 189230400, 189234000,\n               189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000, 189309600, 189313200, 189316800, 189320400,\n               189324000, 189327600, 189331200, 189334800, 189338400, 189342000,\n               189345600, 189349200, 189352800, 189356400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 6), (1976, 1, 1)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00'],\n              [189216000, 189259200, 189302400, 189345600]),\n             ('6 hours',\n              ['75 Dec 31 06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00'],\n              [189237600, 189259200, 189280800, 189302400, 189324000]),\n             ('3 hours',\n              ['75 Dec 31 06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00'],\n              [189237600, 189244800, 189252000, 189259200, 189266400, 189273600,\n               189280800, 189288000, 189295200, 189302400, 189309600]),\n             ('1 hour',\n              ['75 Dec 31 06:00', '07:00', '08:00', '09:00', '10:00', '11:00',\n               '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00',\n               '19:00', '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00'],\n              [189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000]),\n             ('30 minutes',\n              ['Dec 31 06:00', '06:30', '07:00', '07:30', '08:00', '08:30',\n               '09:00', '09:30', '10:00', '10:30', '11:00', '11:30', '12:00',\n               '12:30', '13:00', '13:30', '14:00', '14:30', '15:00', '15:30',\n               '16:00', '16:30', '17:00', '17:30', '18:00', '18:30', '19:00',\n               '19:30', '20:00', '20:30', '21:00', '21:30', '22:00', '22:30',\n               '23:00', '23:30',\n               'Jan 01 00:00', '00:30'],\n              [189237600, 189239400, 189241200, 189243000, 189244800, 189246600,\n               189248400, 189250200, 189252000, 189253800, 189255600, 189257400,\n               189259200, 189261000, 189262800, 189264600, 189266400, 189268200,\n               189270000, 189271800, 189273600, 189275400, 189277200, 189279000,\n               189280800, 189282600, 189284400, 189286200, 189288000, 189289800,\n               189291600, 189293400, 189295200, 189297000, 189298800, 189300600,\n               189302400, 189304200])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 23), (1976, 1, 1, 2)),\n            [('3 hours',\n              ['75 Dec 31 21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189291600, 189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 22:00',\n               '76 Jan 01 00:00', '02:00', '04:00'],\n              [189295200, 189302400, 189309600, 189316800]),\n             ('1 hour',\n              ['75 Dec 31 23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00'],\n              [189298800, 189302400, 189306000, 189309600, 189313200]),\n             ('30 minutes',\n              ['Dec 31 23:00', '23:30',\n               'Jan 01 00:00', '00:30', '01:00', '01:30', '02:00', '02:30'],\n              [189298800, 189300600, 189302400, 189304200, 189306000, 189307800,\n               189309600, 189311400]),\n             ('15 minutes',\n              ['Dec 31 23:00', '23:15', '23:30', '23:45',\n               'Jan 01 00:00', '00:15', '00:30', '00:45', '01:00', '01:15',\n               '01:30', '01:45', '02:00', '02:15'],\n              [189298800, 189299700, 189300600, 189301500, 189302400, 189303300,\n               189304200, 189305100, 189306000, 189306900, 189307800, 189308700,\n               189309600, 189310500]),\n             ('10 minutes',\n              ['Dec 31 23:00', '23:10', '23:20', '23:30', '23:40', '23:50',\n               'Jan 01 00:00', '00:10', '00:20', '00:30', '00:40', '00:50',\n               '01:00', '01:10', '01:20', '01:30', '01:40', '01:50', '02:00',\n               '02:10'],\n              [189298800, 189299400, 189300000, 189300600, 189301200, 189301800,\n               189302400, 189303000, 189303600, 189304200, 189304800, 189305400,\n               189306000, 189306600, 189307200, 189307800, 189308400, 189309000,\n               189309600, 189310200]),\n             ('5 minutes',\n              ['Dec 31 23:00', '23:05', '23:10', '23:15', '23:20', '23:25',\n               '23:30', '23:35', '23:40', '23:45', '23:50', '23:55',\n               'Jan 01 00:00', '00:05', '00:10', '00:15', '00:20', '00:25',\n               '00:30', '00:35', '00:40', '00:45', '00:50', '00:55', '01:00',\n               '01:05', '01:10', '01:15', '01:20', '01:25', '01:30', '01:35',\n               '01:40', '01:45', '01:50', '01:55', '02:00', '02:05'],\n              [189298800, 189299100, 189299400, 189299700, 189300000, 189300300,\n               189300600, 189300900, 189301200, 189301500, 189301800, 189302100,\n               189302400, 189302700, 189303000, 189303300, 189303600, 189303900,\n               189304200, 189304500, 189304800, 189305100, 189305400, 189305700,\n               189306000, 189306300, 189306600, 189306900, 189307200, 189307500,\n               189307800, 189308100, 189308400, 189308700, 189309000, 189309300,\n               189309600, 189309900])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 23, 18)),\n            [('12 hours',\n              ['Jun 09 00:00', '12:00', '10 00:00'],\n              [-1437868800, -1437825600, -1437782400]),\n             ('6 hours',\n              ['Jun 09 06:00', '12:00', '18:00', '10 00:00'],\n              [-1437847200, -1437825600, -1437804000, -1437782400]),\n             ('3 hours',\n              ['Jun 09 09:00', '12:00', '15:00', '18:00', '21:00', '10 00:00'],\n              [-1437836400, -1437825600, -1437814800, -1437804000, -1437793200,\n               -1437782400]),\n             ('2 hours',\n              ['Jun 09 10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00', '10 00:00'],\n              [-1437832800, -1437825600, -1437818400, -1437811200, -1437804000,\n               -1437796800, -1437789600, -1437782400]),\n             ('1 hour',\n              ['Jun 09 10:00', '11:00', '12:00', '13:00', '14:00', '15:00',\n               '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00',\n               '23:00',\n               '10 00:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000, -1437818400,\n               -1437814800, -1437811200, -1437807600, -1437804000, -1437800400,\n               -1437796800, -1437793200, -1437789600, -1437786000,\n               -1437782400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30', '14:00', '14:30', '15:00', '15:30', '16:00', '16:30',\n               '17:00', '17:30', '18:00', '18:30', '19:00', '19:30', '20:00',\n               '20:30', '21:00', '21:30', '22:00', '22:30', '23:00', '23:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200, -1437818400, -1437816600,\n               -1437814800, -1437813000, -1437811200, -1437809400, -1437807600,\n               -1437805800, -1437804000, -1437802200, -1437800400, -1437798600,\n               -1437796800, -1437795000, -1437793200, -1437791400, -1437789600,\n               -1437787800, -1437786000, -1437784200])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 13, 18)),\n            [('2 hours',\n              ['10:00', '12:00', '14:00'],\n              [-1437832800, -1437825600, -1437818400]),\n             ('1 hour',\n              ['10:00', '11:00', '12:00', '13:00', '14:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000,\n               -1437818400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00', '11:15', '11:30',\n               '11:45', '12:00', '12:15', '12:30', '12:45', '13:00', '13:15',\n               '13:30'],\n              [-1437832800, -1437831900, -1437831000, -1437830100, -1437829200,\n               -1437828300, -1437827400, -1437826500, -1437825600, -1437824700,\n               -1437823800, -1437822900, -1437822000, -1437821100,\n               -1437820200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50', '11:00',\n               '11:10', '11:20', '11:30', '11:40', '11:50', '12:00', '12:10',\n               '12:20', '12:30', '12:40', '12:50', '13:00', '13:10', '13:20'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800, -1437829200, -1437828600, -1437828000, -1437827400,\n               -1437826800, -1437826200, -1437825600, -1437825000, -1437824400,\n               -1437823800, -1437823200, -1437822600, -1437822000, -1437821400,\n               -1437820800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50', '10:55', '11:00', '11:05',\n               '11:10', '11:15', '11:20', '11:25', '11:30', '11:35', '11:40',\n               '11:45', '11:50', '11:55', '12:00', '12:05', '12:10', '12:15',\n               '12:20', '12:25', '12:30', '12:35', '12:40', '12:45', '12:50',\n               '12:55', '13:00', '13:05', '13:10', '13:15', '13:20'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800, -1437829500, -1437829200, -1437828900, -1437828600,\n               -1437828300, -1437828000, -1437827700, -1437827400, -1437827100,\n               -1437826800, -1437826500, -1437826200, -1437825900, -1437825600,\n               -1437825300, -1437825000, -1437824700, -1437824400, -1437824100,\n               -1437823800, -1437823500, -1437823200, -1437822900, -1437822600,\n               -1437822300, -1437822000, -1437821700, -1437821400, -1437821100,\n               -1437820800])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 48)),\n            [('30 minutes',\n              ['10:00', '10:30', '11:00'],\n              [-1437832800, -1437831000, -1437829200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00'],\n              [-1437832800, -1437831900, -1437831000, -1437830100,\n               -1437829200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21', '10:22', '10:23', '10:24', '10:25', '10:26', '10:27',\n               '10:28', '10:29', '10:30', '10:31', '10:32', '10:33', '10:34',\n               '10:35', '10:36', '10:37', '10:38', '10:39', '10:40', '10:41',\n               '10:42', '10:43', '10:44', '10:45', '10:46', '10:47', '10:48',\n               '10:49'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540, -1437831480, -1437831420, -1437831360,\n               -1437831300, -1437831240, -1437831180, -1437831120, -1437831060,\n               -1437831000, -1437830940, -1437830880, -1437830820, -1437830760,\n               -1437830700, -1437830640, -1437830580, -1437830520, -1437830460,\n               -1437830400, -1437830340, -1437830280, -1437830220, -1437830160,\n               -1437830100, -1437830040, -1437829980, -1437829920, -1437829860]\n              )]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 20)),\n            [('15 minutes',\n              ['10:00', '10:15', '10:30'],\n              [-1437832800, -1437831900, -1437831000]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30'],\n              [-1437832800, -1437832200, -1437831600, -1437831000]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540]),\n             ('30 seconds',\n              ['10:00:00', '10:00:30', '10:01:00', '10:01:30', '10:02:00',\n               '10:02:30', '10:03:00', '10:03:30', '10:04:00', '10:04:30',\n               '10:05:00', '10:05:30', '10:06:00', '10:06:30', '10:07:00',\n               '10:07:30', '10:08:00', '10:08:30', '10:09:00', '10:09:30',\n               '10:10:00', '10:10:30', '10:11:00', '10:11:30', '10:12:00',\n               '10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30', '10:19:00', '10:19:30',\n               '10:20:00', '10:20:30'],\n              [-1437832800, -1437832770, -1437832740, -1437832710, -1437832680,\n               -1437832650, -1437832620, -1437832590, -1437832560, -1437832530,\n               -1437832500, -1437832470, -1437832440, -1437832410, -1437832380,\n               -1437832350, -1437832320, -1437832290, -1437832260, -1437832230,\n               -1437832200, -1437832170, -1437832140, -1437832110, -1437832080,\n               -1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690, -1437831660, -1437831630,\n               -1437831600, -1437831570])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 18, 12)),\n            [('5 minutes',\n              ['10:10', '10:15', '10:20'],\n              [-1437832200, -1437831900, -1437831600]),\n             ('1 minute',\n              ['10:12', '10:13', '10:14', '10:15', '10:16', '10:17', '10:18',\n               '10:19'],\n              [-1437832080, -1437832020, -1437831960, -1437831900, -1437831840,\n               -1437831780, -1437831720, -1437831660]),\n             ('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30'],\n              [-1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15', '10:13:30',\n               '10:13:45', '10:14:00', '10:14:15', '10:14:30', '10:14:45',\n               '10:15:00', '10:15:15', '10:15:30', '10:15:45', '10:16:00',\n               '10:16:15', '10:16:30', '10:16:45', '10:17:00', '10:17:15',\n               '10:17:30', '10:17:45', '10:18:00', '10:18:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005, -1437831990,\n               -1437831975, -1437831960, -1437831945, -1437831930, -1437831915,\n               -1437831900, -1437831885, -1437831870, -1437831855, -1437831840,\n               -1437831825, -1437831810, -1437831795, -1437831780, -1437831765,\n               -1437831750, -1437831735, -1437831720, -1437831705]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20', '10:13:30', '10:13:40', '10:13:50', '10:14:00',\n               '10:14:10', '10:14:20', '10:14:30', '10:14:40', '10:14:50',\n               '10:15:00', '10:15:10', '10:15:20', '10:15:30', '10:15:40',\n               '10:15:50', '10:16:00', '10:16:10', '10:16:20', '10:16:30',\n               '10:16:40', '10:16:50', '10:17:00', '10:17:10', '10:17:20',\n               '10:17:30', '10:17:40', '10:17:50', '10:18:00', '10:18:10',\n               '10:18:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000, -1437831990, -1437831980, -1437831970, -1437831960,\n               -1437831950, -1437831940, -1437831930, -1437831920, -1437831910,\n               -1437831900, -1437831890, -1437831880, -1437831870, -1437831860,\n               -1437831850, -1437831840, -1437831830, -1437831820, -1437831810,\n               -1437831800, -1437831790, -1437831780, -1437831770, -1437831760,\n               -1437831750, -1437831740, -1437831730, -1437831720, -1437831710,\n               -1437831700])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 13, 12)),\n            [('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30'],\n              [-1437832050, -1437832020, -1437831990]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000]),\n             ('5 seconds',\n              ['10:12:30', '10:12:35', '10:12:40', '10:12:45', '10:12:50',\n               '10:12:55', '10:13:00', '10:13:05', '10:13:10', '10:13:15'],\n              [-1437832050, -1437832045, -1437832040, -1437832035, -1437832030,\n               -1437832025, -1437832020, -1437832015, -1437832010,\n               -1437832005]),\n             ('1 second',\n              ['10:12:33', '10:12:34', '10:12:35', '10:12:36', '10:12:37',\n               '10:12:38', '10:12:39', '10:12:40', '10:12:41', '10:12:42',\n               '10:12:43', '10:12:44', '10:12:45', '10:12:46', '10:12:47',\n               '10:12:48', '10:12:49', '10:12:50', '10:12:51', '10:12:52',\n               '10:12:53', '10:12:54', '10:12:55', '10:12:56', '10:12:57',\n               '10:12:58', '10:12:59', '10:13:00', '10:13:01', '10:13:02',\n               '10:13:03', '10:13:04', '10:13:05', '10:13:06', '10:13:07',\n               '10:13:08', '10:13:09', '10:13:10', '10:13:11', '10:13:12',\n               '10:13:13'],\n              [-1437832047, -1437832046, -1437832045, -1437832044, -1437832043,\n               -1437832042, -1437832041, -1437832040, -1437832039, -1437832038,\n               -1437832037, -1437832036, -1437832035, -1437832034, -1437832033,\n               -1437832032, -1437832031, -1437832030, -1437832029, -1437832028,\n               -1437832027, -1437832026, -1437832025, -1437832024, -1437832023,\n               -1437832022, -1437832021, -1437832020, -1437832019, -1437832018,\n               -1437832017, -1437832016, -1437832015, -1437832014, -1437832013,\n               -1437832012, -1437832011, -1437832010, -1437832009, -1437832008,\n               -1437832007])])\n\n    def test_min_unique(self):\n        bins = time_binnings(self.dates, min_unique=7)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_add_unique(self):\n        bins = time_binnings(self.dates, add_unique=7)\n        self.assertNotEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_limits(self):\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=17)},\n            {9, 17})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=16)},\n            {9})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=10, max_bins=17)},\n            {17})\n\n    def test_single_value(self):\n        dates = np.array([42])\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_no_values(self):\n        dates = np.array([])\n        self.assertRaises(ValueError, time_binnings, dates)\n\n        dates = np.array([np.nan, np.nan])\n        self.assertRaises(ValueError, time_binnings, dates)\n\n\nclass TestBinDefinition(unittest.TestCase):\n    def test_labels(self):\n        thresholds = np.array([1, 2, 3.14])\n        self.assertEqual(BinDefinition(thresholds).labels,\n                         [\"1\", \"2\", \"3.14\"])\n        self.assertEqual(BinDefinition(thresholds, \"%.3f\").labels,\n                         [\"1.000\", \"2.000\", \"3.140\"])\n        self.assertEqual(BinDefinition(thresholds, lambda x: f\"b{x:g}\").labels,\n                         [\"b1\", \"b2\", \"b3.14\"])\n        self.assertEqual(BinDefinition(thresholds, list(\"abc\")).labels,\n                         list(\"abc\"))\n\n    def test_width_label(self):\n        thresholds = np.array([1, 2, 3.14])\n        self.assertEqual(BinDefinition(thresholds).width_label, \"\")\n        self.assertEqual(BinDefinition(thresholds, width=3).width_label, \"3\")\n        self.assertEqual(BinDefinition(thresholds, width=3.14).width_label, \"3.14\")\n\n    def test_thresholds(self):\n        thresholds = np.array([1, 2, 3.14])\n        bindef = BinDefinition(thresholds)\n        np.testing.assert_equal(bindef.thresholds, thresholds)\n        self.assertEqual(bindef.start, 1)\n        self.assertEqual(bindef.nbins, 2)\n\n\nif __name__ == '__main__':\n    unittest.main()\n",
            "new_file_content": "# File contains some long lines; breaking them would decrease readability\n# pylint: disable=line-too-long\nimport unittest\nfrom time import struct_time, mktime\n\nimport numpy as np\nfrom Orange.preprocess.discretize import \\\n    _time_binnings, time_binnings, BinDefinition\n\n\n# pylint: disable=redefined-builtin\ndef create(year=1970, month=1, day=1, hour=0, min=0, sec=0):\n    return struct_time((year, month, day, hour, min, sec, 0, 0, 0))\n\n\nclass TestTimeBinning(unittest.TestCase):\n    def setUp(self):\n        self.dates = [mktime(x) for x in\n            [(1975, 6, 9, 10, 0, 0, 0, 161, 0),\n             (1975, 6, 9, 10, 50, 0, 0, 161, 0),\n             (1975, 6, 9, 11, 40, 0, 0, 161, 0),\n             (1975, 6, 9, 12, 30, 0, 0, 161, 0),\n             (1975, 6, 9, 13, 20, 0, 0, 161, 0),\n             (1975, 6, 9, 14, 10, 0, 0, 161, 0)]]\n\n    def test_binning(self):\n        def testbin(start, end):\n            bins = _time_binnings(create(*start), create(*end), 3, 51)\n            return [(bin.width_label, bin.short_labels, bin.thresholds)\n                    for bin in reversed(bins)]\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1989, 3, 1)),\n            [('10 years',\n              ['1970', '1980', '1990'],\n              [0, 315532800, 631152000]),\n             ('5 years',\n              ['1975', '1980', '1985', '1990'],\n              [157766400, 315532800, 473385600, 631152000]),\n             ('2 years',\n              ['1974', '1976', '1978', '1980', '1982', '1984', '1986', '1988',\n               '1990'],\n              [126230400, 189302400, 252460800, 315532800, 378691200, 441763200,\n               504921600, 567993600, 631152000]),\n             ('1 year',\n              ['1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982',\n               '1983', '1984', '1985', '1986', '1987', '1988', '1989', '1990'],\n              [157766400, 189302400, 220924800, 252460800, 283996800, 315532800,\n               347155200, 378691200, 410227200, 441763200, 473385600, 504921600,\n               536457600, 567993600, 599616000, 631152000]),\n             ('6 months',\n              ['75 Jan', 'Jul', '76 Jan', 'Jul', '77 Jan', 'Jul', '78 Jan',\n               'Jul', '79 Jan', 'Jul', '80 Jan', 'Jul', '81 Jan', 'Jul',\n               '82 Jan', 'Jul', '83 Jan', 'Jul', '84 Jan', 'Jul', '85 Jan',\n               'Jul', '86 Jan', 'Jul', '87 Jan', 'Jul', '88 Jan', 'Jul',\n               '89 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200, 283996800, 299635200, 315532800, 331257600,\n               347155200, 362793600, 378691200, 394329600, 410227200, 425865600,\n               441763200, 457488000, 473385600, 489024000, 504921600, 520560000,\n               536457600, 552096000, 567993600, 583718400, 599616000,\n               615254400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1978, 3, 1)),\n            [('2 years',\n              ['1974', '1976', '1978', '1980'],\n              [126230400, 189302400, 252460800, 315532800]),\n             ('1 year',\n              ['1975', '1976', '1977', '1978', '1979'],\n              [157766400, 189302400, 220924800, 252460800, 283996800]),\n             ('6 months',\n              ['75 Jan', 'Jul',\n               '76 Jan', 'Jul',\n               '77 Jan', 'Jul',\n               '78 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200]),\n             ('3 months',\n              ['75 Apr', 'Jul', 'Oct',\n               '76 Jan', 'Apr', 'Jul', 'Oct',\n               '77 Jan', 'Apr', 'Jul', 'Oct',\n               '78 Jan', 'Apr'],\n              [165542400, 173404800, 181353600, 189302400, 197164800, 205027200,\n               212976000, 220924800, 228700800, 236563200, 244512000, 252460800,\n               260236800]),\n             ('2 months',\n              ['75 Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '76 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '77 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '78 Jan', 'Mar', 'May'],\n              [162864000, 168134400, 173404800, 178761600, 184032000, 189302400,\n               194486400, 199756800, 205027200, 210384000, 215654400, 220924800,\n               226022400, 231292800, 236563200, 241920000, 247190400, 252460800,\n               257558400, 262828800]),\n             ('1 month',\n              ['75 Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '76 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '77 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '78 Jan', 'Feb', 'Mar', 'Apr'],\n              [165542400, 168134400, 170812800, 173404800, 176083200, 178761600,\n               181353600, 184032000, 186624000, 189302400, 191980800, 194486400,\n               197164800, 199756800, 202435200, 205027200, 207705600, 210384000,\n               212976000, 215654400, 218246400, 220924800, 223603200, 226022400,\n               228700800, 231292800, 233971200, 236563200, 239241600, 241920000,\n               244512000, 247190400, 249782400, 252460800, 255139200, 257558400,\n               260236800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 2), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('2 weeks',\n              ['75 Dec 03', '17', '31', '76 Jan 14'],\n              [186796800, 188006400, 189216000, 190425600]),\n             ('1 week',\n              ['75 Dec 03', '10', '17', '24', '31',\n               '76 Jan 07'],\n              [186796800, 187401600, 188006400, 188611200, 189216000,\n               189820800]),\n             ('1 day',\n              ['75 Dec 02', '03', '04', '05', '06', '07', '08', '09', '10',\n               '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21',\n               '22', '23', '24', '25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [186710400, 186796800, 186883200, 186969600, 187056000, 187142400,\n               187228800, 187315200, 187401600, 187488000, 187574400, 187660800,\n               187747200, 187833600, 187920000, 188006400, 188092800, 188179200,\n               188265600, 188352000, 188438400, 188524800, 188611200, 188697600,\n               188784000, 188870400, 188956800, 189043200, 189129600, 189216000,\n               189302400, 189388800, 189475200, 189561600])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 25), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [188697600, 188784000, 188870400, 188956800, 189043200, 189129600,\n               189216000, 189302400, 189388800, 189475200, 189561600]),\n             ('12 hours',\n              ['75 Dec 25 00:00', '12:00',\n               '26 00:00', '12:00',\n               '27 00:00', '12:00',\n               '28 00:00', '12:00',\n               '29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [188697600, 188740800, 188784000, 188827200, 188870400, 188913600,\n               188956800, 189000000, 189043200, 189086400, 189129600, 189172800,\n               189216000, 189259200, 189302400, 189345600, 189388800, 189432000,\n               189475200, 189518400]),\n             ('6 hours',\n              ['75 Dec 25 00:00', '06:00', '12:00', '18:00',\n               '26 00:00', '06:00', '12:00', '18:00',\n               '27 00:00', '06:00', '12:00', '18:00',\n               '28 00:00', '06:00', '12:00', '18:00',\n               '29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [188697600, 188719200, 188740800, 188762400, 188784000, 188805600,\n               188827200, 188848800, 188870400, 188892000, 188913600, 188935200,\n               188956800, 188978400, 189000000, 189021600, 189043200, 189064800,\n               189086400, 189108000, 189129600, 189151200, 189172800, 189194400,\n               189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200, 189388800, 189410400, 189432000, 189453600,\n               189475200, 189496800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 29), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [189043200, 189129600, 189216000, 189302400, 189388800, 189475200,\n               189561600]),\n             ('12 hours',\n              ['75 Dec 29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [189043200, 189086400, 189129600, 189172800, 189216000, 189259200,\n               189302400, 189345600, 189388800, 189432000, 189475200,\n               189518400]),\n             ('6 hours',\n              ['75 Dec 29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [189043200, 189064800, 189086400, 189108000, 189129600, 189151200,\n               189172800, 189194400, 189216000, 189237600, 189259200, 189280800,\n               189302400, 189324000, 189345600, 189367200, 189388800, 189410400,\n               189432000, 189453600, 189475200, 189496800]),\n             ('3 hours',\n              ['75 Dec 29 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '30 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '02 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '03 00:00', '03:00'],\n              [189043200, 189054000, 189064800, 189075600, 189086400, 189097200,\n               189108000, 189118800, 189129600, 189140400, 189151200, 189162000,\n               189172800, 189183600, 189194400, 189205200, 189216000, 189226800,\n               189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200, 189324000, 189334800, 189345600, 189356400,\n               189367200, 189378000, 189388800, 189399600, 189410400, 189421200,\n               189432000, 189442800, 189453600, 189464400, 189475200,\n               189486000])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 0, 0, 0), (1976, 1, 1, 14, 30)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00'],\n              [189216000, 189259200, 189302400, 189345600, 189388800]),\n             ('6 hours',\n              ['75 Dec 31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00'],\n              [189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200]),\n             ('3 hours',\n              ['75 Dec 31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00'],\n              [189216000, 189226800, 189237600, 189248400, 189259200, 189270000,\n               189280800, 189291600, 189302400, 189313200, 189324000, 189334800,\n               189345600, 189356400]),\n             ('2 hours',\n              ['75 Dec 31 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00'],\n              [189216000, 189223200, 189230400, 189237600, 189244800, 189252000,\n               189259200, 189266400, 189273600, 189280800, 189288000, 189295200,\n               189302400, 189309600, 189316800, 189324000, 189331200, 189338400,\n               189345600, 189352800, 189360000]),\n             ('1 hour',\n              ['75 Dec 31 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00',\n               '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00'],\n              [189216000, 189219600, 189223200, 189226800, 189230400, 189234000,\n               189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000, 189309600, 189313200, 189316800, 189320400,\n               189324000, 189327600, 189331200, 189334800, 189338400, 189342000,\n               189345600, 189349200, 189352800, 189356400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 6), (1976, 1, 1)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00'],\n              [189216000, 189259200, 189302400, 189345600]),\n             ('6 hours',\n              ['75 Dec 31 06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00'],\n              [189237600, 189259200, 189280800, 189302400, 189324000]),\n             ('3 hours',\n              ['75 Dec 31 06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00'],\n              [189237600, 189244800, 189252000, 189259200, 189266400, 189273600,\n               189280800, 189288000, 189295200, 189302400, 189309600]),\n             ('1 hour',\n              ['75 Dec 31 06:00', '07:00', '08:00', '09:00', '10:00', '11:00',\n               '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00',\n               '19:00', '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00'],\n              [189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000]),\n             ('30 minutes',\n              ['Dec 31 06:00', '06:30', '07:00', '07:30', '08:00', '08:30',\n               '09:00', '09:30', '10:00', '10:30', '11:00', '11:30', '12:00',\n               '12:30', '13:00', '13:30', '14:00', '14:30', '15:00', '15:30',\n               '16:00', '16:30', '17:00', '17:30', '18:00', '18:30', '19:00',\n               '19:30', '20:00', '20:30', '21:00', '21:30', '22:00', '22:30',\n               '23:00', '23:30',\n               'Jan 01 00:00', '00:30'],\n              [189237600, 189239400, 189241200, 189243000, 189244800, 189246600,\n               189248400, 189250200, 189252000, 189253800, 189255600, 189257400,\n               189259200, 189261000, 189262800, 189264600, 189266400, 189268200,\n               189270000, 189271800, 189273600, 189275400, 189277200, 189279000,\n               189280800, 189282600, 189284400, 189286200, 189288000, 189289800,\n               189291600, 189293400, 189295200, 189297000, 189298800, 189300600,\n               189302400, 189304200])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 23), (1976, 1, 1, 2)),\n            [('3 hours',\n              ['75 Dec 31 21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189291600, 189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 22:00',\n               '76 Jan 01 00:00', '02:00', '04:00'],\n              [189295200, 189302400, 189309600, 189316800]),\n             ('1 hour',\n              ['75 Dec 31 23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00'],\n              [189298800, 189302400, 189306000, 189309600, 189313200]),\n             ('30 minutes',\n              ['Dec 31 23:00', '23:30',\n               'Jan 01 00:00', '00:30', '01:00', '01:30', '02:00', '02:30'],\n              [189298800, 189300600, 189302400, 189304200, 189306000, 189307800,\n               189309600, 189311400]),\n             ('15 minutes',\n              ['Dec 31 23:00', '23:15', '23:30', '23:45',\n               'Jan 01 00:00', '00:15', '00:30', '00:45', '01:00', '01:15',\n               '01:30', '01:45', '02:00', '02:15'],\n              [189298800, 189299700, 189300600, 189301500, 189302400, 189303300,\n               189304200, 189305100, 189306000, 189306900, 189307800, 189308700,\n               189309600, 189310500]),\n             ('10 minutes',\n              ['Dec 31 23:00', '23:10', '23:20', '23:30', '23:40', '23:50',\n               'Jan 01 00:00', '00:10', '00:20', '00:30', '00:40', '00:50',\n               '01:00', '01:10', '01:20', '01:30', '01:40', '01:50', '02:00',\n               '02:10'],\n              [189298800, 189299400, 189300000, 189300600, 189301200, 189301800,\n               189302400, 189303000, 189303600, 189304200, 189304800, 189305400,\n               189306000, 189306600, 189307200, 189307800, 189308400, 189309000,\n               189309600, 189310200]),\n             ('5 minutes',\n              ['Dec 31 23:00', '23:05', '23:10', '23:15', '23:20', '23:25',\n               '23:30', '23:35', '23:40', '23:45', '23:50', '23:55',\n               'Jan 01 00:00', '00:05', '00:10', '00:15', '00:20', '00:25',\n               '00:30', '00:35', '00:40', '00:45', '00:50', '00:55', '01:00',\n               '01:05', '01:10', '01:15', '01:20', '01:25', '01:30', '01:35',\n               '01:40', '01:45', '01:50', '01:55', '02:00', '02:05'],\n              [189298800, 189299100, 189299400, 189299700, 189300000, 189300300,\n               189300600, 189300900, 189301200, 189301500, 189301800, 189302100,\n               189302400, 189302700, 189303000, 189303300, 189303600, 189303900,\n               189304200, 189304500, 189304800, 189305100, 189305400, 189305700,\n               189306000, 189306300, 189306600, 189306900, 189307200, 189307500,\n               189307800, 189308100, 189308400, 189308700, 189309000, 189309300,\n               189309600, 189309900])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 23, 18)),\n            [('12 hours',\n              ['Jun 09 00:00', '12:00', '10 00:00'],\n              [-1437868800, -1437825600, -1437782400]),\n             ('6 hours',\n              ['Jun 09 06:00', '12:00', '18:00', '10 00:00'],\n              [-1437847200, -1437825600, -1437804000, -1437782400]),\n             ('3 hours',\n              ['Jun 09 09:00', '12:00', '15:00', '18:00', '21:00', '10 00:00'],\n              [-1437836400, -1437825600, -1437814800, -1437804000, -1437793200,\n               -1437782400]),\n             ('2 hours',\n              ['Jun 09 10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00', '10 00:00'],\n              [-1437832800, -1437825600, -1437818400, -1437811200, -1437804000,\n               -1437796800, -1437789600, -1437782400]),\n             ('1 hour',\n              ['Jun 09 10:00', '11:00', '12:00', '13:00', '14:00', '15:00',\n               '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00',\n               '23:00',\n               '10 00:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000, -1437818400,\n               -1437814800, -1437811200, -1437807600, -1437804000, -1437800400,\n               -1437796800, -1437793200, -1437789600, -1437786000,\n               -1437782400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30', '14:00', '14:30', '15:00', '15:30', '16:00', '16:30',\n               '17:00', '17:30', '18:00', '18:30', '19:00', '19:30', '20:00',\n               '20:30', '21:00', '21:30', '22:00', '22:30', '23:00', '23:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200, -1437818400, -1437816600,\n               -1437814800, -1437813000, -1437811200, -1437809400, -1437807600,\n               -1437805800, -1437804000, -1437802200, -1437800400, -1437798600,\n               -1437796800, -1437795000, -1437793200, -1437791400, -1437789600,\n               -1437787800, -1437786000, -1437784200])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 13, 18)),\n            [('2 hours',\n              ['10:00', '12:00', '14:00'],\n              [-1437832800, -1437825600, -1437818400]),\n             ('1 hour',\n              ['10:00', '11:00', '12:00', '13:00', '14:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000,\n               -1437818400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00', '11:15', '11:30',\n               '11:45', '12:00', '12:15', '12:30', '12:45', '13:00', '13:15',\n               '13:30'],\n              [-1437832800, -1437831900, -1437831000, -1437830100, -1437829200,\n               -1437828300, -1437827400, -1437826500, -1437825600, -1437824700,\n               -1437823800, -1437822900, -1437822000, -1437821100,\n               -1437820200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50', '11:00',\n               '11:10', '11:20', '11:30', '11:40', '11:50', '12:00', '12:10',\n               '12:20', '12:30', '12:40', '12:50', '13:00', '13:10', '13:20'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800, -1437829200, -1437828600, -1437828000, -1437827400,\n               -1437826800, -1437826200, -1437825600, -1437825000, -1437824400,\n               -1437823800, -1437823200, -1437822600, -1437822000, -1437821400,\n               -1437820800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50', '10:55', '11:00', '11:05',\n               '11:10', '11:15', '11:20', '11:25', '11:30', '11:35', '11:40',\n               '11:45', '11:50', '11:55', '12:00', '12:05', '12:10', '12:15',\n               '12:20', '12:25', '12:30', '12:35', '12:40', '12:45', '12:50',\n               '12:55', '13:00', '13:05', '13:10', '13:15', '13:20'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800, -1437829500, -1437829200, -1437828900, -1437828600,\n               -1437828300, -1437828000, -1437827700, -1437827400, -1437827100,\n               -1437826800, -1437826500, -1437826200, -1437825900, -1437825600,\n               -1437825300, -1437825000, -1437824700, -1437824400, -1437824100,\n               -1437823800, -1437823500, -1437823200, -1437822900, -1437822600,\n               -1437822300, -1437822000, -1437821700, -1437821400, -1437821100,\n               -1437820800])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 48)),\n            [('30 minutes',\n              ['10:00', '10:30', '11:00'],\n              [-1437832800, -1437831000, -1437829200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00'],\n              [-1437832800, -1437831900, -1437831000, -1437830100,\n               -1437829200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21', '10:22', '10:23', '10:24', '10:25', '10:26', '10:27',\n               '10:28', '10:29', '10:30', '10:31', '10:32', '10:33', '10:34',\n               '10:35', '10:36', '10:37', '10:38', '10:39', '10:40', '10:41',\n               '10:42', '10:43', '10:44', '10:45', '10:46', '10:47', '10:48',\n               '10:49'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540, -1437831480, -1437831420, -1437831360,\n               -1437831300, -1437831240, -1437831180, -1437831120, -1437831060,\n               -1437831000, -1437830940, -1437830880, -1437830820, -1437830760,\n               -1437830700, -1437830640, -1437830580, -1437830520, -1437830460,\n               -1437830400, -1437830340, -1437830280, -1437830220, -1437830160,\n               -1437830100, -1437830040, -1437829980, -1437829920, -1437829860]\n              )]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 20)),\n            [('15 minutes',\n              ['10:00', '10:15', '10:30'],\n              [-1437832800, -1437831900, -1437831000]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30'],\n              [-1437832800, -1437832200, -1437831600, -1437831000]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540]),\n             ('30 seconds',\n              ['10:00:00', '10:00:30', '10:01:00', '10:01:30', '10:02:00',\n               '10:02:30', '10:03:00', '10:03:30', '10:04:00', '10:04:30',\n               '10:05:00', '10:05:30', '10:06:00', '10:06:30', '10:07:00',\n               '10:07:30', '10:08:00', '10:08:30', '10:09:00', '10:09:30',\n               '10:10:00', '10:10:30', '10:11:00', '10:11:30', '10:12:00',\n               '10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30', '10:19:00', '10:19:30',\n               '10:20:00', '10:20:30'],\n              [-1437832800, -1437832770, -1437832740, -1437832710, -1437832680,\n               -1437832650, -1437832620, -1437832590, -1437832560, -1437832530,\n               -1437832500, -1437832470, -1437832440, -1437832410, -1437832380,\n               -1437832350, -1437832320, -1437832290, -1437832260, -1437832230,\n               -1437832200, -1437832170, -1437832140, -1437832110, -1437832080,\n               -1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690, -1437831660, -1437831630,\n               -1437831600, -1437831570])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 18, 12)),\n            [('5 minutes',\n              ['10:10', '10:15', '10:20'],\n              [-1437832200, -1437831900, -1437831600]),\n             ('1 minute',\n              ['10:12', '10:13', '10:14', '10:15', '10:16', '10:17', '10:18',\n               '10:19'],\n              [-1437832080, -1437832020, -1437831960, -1437831900, -1437831840,\n               -1437831780, -1437831720, -1437831660]),\n             ('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30'],\n              [-1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15', '10:13:30',\n               '10:13:45', '10:14:00', '10:14:15', '10:14:30', '10:14:45',\n               '10:15:00', '10:15:15', '10:15:30', '10:15:45', '10:16:00',\n               '10:16:15', '10:16:30', '10:16:45', '10:17:00', '10:17:15',\n               '10:17:30', '10:17:45', '10:18:00', '10:18:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005, -1437831990,\n               -1437831975, -1437831960, -1437831945, -1437831930, -1437831915,\n               -1437831900, -1437831885, -1437831870, -1437831855, -1437831840,\n               -1437831825, -1437831810, -1437831795, -1437831780, -1437831765,\n               -1437831750, -1437831735, -1437831720, -1437831705]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20', '10:13:30', '10:13:40', '10:13:50', '10:14:00',\n               '10:14:10', '10:14:20', '10:14:30', '10:14:40', '10:14:50',\n               '10:15:00', '10:15:10', '10:15:20', '10:15:30', '10:15:40',\n               '10:15:50', '10:16:00', '10:16:10', '10:16:20', '10:16:30',\n               '10:16:40', '10:16:50', '10:17:00', '10:17:10', '10:17:20',\n               '10:17:30', '10:17:40', '10:17:50', '10:18:00', '10:18:10',\n               '10:18:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000, -1437831990, -1437831980, -1437831970, -1437831960,\n               -1437831950, -1437831940, -1437831930, -1437831920, -1437831910,\n               -1437831900, -1437831890, -1437831880, -1437831870, -1437831860,\n               -1437831850, -1437831840, -1437831830, -1437831820, -1437831810,\n               -1437831800, -1437831790, -1437831780, -1437831770, -1437831760,\n               -1437831750, -1437831740, -1437831730, -1437831720, -1437831710,\n               -1437831700])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 13, 12)),\n            [('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30'],\n              [-1437832050, -1437832020, -1437831990]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000]),\n             ('5 seconds',\n              ['10:12:30', '10:12:35', '10:12:40', '10:12:45', '10:12:50',\n               '10:12:55', '10:13:00', '10:13:05', '10:13:10', '10:13:15'],\n              [-1437832050, -1437832045, -1437832040, -1437832035, -1437832030,\n               -1437832025, -1437832020, -1437832015, -1437832010,\n               -1437832005]),\n             ('1 second',\n              ['10:12:33', '10:12:34', '10:12:35', '10:12:36', '10:12:37',\n               '10:12:38', '10:12:39', '10:12:40', '10:12:41', '10:12:42',\n               '10:12:43', '10:12:44', '10:12:45', '10:12:46', '10:12:47',\n               '10:12:48', '10:12:49', '10:12:50', '10:12:51', '10:12:52',\n               '10:12:53', '10:12:54', '10:12:55', '10:12:56', '10:12:57',\n               '10:12:58', '10:12:59', '10:13:00', '10:13:01', '10:13:02',\n               '10:13:03', '10:13:04', '10:13:05', '10:13:06', '10:13:07',\n               '10:13:08', '10:13:09', '10:13:10', '10:13:11', '10:13:12',\n               '10:13:13'],\n              [-1437832047, -1437832046, -1437832045, -1437832044, -1437832043,\n               -1437832042, -1437832041, -1437832040, -1437832039, -1437832038,\n               -1437832037, -1437832036, -1437832035, -1437832034, -1437832033,\n               -1437832032, -1437832031, -1437832030, -1437832029, -1437832028,\n               -1437832027, -1437832026, -1437832025, -1437832024, -1437832023,\n               -1437832022, -1437832021, -1437832020, -1437832019, -1437832018,\n               -1437832017, -1437832016, -1437832015, -1437832014, -1437832013,\n               -1437832012, -1437832011, -1437832010, -1437832009, -1437832008,\n               -1437832007])])\n\n        self.assertEqual(\n            testbin((1973, 9, 14), (2010, 9, 8)),\n            [\n                ('50 years',\n                 ['1950', '2000', '2050'],\n                 [-631152000, 946684800, 2524608000]),\n                ('25 years',\n                 ['1950', '1975', '2000', '2025'],\n                 [-631152000, 157766400, 946684800, 1735689600]),\n                ('10 years',\n                 ['1970', '1980', '1990', '2000', '2010', '2020'],\n                 [0, 315532800, 631152000, 946684800, 1262304000, 1577836800]),\n                ('5 years',\n                 ['1970', '1975', '1980', '1985', '1990', '1995', '2000',\n                  '2005', '2010', '2015'],\n                 [0, 157766400, 315532800, 473385600, 631152000, 788918400,\n                  946684800, 1104537600, 1262304000, 1420070400]),\n                ('2 years',\n                 ['1972', '1974', '1976', '1978', '1980', '1982', '1984',\n                  '1986', '1988', '1990', '1992', '1994', '1996', '1998',\n                  '2000', '2002', '2004', '2006', '2008', '2010', '2012'],\n                 [63072000, 126230400, 189302400, 252460800, 315532800,\n                  378691200, 441763200, 504921600, 567993600, 631152000,\n                  694224000, 757382400, 820454400, 883612800, 946684800,\n                  1009843200, 1072915200, 1136073600, 1199145600, 1262304000,\n                  1325376000]),\n                ('1 year',\n                 ['1973', '1974', '1975', '1976', '1977', '1978', '1979',\n                  '1980', '1981', '1982', '1983', '1984', '1985', '1986',\n                  '1987', '1988', '1989', '1990', '1991', '1992', '1993',\n                  '1994', '1995', '1996', '1997', '1998', '1999', '2000',\n                  '2001', '2002', '2003', '2004', '2005', '2006', '2007',\n                  '2008', '2009', '2010', '2011'],\n                 [94694400, 126230400, 157766400, 189302400, 220924800,\n                  252460800, 283996800, 315532800, 347155200, 378691200,\n                  410227200, 441763200, 473385600, 504921600, 536457600,\n                  567993600, 599616000, 631152000, 662688000, 694224000,\n                  725846400, 757382400, 788918400, 820454400, 852076800,\n                  883612800, 915148800, 946684800, 978307200, 1009843200,\n                  1041379200, 1072915200, 1104537600, 1136073600, 1167609600,\n                  1199145600, 1230768000, 1262304000, 1293840000])\n            ]\n        )\n\n    def test_min_unique(self):\n        bins = time_binnings(self.dates, min_unique=7)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_add_unique(self):\n        bins = time_binnings(self.dates, add_unique=7)\n        self.assertNotEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_limits(self):\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=17)},\n            {9, 17})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=16)},\n            {9})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=10, max_bins=17)},\n            {17})\n\n    def test_single_value(self):\n        dates = np.array([42])\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_multiple_identical(self):\n        dates = np.array([42] * 5)\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_no_values(self):\n        dates = np.array([])\n        self.assertRaises(ValueError, time_binnings, dates)\n\n        dates = np.array([np.nan, np.nan])\n        self.assertRaises(ValueError, time_binnings, dates)\n\n\nclass TestBinDefinition(unittest.TestCase):\n    def test_labels(self):\n        thresholds = np.array([1, 2, 3.14])\n        self.assertEqual(BinDefinition(thresholds).labels,\n                         [\"1\", \"2\", \"3.14\"])\n        self.assertEqual(BinDefinition(thresholds, \"%.3f\").labels,\n                         [\"1.000\", \"2.000\", \"3.140\"])\n        self.assertEqual(BinDefinition(thresholds, lambda x: f\"b{x:g}\").labels,\n                         [\"b1\", \"b2\", \"b3.14\"])\n        self.assertEqual(BinDefinition(thresholds, list(\"abc\")).labels,\n                         list(\"abc\"))\n\n    def test_width_label(self):\n        thresholds = np.array([1, 2, 3.14])\n        self.assertEqual(BinDefinition(thresholds).width_label, \"\")\n        self.assertEqual(BinDefinition(thresholds, width=3).width_label, \"3\")\n        self.assertEqual(BinDefinition(thresholds, width=3.14).width_label, \"3.14\")\n\n    def test_thresholds(self):\n        thresholds = np.array([1, 2, 3.14])\n        bindef = BinDefinition(thresholds)\n        np.testing.assert_equal(bindef.thresholds, thresholds)\n        self.assertEqual(bindef.start, 1)\n        self.assertEqual(bindef.nbins, 2)\n\n\nif __name__ == '__main__':\n    unittest.main()\n",
            "header": {
                "file": {
                    "path": "Orange/preprocess/tests/test_discretize.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "9c8f01136",
                "new_commit_hash": "32fbe1d95",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/Orange/preprocess/tests/test_discretize.py"
            },
            "plus_file": {
                "path": "b/Orange/preprocess/tests/test_discretize.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 32,
                            "length": 18
                        },
                        "new_range": {
                            "start": 32,
                            "length": 19
                        },
                        "section": "class TestTimeBinning(unittest.TestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        self.assertEqual(",
                                "type": "context"
                            },
                            {
                                "content": "            testbin((1975, 4, 2), (1989, 3, 1)),",
                                "type": "context"
                            },
                            {
                                "content": "            [('10 years',",
                                "type": "context"
                            },
                            {
                                "content": "              ['70', '80', '90'],",
                                "type": "deleted"
                            },
                            {
                                "content": "              ['1970', '1980', '1990'],",
                                "type": "added"
                            },
                            {
                                "content": "              [0, 315532800, 631152000]),",
                                "type": "context"
                            },
                            {
                                "content": "             ('5 years',",
                                "type": "context"
                            },
                            {
                                "content": "              ['75', '80', '85', '90'],",
                                "type": "deleted"
                            },
                            {
                                "content": "              ['1975', '1980', '1985', '1990'],",
                                "type": "added"
                            },
                            {
                                "content": "              [157766400, 315532800, 473385600, 631152000]),",
                                "type": "context"
                            },
                            {
                                "content": "             ('2 years',",
                                "type": "context"
                            },
                            {
                                "content": "              ['74', '76', '78', '80', '82', '84', '86', '88', '90'],",
                                "type": "deleted"
                            },
                            {
                                "content": "              ['1974', '1976', '1978', '1980', '1982', '1984', '1986', '1988',",
                                "type": "added"
                            },
                            {
                                "content": "               '1990'],",
                                "type": "added"
                            },
                            {
                                "content": "              [126230400, 189302400, 252460800, 315532800, 378691200, 441763200,",
                                "type": "context"
                            },
                            {
                                "content": "               504921600, 567993600, 631152000]),",
                                "type": "context"
                            },
                            {
                                "content": "             ('1 year',",
                                "type": "context"
                            },
                            {
                                "content": "              ['75', '76', '77', '78', '79', '80', '81', '82', '83', '84', '85',",
                                "type": "deleted"
                            },
                            {
                                "content": "               '86', '87', '88', '89', '90'],",
                                "type": "deleted"
                            },
                            {
                                "content": "              ['1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982',",
                                "type": "added"
                            },
                            {
                                "content": "               '1983', '1984', '1985', '1986', '1987', '1988', '1989', '1990'],",
                                "type": "added"
                            },
                            {
                                "content": "              [157766400, 189302400, 220924800, 252460800, 283996800, 315532800,",
                                "type": "context"
                            },
                            {
                                "content": "               347155200, 378691200, 410227200, 441763200, 473385600, 504921600,",
                                "type": "context"
                            },
                            {
                                "content": "               536457600, 567993600, 599616000, 631152000]),",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/preprocess/tests/test_discretize.py",
                            "type": "method",
                            "name": "TestTimeBinning.test_binning",
                            "content": "class TestTimeBinning(unittest.TestCase):\n    def setUp(self):\n        self.dates = [mktime(x) for x in\n            [(1975, 6, 9, 10, 0, 0, 0, 161, 0),\n             (1975, 6, 9, 10, 50, 0, 0, 161, 0),\n             (1975, 6, 9, 11, 40, 0, 0, 161, 0),\n             (1975, 6, 9, 12, 30, 0, 0, 161, 0),\n             (1975, 6, 9, 13, 20, 0, 0, 161, 0),\n             (1975, 6, 9, 14, 10, 0, 0, 161, 0)]]\n\n    def test_binning(self):\n        def testbin(start, end):\n            bins = _time_binnings(create(*start), create(*end), 3, 51)\n            return [(bin.width_label, bin.short_labels, bin.thresholds)\n                    for bin in reversed(bins)]\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1989, 3, 1)),\n            [('10 years',\n              ['70', '80', '90'],\n              [0, 315532800, 631152000]),\n             ('5 years',\n              ['75', '80', '85', '90'],\n              [157766400, 315532800, 473385600, 631152000]),\n             ('2 years',\n              ['74', '76', '78', '80', '82', '84', '86', '88', '90'],\n              [126230400, 189302400, 252460800, 315532800, 378691200, 441763200,\n               504921600, 567993600, 631152000]),\n             ('1 year',\n              ['75', '76', '77', '78', '79', '80', '81', '82', '83', '84', '85',\n               '86', '87', '88', '89', '90'],\n              [157766400, 189302400, 220924800, 252460800, 283996800, 315532800,\n               347155200, 378691200, 410227200, 441763200, 473385600, 504921600,\n               536457600, 567993600, 599616000, 631152000]),\n             ('6 months',\n              ['75 Jan', 'Jul', '76 Jan', 'Jul', '77 Jan', 'Jul', '78 Jan',\n               'Jul', '79 Jan', 'Jul', '80 Jan', 'Jul', '81 Jan', 'Jul',\n               '82 Jan', 'Jul', '83 Jan', 'Jul', '84 Jan', 'Jul', '85 Jan',\n               'Jul', '86 Jan', 'Jul', '87 Jan', 'Jul', '88 Jan', 'Jul',\n               '89 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200, 283996800, 299635200, 315532800, 331257600,\n               347155200, 362793600, 378691200, 394329600, 410227200, 425865600,\n               441763200, 457488000, 473385600, 489024000, 504921600, 520560000,\n               536457600, 552096000, 567993600, 583718400, 599616000,\n               615254400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1978, 3, 1)),\n            [('2 years',\n              ['74', '76', '78', '80'],\n              [126230400, 189302400, 252460800, 315532800]),\n             ('1 year',\n              ['75', '76', '77', '78', '79'],\n              [157766400, 189302400, 220924800, 252460800, 283996800]),\n             ('6 months',\n              ['75 Jan', 'Jul',\n               '76 Jan', 'Jul',\n               '77 Jan', 'Jul',\n               '78 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200]),\n             ('3 months',\n              ['75 Apr', 'Jul', 'Oct',\n               '76 Jan', 'Apr', 'Jul', 'Oct',\n               '77 Jan', 'Apr', 'Jul', 'Oct',\n               '78 Jan', 'Apr'],\n              [165542400, 173404800, 181353600, 189302400, 197164800, 205027200,\n               212976000, 220924800, 228700800, 236563200, 244512000, 252460800,\n               260236800]),\n             ('2 months',\n              ['75 Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '76 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '77 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '78 Jan', 'Mar', 'May'],\n              [162864000, 168134400, 173404800, 178761600, 184032000, 189302400,\n               194486400, 199756800, 205027200, 210384000, 215654400, 220924800,\n               226022400, 231292800, 236563200, 241920000, 247190400, 252460800,\n               257558400, 262828800]),\n             ('1 month',\n              ['75 Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '76 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '77 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '78 Jan', 'Feb', 'Mar', 'Apr'],\n              [165542400, 168134400, 170812800, 173404800, 176083200, 178761600,\n               181353600, 184032000, 186624000, 189302400, 191980800, 194486400,\n               197164800, 199756800, 202435200, 205027200, 207705600, 210384000,\n               212976000, 215654400, 218246400, 220924800, 223603200, 226022400,\n               228700800, 231292800, 233971200, 236563200, 239241600, 241920000,\n               244512000, 247190400, 249782400, 252460800, 255139200, 257558400,\n               260236800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 2), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('2 weeks',\n              ['75 Dec 03', '17', '31', '76 Jan 14'],\n              [186796800, 188006400, 189216000, 190425600]),\n             ('1 week',\n              ['75 Dec 03', '10', '17', '24', '31',\n               '76 Jan 07'],\n              [186796800, 187401600, 188006400, 188611200, 189216000,\n               189820800]),\n             ('1 day',\n              ['75 Dec 02', '03', '04', '05', '06', '07', '08', '09', '10',\n               '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21',\n               '22', '23', '24', '25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [186710400, 186796800, 186883200, 186969600, 187056000, 187142400,\n               187228800, 187315200, 187401600, 187488000, 187574400, 187660800,\n               187747200, 187833600, 187920000, 188006400, 188092800, 188179200,\n               188265600, 188352000, 188438400, 188524800, 188611200, 188697600,\n               188784000, 188870400, 188956800, 189043200, 189129600, 189216000,\n               189302400, 189388800, 189475200, 189561600])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 25), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [188697600, 188784000, 188870400, 188956800, 189043200, 189129600,\n               189216000, 189302400, 189388800, 189475200, 189561600]),\n             ('12 hours',\n              ['75 Dec 25 00:00', '12:00',\n               '26 00:00', '12:00',\n               '27 00:00', '12:00',\n               '28 00:00', '12:00',\n               '29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [188697600, 188740800, 188784000, 188827200, 188870400, 188913600,\n               188956800, 189000000, 189043200, 189086400, 189129600, 189172800,\n               189216000, 189259200, 189302400, 189345600, 189388800, 189432000,\n               189475200, 189518400]),\n             ('6 hours',\n              ['75 Dec 25 00:00', '06:00', '12:00', '18:00',\n               '26 00:00', '06:00', '12:00', '18:00',\n               '27 00:00', '06:00', '12:00', '18:00',\n               '28 00:00', '06:00', '12:00', '18:00',\n               '29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [188697600, 188719200, 188740800, 188762400, 188784000, 188805600,\n               188827200, 188848800, 188870400, 188892000, 188913600, 188935200,\n               188956800, 188978400, 189000000, 189021600, 189043200, 189064800,\n               189086400, 189108000, 189129600, 189151200, 189172800, 189194400,\n               189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200, 189388800, 189410400, 189432000, 189453600,\n               189475200, 189496800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 29), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [189043200, 189129600, 189216000, 189302400, 189388800, 189475200,\n               189561600]),\n             ('12 hours',\n              ['75 Dec 29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [189043200, 189086400, 189129600, 189172800, 189216000, 189259200,\n               189302400, 189345600, 189388800, 189432000, 189475200,\n               189518400]),\n             ('6 hours',\n              ['75 Dec 29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [189043200, 189064800, 189086400, 189108000, 189129600, 189151200,\n               189172800, 189194400, 189216000, 189237600, 189259200, 189280800,\n               189302400, 189324000, 189345600, 189367200, 189388800, 189410400,\n               189432000, 189453600, 189475200, 189496800]),\n             ('3 hours',\n              ['75 Dec 29 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '30 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '02 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '03 00:00', '03:00'],\n              [189043200, 189054000, 189064800, 189075600, 189086400, 189097200,\n               189108000, 189118800, 189129600, 189140400, 189151200, 189162000,\n               189172800, 189183600, 189194400, 189205200, 189216000, 189226800,\n               189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200, 189324000, 189334800, 189345600, 189356400,\n               189367200, 189378000, 189388800, 189399600, 189410400, 189421200,\n               189432000, 189442800, 189453600, 189464400, 189475200,\n               189486000])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 0, 0, 0), (1976, 1, 1, 14, 30)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00'],\n              [189216000, 189259200, 189302400, 189345600, 189388800]),\n             ('6 hours',\n              ['75 Dec 31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00'],\n              [189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200]),\n             ('3 hours',\n              ['75 Dec 31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00'],\n              [189216000, 189226800, 189237600, 189248400, 189259200, 189270000,\n               189280800, 189291600, 189302400, 189313200, 189324000, 189334800,\n               189345600, 189356400]),\n             ('2 hours',\n              ['75 Dec 31 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00'],\n              [189216000, 189223200, 189230400, 189237600, 189244800, 189252000,\n               189259200, 189266400, 189273600, 189280800, 189288000, 189295200,\n               189302400, 189309600, 189316800, 189324000, 189331200, 189338400,\n               189345600, 189352800, 189360000]),\n             ('1 hour',\n              ['75 Dec 31 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00',\n               '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00'],\n              [189216000, 189219600, 189223200, 189226800, 189230400, 189234000,\n               189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000, 189309600, 189313200, 189316800, 189320400,\n               189324000, 189327600, 189331200, 189334800, 189338400, 189342000,\n               189345600, 189349200, 189352800, 189356400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 6), (1976, 1, 1)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00'],\n              [189216000, 189259200, 189302400, 189345600]),\n             ('6 hours',\n              ['75 Dec 31 06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00'],\n              [189237600, 189259200, 189280800, 189302400, 189324000]),\n             ('3 hours',\n              ['75 Dec 31 06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00'],\n              [189237600, 189244800, 189252000, 189259200, 189266400, 189273600,\n               189280800, 189288000, 189295200, 189302400, 189309600]),\n             ('1 hour',\n              ['75 Dec 31 06:00', '07:00', '08:00', '09:00', '10:00', '11:00',\n               '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00',\n               '19:00', '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00'],\n              [189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000]),\n             ('30 minutes',\n              ['Dec 31 06:00', '06:30', '07:00', '07:30', '08:00', '08:30',\n               '09:00', '09:30', '10:00', '10:30', '11:00', '11:30', '12:00',\n               '12:30', '13:00', '13:30', '14:00', '14:30', '15:00', '15:30',\n               '16:00', '16:30', '17:00', '17:30', '18:00', '18:30', '19:00',\n               '19:30', '20:00', '20:30', '21:00', '21:30', '22:00', '22:30',\n               '23:00', '23:30',\n               'Jan 01 00:00', '00:30'],\n              [189237600, 189239400, 189241200, 189243000, 189244800, 189246600,\n               189248400, 189250200, 189252000, 189253800, 189255600, 189257400,\n               189259200, 189261000, 189262800, 189264600, 189266400, 189268200,\n               189270000, 189271800, 189273600, 189275400, 189277200, 189279000,\n               189280800, 189282600, 189284400, 189286200, 189288000, 189289800,\n               189291600, 189293400, 189295200, 189297000, 189298800, 189300600,\n               189302400, 189304200])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 23), (1976, 1, 1, 2)),\n            [('3 hours',\n              ['75 Dec 31 21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189291600, 189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 22:00',\n               '76 Jan 01 00:00', '02:00', '04:00'],\n              [189295200, 189302400, 189309600, 189316800]),\n             ('1 hour',\n              ['75 Dec 31 23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00'],\n              [189298800, 189302400, 189306000, 189309600, 189313200]),\n             ('30 minutes',\n              ['Dec 31 23:00', '23:30',\n               'Jan 01 00:00', '00:30', '01:00', '01:30', '02:00', '02:30'],\n              [189298800, 189300600, 189302400, 189304200, 189306000, 189307800,\n               189309600, 189311400]),\n             ('15 minutes',\n              ['Dec 31 23:00', '23:15', '23:30', '23:45',\n               'Jan 01 00:00', '00:15', '00:30', '00:45', '01:00', '01:15',\n               '01:30', '01:45', '02:00', '02:15'],\n              [189298800, 189299700, 189300600, 189301500, 189302400, 189303300,\n               189304200, 189305100, 189306000, 189306900, 189307800, 189308700,\n               189309600, 189310500]),\n             ('10 minutes',\n              ['Dec 31 23:00', '23:10', '23:20', '23:30', '23:40', '23:50',\n               'Jan 01 00:00', '00:10', '00:20', '00:30', '00:40', '00:50',\n               '01:00', '01:10', '01:20', '01:30', '01:40', '01:50', '02:00',\n               '02:10'],\n              [189298800, 189299400, 189300000, 189300600, 189301200, 189301800,\n               189302400, 189303000, 189303600, 189304200, 189304800, 189305400,\n               189306000, 189306600, 189307200, 189307800, 189308400, 189309000,\n               189309600, 189310200]),\n             ('5 minutes',\n              ['Dec 31 23:00', '23:05', '23:10', '23:15', '23:20', '23:25',\n               '23:30', '23:35', '23:40', '23:45', '23:50', '23:55',\n               'Jan 01 00:00', '00:05', '00:10', '00:15', '00:20', '00:25',\n               '00:30', '00:35', '00:40', '00:45', '00:50', '00:55', '01:00',\n               '01:05', '01:10', '01:15', '01:20', '01:25', '01:30', '01:35',\n               '01:40', '01:45', '01:50', '01:55', '02:00', '02:05'],\n              [189298800, 189299100, 189299400, 189299700, 189300000, 189300300,\n               189300600, 189300900, 189301200, 189301500, 189301800, 189302100,\n               189302400, 189302700, 189303000, 189303300, 189303600, 189303900,\n               189304200, 189304500, 189304800, 189305100, 189305400, 189305700,\n               189306000, 189306300, 189306600, 189306900, 189307200, 189307500,\n               189307800, 189308100, 189308400, 189308700, 189309000, 189309300,\n               189309600, 189309900])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 23, 18)),\n            [('12 hours',\n              ['Jun 09 00:00', '12:00', '10 00:00'],\n              [-1437868800, -1437825600, -1437782400]),\n             ('6 hours',\n              ['Jun 09 06:00', '12:00', '18:00', '10 00:00'],\n              [-1437847200, -1437825600, -1437804000, -1437782400]),\n             ('3 hours',\n              ['Jun 09 09:00', '12:00', '15:00', '18:00', '21:00', '10 00:00'],\n              [-1437836400, -1437825600, -1437814800, -1437804000, -1437793200,\n               -1437782400]),\n             ('2 hours',\n              ['Jun 09 10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00', '10 00:00'],\n              [-1437832800, -1437825600, -1437818400, -1437811200, -1437804000,\n               -1437796800, -1437789600, -1437782400]),\n             ('1 hour',\n              ['Jun 09 10:00', '11:00', '12:00', '13:00', '14:00', '15:00',\n               '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00',\n               '23:00',\n               '10 00:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000, -1437818400,\n               -1437814800, -1437811200, -1437807600, -1437804000, -1437800400,\n               -1437796800, -1437793200, -1437789600, -1437786000,\n               -1437782400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30', '14:00', '14:30', '15:00', '15:30', '16:00', '16:30',\n               '17:00', '17:30', '18:00', '18:30', '19:00', '19:30', '20:00',\n               '20:30', '21:00', '21:30', '22:00', '22:30', '23:00', '23:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200, -1437818400, -1437816600,\n               -1437814800, -1437813000, -1437811200, -1437809400, -1437807600,\n               -1437805800, -1437804000, -1437802200, -1437800400, -1437798600,\n               -1437796800, -1437795000, -1437793200, -1437791400, -1437789600,\n               -1437787800, -1437786000, -1437784200])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 13, 18)),\n            [('2 hours',\n              ['10:00', '12:00', '14:00'],\n              [-1437832800, -1437825600, -1437818400]),\n             ('1 hour',\n              ['10:00', '11:00', '12:00', '13:00', '14:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000,\n               -1437818400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00', '11:15', '11:30',\n               '11:45', '12:00', '12:15', '12:30', '12:45', '13:00', '13:15',\n               '13:30'],\n              [-1437832800, -1437831900, -1437831000, -1437830100, -1437829200,\n               -1437828300, -1437827400, -1437826500, -1437825600, -1437824700,\n               -1437823800, -1437822900, -1437822000, -1437821100,\n               -1437820200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50', '11:00',\n               '11:10', '11:20', '11:30', '11:40', '11:50', '12:00', '12:10',\n               '12:20', '12:30', '12:40', '12:50', '13:00', '13:10', '13:20'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800, -1437829200, -1437828600, -1437828000, -1437827400,\n               -1437826800, -1437826200, -1437825600, -1437825000, -1437824400,\n               -1437823800, -1437823200, -1437822600, -1437822000, -1437821400,\n               -1437820800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50', '10:55', '11:00', '11:05',\n               '11:10', '11:15', '11:20', '11:25', '11:30', '11:35', '11:40',\n               '11:45', '11:50', '11:55', '12:00', '12:05', '12:10', '12:15',\n               '12:20', '12:25', '12:30', '12:35', '12:40', '12:45', '12:50',\n               '12:55', '13:00', '13:05', '13:10', '13:15', '13:20'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800, -1437829500, -1437829200, -1437828900, -1437828600,\n               -1437828300, -1437828000, -1437827700, -1437827400, -1437827100,\n               -1437826800, -1437826500, -1437826200, -1437825900, -1437825600,\n               -1437825300, -1437825000, -1437824700, -1437824400, -1437824100,\n               -1437823800, -1437823500, -1437823200, -1437822900, -1437822600,\n               -1437822300, -1437822000, -1437821700, -1437821400, -1437821100,\n               -1437820800])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 48)),\n            [('30 minutes',\n              ['10:00', '10:30', '11:00'],\n              [-1437832800, -1437831000, -1437829200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00'],\n              [-1437832800, -1437831900, -1437831000, -1437830100,\n               -1437829200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21', '10:22', '10:23', '10:24', '10:25', '10:26', '10:27',\n               '10:28', '10:29', '10:30', '10:31', '10:32', '10:33', '10:34',\n               '10:35', '10:36', '10:37', '10:38', '10:39', '10:40', '10:41',\n               '10:42', '10:43', '10:44', '10:45', '10:46', '10:47', '10:48',\n               '10:49'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540, -1437831480, -1437831420, -1437831360,\n               -1437831300, -1437831240, -1437831180, -1437831120, -1437831060,\n               -1437831000, -1437830940, -1437830880, -1437830820, -1437830760,\n               -1437830700, -1437830640, -1437830580, -1437830520, -1437830460,\n               -1437830400, -1437830340, -1437830280, -1437830220, -1437830160,\n               -1437830100, -1437830040, -1437829980, -1437829920, -1437829860]\n              )]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 20)),\n            [('15 minutes',\n              ['10:00', '10:15', '10:30'],\n              [-1437832800, -1437831900, -1437831000]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30'],\n              [-1437832800, -1437832200, -1437831600, -1437831000]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540]),\n             ('30 seconds',\n              ['10:00:00', '10:00:30', '10:01:00', '10:01:30', '10:02:00',\n               '10:02:30', '10:03:00', '10:03:30', '10:04:00', '10:04:30',\n               '10:05:00', '10:05:30', '10:06:00', '10:06:30', '10:07:00',\n               '10:07:30', '10:08:00', '10:08:30', '10:09:00', '10:09:30',\n               '10:10:00', '10:10:30', '10:11:00', '10:11:30', '10:12:00',\n               '10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30', '10:19:00', '10:19:30',\n               '10:20:00', '10:20:30'],\n              [-1437832800, -1437832770, -1437832740, -1437832710, -1437832680,\n               -1437832650, -1437832620, -1437832590, -1437832560, -1437832530,\n               -1437832500, -1437832470, -1437832440, -1437832410, -1437832380,\n               -1437832350, -1437832320, -1437832290, -1437832260, -1437832230,\n               -1437832200, -1437832170, -1437832140, -1437832110, -1437832080,\n               -1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690, -1437831660, -1437831630,\n               -1437831600, -1437831570])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 18, 12)),\n            [('5 minutes',\n              ['10:10', '10:15', '10:20'],\n              [-1437832200, -1437831900, -1437831600]),\n             ('1 minute',\n              ['10:12', '10:13', '10:14', '10:15', '10:16', '10:17', '10:18',\n               '10:19'],\n              [-1437832080, -1437832020, -1437831960, -1437831900, -1437831840,\n               -1437831780, -1437831720, -1437831660]),\n             ('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30'],\n              [-1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15', '10:13:30',\n               '10:13:45', '10:14:00', '10:14:15', '10:14:30', '10:14:45',\n               '10:15:00', '10:15:15', '10:15:30', '10:15:45', '10:16:00',\n               '10:16:15', '10:16:30', '10:16:45', '10:17:00', '10:17:15',\n               '10:17:30', '10:17:45', '10:18:00', '10:18:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005, -1437831990,\n               -1437831975, -1437831960, -1437831945, -1437831930, -1437831915,\n               -1437831900, -1437831885, -1437831870, -1437831855, -1437831840,\n               -1437831825, -1437831810, -1437831795, -1437831780, -1437831765,\n               -1437831750, -1437831735, -1437831720, -1437831705]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20', '10:13:30', '10:13:40', '10:13:50', '10:14:00',\n               '10:14:10', '10:14:20', '10:14:30', '10:14:40', '10:14:50',\n               '10:15:00', '10:15:10', '10:15:20', '10:15:30', '10:15:40',\n               '10:15:50', '10:16:00', '10:16:10', '10:16:20', '10:16:30',\n               '10:16:40', '10:16:50', '10:17:00', '10:17:10', '10:17:20',\n               '10:17:30', '10:17:40', '10:17:50', '10:18:00', '10:18:10',\n               '10:18:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000, -1437831990, -1437831980, -1437831970, -1437831960,\n               -1437831950, -1437831940, -1437831930, -1437831920, -1437831910,\n               -1437831900, -1437831890, -1437831880, -1437831870, -1437831860,\n               -1437831850, -1437831840, -1437831830, -1437831820, -1437831810,\n               -1437831800, -1437831790, -1437831780, -1437831770, -1437831760,\n               -1437831750, -1437831740, -1437831730, -1437831720, -1437831710,\n               -1437831700])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 13, 12)),\n            [('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30'],\n              [-1437832050, -1437832020, -1437831990]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000]),\n             ('5 seconds',\n              ['10:12:30', '10:12:35', '10:12:40', '10:12:45', '10:12:50',\n               '10:12:55', '10:13:00', '10:13:05', '10:13:10', '10:13:15'],\n              [-1437832050, -1437832045, -1437832040, -1437832035, -1437832030,\n               -1437832025, -1437832020, -1437832015, -1437832010,\n               -1437832005]),\n             ('1 second',\n              ['10:12:33', '10:12:34', '10:12:35', '10:12:36', '10:12:37',\n               '10:12:38', '10:12:39', '10:12:40', '10:12:41', '10:12:42',\n               '10:12:43', '10:12:44', '10:12:45', '10:12:46', '10:12:47',\n               '10:12:48', '10:12:49', '10:12:50', '10:12:51', '10:12:52',\n               '10:12:53', '10:12:54', '10:12:55', '10:12:56', '10:12:57',\n               '10:12:58', '10:12:59', '10:13:00', '10:13:01', '10:13:02',\n               '10:13:03', '10:13:04', '10:13:05', '10:13:06', '10:13:07',\n               '10:13:08', '10:13:09', '10:13:10', '10:13:11', '10:13:12',\n               '10:13:13'],\n              [-1437832047, -1437832046, -1437832045, -1437832044, -1437832043,\n               -1437832042, -1437832041, -1437832040, -1437832039, -1437832038,\n               -1437832037, -1437832036, -1437832035, -1437832034, -1437832033,\n               -1437832032, -1437832031, -1437832030, -1437832029, -1437832028,\n               -1437832027, -1437832026, -1437832025, -1437832024, -1437832023,\n               -1437832022, -1437832021, -1437832020, -1437832019, -1437832018,\n               -1437832017, -1437832016, -1437832015, -1437832014, -1437832013,\n               -1437832012, -1437832011, -1437832010, -1437832009, -1437832008,\n               -1437832007])])\n\n    def test_min_unique(self):\n        bins = time_binnings(self.dates, min_unique=7)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_add_unique(self):\n        bins = time_binnings(self.dates, add_unique=7)\n        self.assertNotEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_limits(self):\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=17)},\n            {9, 17})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=16)},\n            {9})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=10, max_bins=17)},\n            {17})\n\n    def test_single_value(self):\n        dates = np.array([42])\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_no_values(self):\n        dates = np.array([])\n        self.assertRaises(ValueError, time_binnings, dates)\n\n        dates = np.array([np.nan, np.nan])\n        self.assertRaises(ValueError, time_binnings, dates)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 26,
                            "end_lineno": 627,
                            "parent": {
                                "file_name": "Orange/preprocess/tests/test_discretize.py",
                                "type": "class",
                                "name": "TestTimeBinning",
                                "content": "class TestTimeBinning(unittest.TestCase):\n    def setUp(self):\n        self.dates = [mktime(x) for x in\n            [(1975, 6, 9, 10, 0, 0, 0, 161, 0),\n             (1975, 6, 9, 10, 50, 0, 0, 161, 0),\n             (1975, 6, 9, 11, 40, 0, 0, 161, 0),\n             (1975, 6, 9, 12, 30, 0, 0, 161, 0),\n             (1975, 6, 9, 13, 20, 0, 0, 161, 0),\n             (1975, 6, 9, 14, 10, 0, 0, 161, 0)]]\n\n    def test_binning(self):\n        def testbin(start, end):\n            bins = _time_binnings(create(*start), create(*end), 3, 51)\n            return [(bin.width_label, bin.short_labels, bin.thresholds)\n                    for bin in reversed(bins)]\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1989, 3, 1)),\n            [('10 years',\n              ['70', '80', '90'],\n              [0, 315532800, 631152000]),\n             ('5 years',\n              ['75', '80', '85', '90'],\n              [157766400, 315532800, 473385600, 631152000]),\n             ('2 years',\n              ['74', '76', '78', '80', '82', '84', '86', '88', '90'],\n              [126230400, 189302400, 252460800, 315532800, 378691200, 441763200,\n               504921600, 567993600, 631152000]),\n             ('1 year',\n              ['75', '76', '77', '78', '79', '80', '81', '82', '83', '84', '85',\n               '86', '87', '88', '89', '90'],\n              [157766400, 189302400, 220924800, 252460800, 283996800, 315532800,\n               347155200, 378691200, 410227200, 441763200, 473385600, 504921600,\n               536457600, 567993600, 599616000, 631152000]),\n             ('6 months',\n              ['75 Jan', 'Jul', '76 Jan', 'Jul', '77 Jan', 'Jul', '78 Jan',\n               'Jul', '79 Jan', 'Jul', '80 Jan', 'Jul', '81 Jan', 'Jul',\n               '82 Jan', 'Jul', '83 Jan', 'Jul', '84 Jan', 'Jul', '85 Jan',\n               'Jul', '86 Jan', 'Jul', '87 Jan', 'Jul', '88 Jan', 'Jul',\n               '89 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200, 283996800, 299635200, 315532800, 331257600,\n               347155200, 362793600, 378691200, 394329600, 410227200, 425865600,\n               441763200, 457488000, 473385600, 489024000, 504921600, 520560000,\n               536457600, 552096000, 567993600, 583718400, 599616000,\n               615254400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1978, 3, 1)),\n            [('2 years',\n              ['74', '76', '78', '80'],\n              [126230400, 189302400, 252460800, 315532800]),\n             ('1 year',\n              ['75', '76', '77', '78', '79'],\n              [157766400, 189302400, 220924800, 252460800, 283996800]),\n             ('6 months',\n              ['75 Jan', 'Jul',\n               '76 Jan', 'Jul',\n               '77 Jan', 'Jul',\n               '78 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200]),\n             ('3 months',\n              ['75 Apr', 'Jul', 'Oct',\n               '76 Jan', 'Apr', 'Jul', 'Oct',\n               '77 Jan', 'Apr', 'Jul', 'Oct',\n               '78 Jan', 'Apr'],\n              [165542400, 173404800, 181353600, 189302400, 197164800, 205027200,\n               212976000, 220924800, 228700800, 236563200, 244512000, 252460800,\n               260236800]),\n             ('2 months',\n              ['75 Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '76 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '77 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '78 Jan', 'Mar', 'May'],\n              [162864000, 168134400, 173404800, 178761600, 184032000, 189302400,\n               194486400, 199756800, 205027200, 210384000, 215654400, 220924800,\n               226022400, 231292800, 236563200, 241920000, 247190400, 252460800,\n               257558400, 262828800]),\n             ('1 month',\n              ['75 Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '76 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '77 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '78 Jan', 'Feb', 'Mar', 'Apr'],\n              [165542400, 168134400, 170812800, 173404800, 176083200, 178761600,\n               181353600, 184032000, 186624000, 189302400, 191980800, 194486400,\n               197164800, 199756800, 202435200, 205027200, 207705600, 210384000,\n               212976000, 215654400, 218246400, 220924800, 223603200, 226022400,\n               228700800, 231292800, 233971200, 236563200, 239241600, 241920000,\n               244512000, 247190400, 249782400, 252460800, 255139200, 257558400,\n               260236800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 2), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('2 weeks',\n              ['75 Dec 03', '17', '31', '76 Jan 14'],\n              [186796800, 188006400, 189216000, 190425600]),\n             ('1 week',\n              ['75 Dec 03', '10', '17', '24', '31',\n               '76 Jan 07'],\n              [186796800, 187401600, 188006400, 188611200, 189216000,\n               189820800]),\n             ('1 day',\n              ['75 Dec 02', '03', '04', '05', '06', '07', '08', '09', '10',\n               '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21',\n               '22', '23', '24', '25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [186710400, 186796800, 186883200, 186969600, 187056000, 187142400,\n               187228800, 187315200, 187401600, 187488000, 187574400, 187660800,\n               187747200, 187833600, 187920000, 188006400, 188092800, 188179200,\n               188265600, 188352000, 188438400, 188524800, 188611200, 188697600,\n               188784000, 188870400, 188956800, 189043200, 189129600, 189216000,\n               189302400, 189388800, 189475200, 189561600])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 25), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [188697600, 188784000, 188870400, 188956800, 189043200, 189129600,\n               189216000, 189302400, 189388800, 189475200, 189561600]),\n             ('12 hours',\n              ['75 Dec 25 00:00', '12:00',\n               '26 00:00', '12:00',\n               '27 00:00', '12:00',\n               '28 00:00', '12:00',\n               '29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [188697600, 188740800, 188784000, 188827200, 188870400, 188913600,\n               188956800, 189000000, 189043200, 189086400, 189129600, 189172800,\n               189216000, 189259200, 189302400, 189345600, 189388800, 189432000,\n               189475200, 189518400]),\n             ('6 hours',\n              ['75 Dec 25 00:00', '06:00', '12:00', '18:00',\n               '26 00:00', '06:00', '12:00', '18:00',\n               '27 00:00', '06:00', '12:00', '18:00',\n               '28 00:00', '06:00', '12:00', '18:00',\n               '29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [188697600, 188719200, 188740800, 188762400, 188784000, 188805600,\n               188827200, 188848800, 188870400, 188892000, 188913600, 188935200,\n               188956800, 188978400, 189000000, 189021600, 189043200, 189064800,\n               189086400, 189108000, 189129600, 189151200, 189172800, 189194400,\n               189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200, 189388800, 189410400, 189432000, 189453600,\n               189475200, 189496800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 29), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [189043200, 189129600, 189216000, 189302400, 189388800, 189475200,\n               189561600]),\n             ('12 hours',\n              ['75 Dec 29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [189043200, 189086400, 189129600, 189172800, 189216000, 189259200,\n               189302400, 189345600, 189388800, 189432000, 189475200,\n               189518400]),\n             ('6 hours',\n              ['75 Dec 29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [189043200, 189064800, 189086400, 189108000, 189129600, 189151200,\n               189172800, 189194400, 189216000, 189237600, 189259200, 189280800,\n               189302400, 189324000, 189345600, 189367200, 189388800, 189410400,\n               189432000, 189453600, 189475200, 189496800]),\n             ('3 hours',\n              ['75 Dec 29 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '30 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '02 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '03 00:00', '03:00'],\n              [189043200, 189054000, 189064800, 189075600, 189086400, 189097200,\n               189108000, 189118800, 189129600, 189140400, 189151200, 189162000,\n               189172800, 189183600, 189194400, 189205200, 189216000, 189226800,\n               189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200, 189324000, 189334800, 189345600, 189356400,\n               189367200, 189378000, 189388800, 189399600, 189410400, 189421200,\n               189432000, 189442800, 189453600, 189464400, 189475200,\n               189486000])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 0, 0, 0), (1976, 1, 1, 14, 30)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00'],\n              [189216000, 189259200, 189302400, 189345600, 189388800]),\n             ('6 hours',\n              ['75 Dec 31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00'],\n              [189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200]),\n             ('3 hours',\n              ['75 Dec 31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00'],\n              [189216000, 189226800, 189237600, 189248400, 189259200, 189270000,\n               189280800, 189291600, 189302400, 189313200, 189324000, 189334800,\n               189345600, 189356400]),\n             ('2 hours',\n              ['75 Dec 31 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00'],\n              [189216000, 189223200, 189230400, 189237600, 189244800, 189252000,\n               189259200, 189266400, 189273600, 189280800, 189288000, 189295200,\n               189302400, 189309600, 189316800, 189324000, 189331200, 189338400,\n               189345600, 189352800, 189360000]),\n             ('1 hour',\n              ['75 Dec 31 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00',\n               '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00'],\n              [189216000, 189219600, 189223200, 189226800, 189230400, 189234000,\n               189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000, 189309600, 189313200, 189316800, 189320400,\n               189324000, 189327600, 189331200, 189334800, 189338400, 189342000,\n               189345600, 189349200, 189352800, 189356400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 6), (1976, 1, 1)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00'],\n              [189216000, 189259200, 189302400, 189345600]),\n             ('6 hours',\n              ['75 Dec 31 06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00'],\n              [189237600, 189259200, 189280800, 189302400, 189324000]),\n             ('3 hours',\n              ['75 Dec 31 06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00'],\n              [189237600, 189244800, 189252000, 189259200, 189266400, 189273600,\n               189280800, 189288000, 189295200, 189302400, 189309600]),\n             ('1 hour',\n              ['75 Dec 31 06:00', '07:00', '08:00', '09:00', '10:00', '11:00',\n               '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00',\n               '19:00', '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00'],\n              [189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000]),\n             ('30 minutes',\n              ['Dec 31 06:00', '06:30', '07:00', '07:30', '08:00', '08:30',\n               '09:00', '09:30', '10:00', '10:30', '11:00', '11:30', '12:00',\n               '12:30', '13:00', '13:30', '14:00', '14:30', '15:00', '15:30',\n               '16:00', '16:30', '17:00', '17:30', '18:00', '18:30', '19:00',\n               '19:30', '20:00', '20:30', '21:00', '21:30', '22:00', '22:30',\n               '23:00', '23:30',\n               'Jan 01 00:00', '00:30'],\n              [189237600, 189239400, 189241200, 189243000, 189244800, 189246600,\n               189248400, 189250200, 189252000, 189253800, 189255600, 189257400,\n               189259200, 189261000, 189262800, 189264600, 189266400, 189268200,\n               189270000, 189271800, 189273600, 189275400, 189277200, 189279000,\n               189280800, 189282600, 189284400, 189286200, 189288000, 189289800,\n               189291600, 189293400, 189295200, 189297000, 189298800, 189300600,\n               189302400, 189304200])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 23), (1976, 1, 1, 2)),\n            [('3 hours',\n              ['75 Dec 31 21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189291600, 189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 22:00',\n               '76 Jan 01 00:00', '02:00', '04:00'],\n              [189295200, 189302400, 189309600, 189316800]),\n             ('1 hour',\n              ['75 Dec 31 23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00'],\n              [189298800, 189302400, 189306000, 189309600, 189313200]),\n             ('30 minutes',\n              ['Dec 31 23:00', '23:30',\n               'Jan 01 00:00', '00:30', '01:00', '01:30', '02:00', '02:30'],\n              [189298800, 189300600, 189302400, 189304200, 189306000, 189307800,\n               189309600, 189311400]),\n             ('15 minutes',\n              ['Dec 31 23:00', '23:15', '23:30', '23:45',\n               'Jan 01 00:00', '00:15', '00:30', '00:45', '01:00', '01:15',\n               '01:30', '01:45', '02:00', '02:15'],\n              [189298800, 189299700, 189300600, 189301500, 189302400, 189303300,\n               189304200, 189305100, 189306000, 189306900, 189307800, 189308700,\n               189309600, 189310500]),\n             ('10 minutes',\n              ['Dec 31 23:00', '23:10', '23:20', '23:30', '23:40', '23:50',\n               'Jan 01 00:00', '00:10', '00:20', '00:30', '00:40', '00:50',\n               '01:00', '01:10', '01:20', '01:30', '01:40', '01:50', '02:00',\n               '02:10'],\n              [189298800, 189299400, 189300000, 189300600, 189301200, 189301800,\n               189302400, 189303000, 189303600, 189304200, 189304800, 189305400,\n               189306000, 189306600, 189307200, 189307800, 189308400, 189309000,\n               189309600, 189310200]),\n             ('5 minutes',\n              ['Dec 31 23:00', '23:05', '23:10', '23:15', '23:20', '23:25',\n               '23:30', '23:35', '23:40', '23:45', '23:50', '23:55',\n               'Jan 01 00:00', '00:05', '00:10', '00:15', '00:20', '00:25',\n               '00:30', '00:35', '00:40', '00:45', '00:50', '00:55', '01:00',\n               '01:05', '01:10', '01:15', '01:20', '01:25', '01:30', '01:35',\n               '01:40', '01:45', '01:50', '01:55', '02:00', '02:05'],\n              [189298800, 189299100, 189299400, 189299700, 189300000, 189300300,\n               189300600, 189300900, 189301200, 189301500, 189301800, 189302100,\n               189302400, 189302700, 189303000, 189303300, 189303600, 189303900,\n               189304200, 189304500, 189304800, 189305100, 189305400, 189305700,\n               189306000, 189306300, 189306600, 189306900, 189307200, 189307500,\n               189307800, 189308100, 189308400, 189308700, 189309000, 189309300,\n               189309600, 189309900])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 23, 18)),\n            [('12 hours',\n              ['Jun 09 00:00', '12:00', '10 00:00'],\n              [-1437868800, -1437825600, -1437782400]),\n             ('6 hours',\n              ['Jun 09 06:00', '12:00', '18:00', '10 00:00'],\n              [-1437847200, -1437825600, -1437804000, -1437782400]),\n             ('3 hours',\n              ['Jun 09 09:00', '12:00', '15:00', '18:00', '21:00', '10 00:00'],\n              [-1437836400, -1437825600, -1437814800, -1437804000, -1437793200,\n               -1437782400]),\n             ('2 hours',\n              ['Jun 09 10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00', '10 00:00'],\n              [-1437832800, -1437825600, -1437818400, -1437811200, -1437804000,\n               -1437796800, -1437789600, -1437782400]),\n             ('1 hour',\n              ['Jun 09 10:00', '11:00', '12:00', '13:00', '14:00', '15:00',\n               '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00',\n               '23:00',\n               '10 00:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000, -1437818400,\n               -1437814800, -1437811200, -1437807600, -1437804000, -1437800400,\n               -1437796800, -1437793200, -1437789600, -1437786000,\n               -1437782400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30', '14:00', '14:30', '15:00', '15:30', '16:00', '16:30',\n               '17:00', '17:30', '18:00', '18:30', '19:00', '19:30', '20:00',\n               '20:30', '21:00', '21:30', '22:00', '22:30', '23:00', '23:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200, -1437818400, -1437816600,\n               -1437814800, -1437813000, -1437811200, -1437809400, -1437807600,\n               -1437805800, -1437804000, -1437802200, -1437800400, -1437798600,\n               -1437796800, -1437795000, -1437793200, -1437791400, -1437789600,\n               -1437787800, -1437786000, -1437784200])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 13, 18)),\n            [('2 hours',\n              ['10:00', '12:00', '14:00'],\n              [-1437832800, -1437825600, -1437818400]),\n             ('1 hour',\n              ['10:00', '11:00', '12:00', '13:00', '14:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000,\n               -1437818400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00', '11:15', '11:30',\n               '11:45', '12:00', '12:15', '12:30', '12:45', '13:00', '13:15',\n               '13:30'],\n              [-1437832800, -1437831900, -1437831000, -1437830100, -1437829200,\n               -1437828300, -1437827400, -1437826500, -1437825600, -1437824700,\n               -1437823800, -1437822900, -1437822000, -1437821100,\n               -1437820200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50', '11:00',\n               '11:10', '11:20', '11:30', '11:40', '11:50', '12:00', '12:10',\n               '12:20', '12:30', '12:40', '12:50', '13:00', '13:10', '13:20'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800, -1437829200, -1437828600, -1437828000, -1437827400,\n               -1437826800, -1437826200, -1437825600, -1437825000, -1437824400,\n               -1437823800, -1437823200, -1437822600, -1437822000, -1437821400,\n               -1437820800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50', '10:55', '11:00', '11:05',\n               '11:10', '11:15', '11:20', '11:25', '11:30', '11:35', '11:40',\n               '11:45', '11:50', '11:55', '12:00', '12:05', '12:10', '12:15',\n               '12:20', '12:25', '12:30', '12:35', '12:40', '12:45', '12:50',\n               '12:55', '13:00', '13:05', '13:10', '13:15', '13:20'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800, -1437829500, -1437829200, -1437828900, -1437828600,\n               -1437828300, -1437828000, -1437827700, -1437827400, -1437827100,\n               -1437826800, -1437826500, -1437826200, -1437825900, -1437825600,\n               -1437825300, -1437825000, -1437824700, -1437824400, -1437824100,\n               -1437823800, -1437823500, -1437823200, -1437822900, -1437822600,\n               -1437822300, -1437822000, -1437821700, -1437821400, -1437821100,\n               -1437820800])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 48)),\n            [('30 minutes',\n              ['10:00', '10:30', '11:00'],\n              [-1437832800, -1437831000, -1437829200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00'],\n              [-1437832800, -1437831900, -1437831000, -1437830100,\n               -1437829200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21', '10:22', '10:23', '10:24', '10:25', '10:26', '10:27',\n               '10:28', '10:29', '10:30', '10:31', '10:32', '10:33', '10:34',\n               '10:35', '10:36', '10:37', '10:38', '10:39', '10:40', '10:41',\n               '10:42', '10:43', '10:44', '10:45', '10:46', '10:47', '10:48',\n               '10:49'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540, -1437831480, -1437831420, -1437831360,\n               -1437831300, -1437831240, -1437831180, -1437831120, -1437831060,\n               -1437831000, -1437830940, -1437830880, -1437830820, -1437830760,\n               -1437830700, -1437830640, -1437830580, -1437830520, -1437830460,\n               -1437830400, -1437830340, -1437830280, -1437830220, -1437830160,\n               -1437830100, -1437830040, -1437829980, -1437829920, -1437829860]\n              )]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 20)),\n            [('15 minutes',\n              ['10:00', '10:15', '10:30'],\n              [-1437832800, -1437831900, -1437831000]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30'],\n              [-1437832800, -1437832200, -1437831600, -1437831000]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540]),\n             ('30 seconds',\n              ['10:00:00', '10:00:30', '10:01:00', '10:01:30', '10:02:00',\n               '10:02:30', '10:03:00', '10:03:30', '10:04:00', '10:04:30',\n               '10:05:00', '10:05:30', '10:06:00', '10:06:30', '10:07:00',\n               '10:07:30', '10:08:00', '10:08:30', '10:09:00', '10:09:30',\n               '10:10:00', '10:10:30', '10:11:00', '10:11:30', '10:12:00',\n               '10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30', '10:19:00', '10:19:30',\n               '10:20:00', '10:20:30'],\n              [-1437832800, -1437832770, -1437832740, -1437832710, -1437832680,\n               -1437832650, -1437832620, -1437832590, -1437832560, -1437832530,\n               -1437832500, -1437832470, -1437832440, -1437832410, -1437832380,\n               -1437832350, -1437832320, -1437832290, -1437832260, -1437832230,\n               -1437832200, -1437832170, -1437832140, -1437832110, -1437832080,\n               -1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690, -1437831660, -1437831630,\n               -1437831600, -1437831570])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 18, 12)),\n            [('5 minutes',\n              ['10:10', '10:15', '10:20'],\n              [-1437832200, -1437831900, -1437831600]),\n             ('1 minute',\n              ['10:12', '10:13', '10:14', '10:15', '10:16', '10:17', '10:18',\n               '10:19'],\n              [-1437832080, -1437832020, -1437831960, -1437831900, -1437831840,\n               -1437831780, -1437831720, -1437831660]),\n             ('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30'],\n              [-1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15', '10:13:30',\n               '10:13:45', '10:14:00', '10:14:15', '10:14:30', '10:14:45',\n               '10:15:00', '10:15:15', '10:15:30', '10:15:45', '10:16:00',\n               '10:16:15', '10:16:30', '10:16:45', '10:17:00', '10:17:15',\n               '10:17:30', '10:17:45', '10:18:00', '10:18:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005, -1437831990,\n               -1437831975, -1437831960, -1437831945, -1437831930, -1437831915,\n               -1437831900, -1437831885, -1437831870, -1437831855, -1437831840,\n               -1437831825, -1437831810, -1437831795, -1437831780, -1437831765,\n               -1437831750, -1437831735, -1437831720, -1437831705]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20', '10:13:30', '10:13:40', '10:13:50', '10:14:00',\n               '10:14:10', '10:14:20', '10:14:30', '10:14:40', '10:14:50',\n               '10:15:00', '10:15:10', '10:15:20', '10:15:30', '10:15:40',\n               '10:15:50', '10:16:00', '10:16:10', '10:16:20', '10:16:30',\n               '10:16:40', '10:16:50', '10:17:00', '10:17:10', '10:17:20',\n               '10:17:30', '10:17:40', '10:17:50', '10:18:00', '10:18:10',\n               '10:18:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000, -1437831990, -1437831980, -1437831970, -1437831960,\n               -1437831950, -1437831940, -1437831930, -1437831920, -1437831910,\n               -1437831900, -1437831890, -1437831880, -1437831870, -1437831860,\n               -1437831850, -1437831840, -1437831830, -1437831820, -1437831810,\n               -1437831800, -1437831790, -1437831780, -1437831770, -1437831760,\n               -1437831750, -1437831740, -1437831730, -1437831720, -1437831710,\n               -1437831700])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 13, 12)),\n            [('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30'],\n              [-1437832050, -1437832020, -1437831990]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000]),\n             ('5 seconds',\n              ['10:12:30', '10:12:35', '10:12:40', '10:12:45', '10:12:50',\n               '10:12:55', '10:13:00', '10:13:05', '10:13:10', '10:13:15'],\n              [-1437832050, -1437832045, -1437832040, -1437832035, -1437832030,\n               -1437832025, -1437832020, -1437832015, -1437832010,\n               -1437832005]),\n             ('1 second',\n              ['10:12:33', '10:12:34', '10:12:35', '10:12:36', '10:12:37',\n               '10:12:38', '10:12:39', '10:12:40', '10:12:41', '10:12:42',\n               '10:12:43', '10:12:44', '10:12:45', '10:12:46', '10:12:47',\n               '10:12:48', '10:12:49', '10:12:50', '10:12:51', '10:12:52',\n               '10:12:53', '10:12:54', '10:12:55', '10:12:56', '10:12:57',\n               '10:12:58', '10:12:59', '10:13:00', '10:13:01', '10:13:02',\n               '10:13:03', '10:13:04', '10:13:05', '10:13:06', '10:13:07',\n               '10:13:08', '10:13:09', '10:13:10', '10:13:11', '10:13:12',\n               '10:13:13'],\n              [-1437832047, -1437832046, -1437832045, -1437832044, -1437832043,\n               -1437832042, -1437832041, -1437832040, -1437832039, -1437832038,\n               -1437832037, -1437832036, -1437832035, -1437832034, -1437832033,\n               -1437832032, -1437832031, -1437832030, -1437832029, -1437832028,\n               -1437832027, -1437832026, -1437832025, -1437832024, -1437832023,\n               -1437832022, -1437832021, -1437832020, -1437832019, -1437832018,\n               -1437832017, -1437832016, -1437832015, -1437832014, -1437832013,\n               -1437832012, -1437832011, -1437832010, -1437832009, -1437832008,\n               -1437832007])])\n\n    def test_min_unique(self):\n        bins = time_binnings(self.dates, min_unique=7)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_add_unique(self):\n        bins = time_binnings(self.dates, add_unique=7)\n        self.assertNotEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_limits(self):\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=17)},\n            {9, 17})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=16)},\n            {9})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=10, max_bins=17)},\n            {17})\n\n    def test_single_value(self):\n        dates = np.array([42])\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_no_values(self):\n        dates = np.array([])\n        self.assertRaises(ValueError, time_binnings, dates)\n\n        dates = np.array([np.nan, np.nan])\n        self.assertRaises(ValueError, time_binnings, dates)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 16,
                                "end_lineno": 664,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "Orange/preprocess/tests/test_discretize.py",
                            "type": "class",
                            "name": "TestTimeBinning",
                            "content": "class TestTimeBinning(unittest.TestCase):\n    def setUp(self):\n        self.dates = [mktime(x) for x in\n            [(1975, 6, 9, 10, 0, 0, 0, 161, 0),\n             (1975, 6, 9, 10, 50, 0, 0, 161, 0),\n             (1975, 6, 9, 11, 40, 0, 0, 161, 0),\n             (1975, 6, 9, 12, 30, 0, 0, 161, 0),\n             (1975, 6, 9, 13, 20, 0, 0, 161, 0),\n             (1975, 6, 9, 14, 10, 0, 0, 161, 0)]]\n\n    def test_binning(self):\n        def testbin(start, end):\n            bins = _time_binnings(create(*start), create(*end), 3, 51)\n            return [(bin.width_label, bin.short_labels, bin.thresholds)\n                    for bin in reversed(bins)]\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1989, 3, 1)),\n            [('10 years',\n              ['70', '80', '90'],\n              [0, 315532800, 631152000]),\n             ('5 years',\n              ['75', '80', '85', '90'],\n              [157766400, 315532800, 473385600, 631152000]),\n             ('2 years',\n              ['74', '76', '78', '80', '82', '84', '86', '88', '90'],\n              [126230400, 189302400, 252460800, 315532800, 378691200, 441763200,\n               504921600, 567993600, 631152000]),\n             ('1 year',\n              ['75', '76', '77', '78', '79', '80', '81', '82', '83', '84', '85',\n               '86', '87', '88', '89', '90'],\n              [157766400, 189302400, 220924800, 252460800, 283996800, 315532800,\n               347155200, 378691200, 410227200, 441763200, 473385600, 504921600,\n               536457600, 567993600, 599616000, 631152000]),\n             ('6 months',\n              ['75 Jan', 'Jul', '76 Jan', 'Jul', '77 Jan', 'Jul', '78 Jan',\n               'Jul', '79 Jan', 'Jul', '80 Jan', 'Jul', '81 Jan', 'Jul',\n               '82 Jan', 'Jul', '83 Jan', 'Jul', '84 Jan', 'Jul', '85 Jan',\n               'Jul', '86 Jan', 'Jul', '87 Jan', 'Jul', '88 Jan', 'Jul',\n               '89 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200, 283996800, 299635200, 315532800, 331257600,\n               347155200, 362793600, 378691200, 394329600, 410227200, 425865600,\n               441763200, 457488000, 473385600, 489024000, 504921600, 520560000,\n               536457600, 552096000, 567993600, 583718400, 599616000,\n               615254400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1978, 3, 1)),\n            [('2 years',\n              ['74', '76', '78', '80'],\n              [126230400, 189302400, 252460800, 315532800]),\n             ('1 year',\n              ['75', '76', '77', '78', '79'],\n              [157766400, 189302400, 220924800, 252460800, 283996800]),\n             ('6 months',\n              ['75 Jan', 'Jul',\n               '76 Jan', 'Jul',\n               '77 Jan', 'Jul',\n               '78 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200]),\n             ('3 months',\n              ['75 Apr', 'Jul', 'Oct',\n               '76 Jan', 'Apr', 'Jul', 'Oct',\n               '77 Jan', 'Apr', 'Jul', 'Oct',\n               '78 Jan', 'Apr'],\n              [165542400, 173404800, 181353600, 189302400, 197164800, 205027200,\n               212976000, 220924800, 228700800, 236563200, 244512000, 252460800,\n               260236800]),\n             ('2 months',\n              ['75 Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '76 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '77 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '78 Jan', 'Mar', 'May'],\n              [162864000, 168134400, 173404800, 178761600, 184032000, 189302400,\n               194486400, 199756800, 205027200, 210384000, 215654400, 220924800,\n               226022400, 231292800, 236563200, 241920000, 247190400, 252460800,\n               257558400, 262828800]),\n             ('1 month',\n              ['75 Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '76 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '77 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '78 Jan', 'Feb', 'Mar', 'Apr'],\n              [165542400, 168134400, 170812800, 173404800, 176083200, 178761600,\n               181353600, 184032000, 186624000, 189302400, 191980800, 194486400,\n               197164800, 199756800, 202435200, 205027200, 207705600, 210384000,\n               212976000, 215654400, 218246400, 220924800, 223603200, 226022400,\n               228700800, 231292800, 233971200, 236563200, 239241600, 241920000,\n               244512000, 247190400, 249782400, 252460800, 255139200, 257558400,\n               260236800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 2), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('2 weeks',\n              ['75 Dec 03', '17', '31', '76 Jan 14'],\n              [186796800, 188006400, 189216000, 190425600]),\n             ('1 week',\n              ['75 Dec 03', '10', '17', '24', '31',\n               '76 Jan 07'],\n              [186796800, 187401600, 188006400, 188611200, 189216000,\n               189820800]),\n             ('1 day',\n              ['75 Dec 02', '03', '04', '05', '06', '07', '08', '09', '10',\n               '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21',\n               '22', '23', '24', '25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [186710400, 186796800, 186883200, 186969600, 187056000, 187142400,\n               187228800, 187315200, 187401600, 187488000, 187574400, 187660800,\n               187747200, 187833600, 187920000, 188006400, 188092800, 188179200,\n               188265600, 188352000, 188438400, 188524800, 188611200, 188697600,\n               188784000, 188870400, 188956800, 189043200, 189129600, 189216000,\n               189302400, 189388800, 189475200, 189561600])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 25), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [188697600, 188784000, 188870400, 188956800, 189043200, 189129600,\n               189216000, 189302400, 189388800, 189475200, 189561600]),\n             ('12 hours',\n              ['75 Dec 25 00:00', '12:00',\n               '26 00:00', '12:00',\n               '27 00:00', '12:00',\n               '28 00:00', '12:00',\n               '29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [188697600, 188740800, 188784000, 188827200, 188870400, 188913600,\n               188956800, 189000000, 189043200, 189086400, 189129600, 189172800,\n               189216000, 189259200, 189302400, 189345600, 189388800, 189432000,\n               189475200, 189518400]),\n             ('6 hours',\n              ['75 Dec 25 00:00', '06:00', '12:00', '18:00',\n               '26 00:00', '06:00', '12:00', '18:00',\n               '27 00:00', '06:00', '12:00', '18:00',\n               '28 00:00', '06:00', '12:00', '18:00',\n               '29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [188697600, 188719200, 188740800, 188762400, 188784000, 188805600,\n               188827200, 188848800, 188870400, 188892000, 188913600, 188935200,\n               188956800, 188978400, 189000000, 189021600, 189043200, 189064800,\n               189086400, 189108000, 189129600, 189151200, 189172800, 189194400,\n               189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200, 189388800, 189410400, 189432000, 189453600,\n               189475200, 189496800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 29), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [189043200, 189129600, 189216000, 189302400, 189388800, 189475200,\n               189561600]),\n             ('12 hours',\n              ['75 Dec 29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [189043200, 189086400, 189129600, 189172800, 189216000, 189259200,\n               189302400, 189345600, 189388800, 189432000, 189475200,\n               189518400]),\n             ('6 hours',\n              ['75 Dec 29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [189043200, 189064800, 189086400, 189108000, 189129600, 189151200,\n               189172800, 189194400, 189216000, 189237600, 189259200, 189280800,\n               189302400, 189324000, 189345600, 189367200, 189388800, 189410400,\n               189432000, 189453600, 189475200, 189496800]),\n             ('3 hours',\n              ['75 Dec 29 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '30 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '02 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '03 00:00', '03:00'],\n              [189043200, 189054000, 189064800, 189075600, 189086400, 189097200,\n               189108000, 189118800, 189129600, 189140400, 189151200, 189162000,\n               189172800, 189183600, 189194400, 189205200, 189216000, 189226800,\n               189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200, 189324000, 189334800, 189345600, 189356400,\n               189367200, 189378000, 189388800, 189399600, 189410400, 189421200,\n               189432000, 189442800, 189453600, 189464400, 189475200,\n               189486000])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 0, 0, 0), (1976, 1, 1, 14, 30)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00'],\n              [189216000, 189259200, 189302400, 189345600, 189388800]),\n             ('6 hours',\n              ['75 Dec 31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00'],\n              [189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200]),\n             ('3 hours',\n              ['75 Dec 31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00'],\n              [189216000, 189226800, 189237600, 189248400, 189259200, 189270000,\n               189280800, 189291600, 189302400, 189313200, 189324000, 189334800,\n               189345600, 189356400]),\n             ('2 hours',\n              ['75 Dec 31 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00'],\n              [189216000, 189223200, 189230400, 189237600, 189244800, 189252000,\n               189259200, 189266400, 189273600, 189280800, 189288000, 189295200,\n               189302400, 189309600, 189316800, 189324000, 189331200, 189338400,\n               189345600, 189352800, 189360000]),\n             ('1 hour',\n              ['75 Dec 31 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00',\n               '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00'],\n              [189216000, 189219600, 189223200, 189226800, 189230400, 189234000,\n               189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000, 189309600, 189313200, 189316800, 189320400,\n               189324000, 189327600, 189331200, 189334800, 189338400, 189342000,\n               189345600, 189349200, 189352800, 189356400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 6), (1976, 1, 1)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00'],\n              [189216000, 189259200, 189302400, 189345600]),\n             ('6 hours',\n              ['75 Dec 31 06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00'],\n              [189237600, 189259200, 189280800, 189302400, 189324000]),\n             ('3 hours',\n              ['75 Dec 31 06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00'],\n              [189237600, 189244800, 189252000, 189259200, 189266400, 189273600,\n               189280800, 189288000, 189295200, 189302400, 189309600]),\n             ('1 hour',\n              ['75 Dec 31 06:00', '07:00', '08:00', '09:00', '10:00', '11:00',\n               '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00',\n               '19:00', '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00'],\n              [189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000]),\n             ('30 minutes',\n              ['Dec 31 06:00', '06:30', '07:00', '07:30', '08:00', '08:30',\n               '09:00', '09:30', '10:00', '10:30', '11:00', '11:30', '12:00',\n               '12:30', '13:00', '13:30', '14:00', '14:30', '15:00', '15:30',\n               '16:00', '16:30', '17:00', '17:30', '18:00', '18:30', '19:00',\n               '19:30', '20:00', '20:30', '21:00', '21:30', '22:00', '22:30',\n               '23:00', '23:30',\n               'Jan 01 00:00', '00:30'],\n              [189237600, 189239400, 189241200, 189243000, 189244800, 189246600,\n               189248400, 189250200, 189252000, 189253800, 189255600, 189257400,\n               189259200, 189261000, 189262800, 189264600, 189266400, 189268200,\n               189270000, 189271800, 189273600, 189275400, 189277200, 189279000,\n               189280800, 189282600, 189284400, 189286200, 189288000, 189289800,\n               189291600, 189293400, 189295200, 189297000, 189298800, 189300600,\n               189302400, 189304200])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 23), (1976, 1, 1, 2)),\n            [('3 hours',\n              ['75 Dec 31 21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189291600, 189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 22:00',\n               '76 Jan 01 00:00', '02:00', '04:00'],\n              [189295200, 189302400, 189309600, 189316800]),\n             ('1 hour',\n              ['75 Dec 31 23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00'],\n              [189298800, 189302400, 189306000, 189309600, 189313200]),\n             ('30 minutes',\n              ['Dec 31 23:00', '23:30',\n               'Jan 01 00:00', '00:30', '01:00', '01:30', '02:00', '02:30'],\n              [189298800, 189300600, 189302400, 189304200, 189306000, 189307800,\n               189309600, 189311400]),\n             ('15 minutes',\n              ['Dec 31 23:00', '23:15', '23:30', '23:45',\n               'Jan 01 00:00', '00:15', '00:30', '00:45', '01:00', '01:15',\n               '01:30', '01:45', '02:00', '02:15'],\n              [189298800, 189299700, 189300600, 189301500, 189302400, 189303300,\n               189304200, 189305100, 189306000, 189306900, 189307800, 189308700,\n               189309600, 189310500]),\n             ('10 minutes',\n              ['Dec 31 23:00', '23:10', '23:20', '23:30', '23:40', '23:50',\n               'Jan 01 00:00', '00:10', '00:20', '00:30', '00:40', '00:50',\n               '01:00', '01:10', '01:20', '01:30', '01:40', '01:50', '02:00',\n               '02:10'],\n              [189298800, 189299400, 189300000, 189300600, 189301200, 189301800,\n               189302400, 189303000, 189303600, 189304200, 189304800, 189305400,\n               189306000, 189306600, 189307200, 189307800, 189308400, 189309000,\n               189309600, 189310200]),\n             ('5 minutes',\n              ['Dec 31 23:00', '23:05', '23:10', '23:15', '23:20', '23:25',\n               '23:30', '23:35', '23:40', '23:45', '23:50', '23:55',\n               'Jan 01 00:00', '00:05', '00:10', '00:15', '00:20', '00:25',\n               '00:30', '00:35', '00:40', '00:45', '00:50', '00:55', '01:00',\n               '01:05', '01:10', '01:15', '01:20', '01:25', '01:30', '01:35',\n               '01:40', '01:45', '01:50', '01:55', '02:00', '02:05'],\n              [189298800, 189299100, 189299400, 189299700, 189300000, 189300300,\n               189300600, 189300900, 189301200, 189301500, 189301800, 189302100,\n               189302400, 189302700, 189303000, 189303300, 189303600, 189303900,\n               189304200, 189304500, 189304800, 189305100, 189305400, 189305700,\n               189306000, 189306300, 189306600, 189306900, 189307200, 189307500,\n               189307800, 189308100, 189308400, 189308700, 189309000, 189309300,\n               189309600, 189309900])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 23, 18)),\n            [('12 hours',\n              ['Jun 09 00:00', '12:00', '10 00:00'],\n              [-1437868800, -1437825600, -1437782400]),\n             ('6 hours',\n              ['Jun 09 06:00', '12:00', '18:00', '10 00:00'],\n              [-1437847200, -1437825600, -1437804000, -1437782400]),\n             ('3 hours',\n              ['Jun 09 09:00', '12:00', '15:00', '18:00', '21:00', '10 00:00'],\n              [-1437836400, -1437825600, -1437814800, -1437804000, -1437793200,\n               -1437782400]),\n             ('2 hours',\n              ['Jun 09 10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00', '10 00:00'],\n              [-1437832800, -1437825600, -1437818400, -1437811200, -1437804000,\n               -1437796800, -1437789600, -1437782400]),\n             ('1 hour',\n              ['Jun 09 10:00', '11:00', '12:00', '13:00', '14:00', '15:00',\n               '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00',\n               '23:00',\n               '10 00:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000, -1437818400,\n               -1437814800, -1437811200, -1437807600, -1437804000, -1437800400,\n               -1437796800, -1437793200, -1437789600, -1437786000,\n               -1437782400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30', '14:00', '14:30', '15:00', '15:30', '16:00', '16:30',\n               '17:00', '17:30', '18:00', '18:30', '19:00', '19:30', '20:00',\n               '20:30', '21:00', '21:30', '22:00', '22:30', '23:00', '23:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200, -1437818400, -1437816600,\n               -1437814800, -1437813000, -1437811200, -1437809400, -1437807600,\n               -1437805800, -1437804000, -1437802200, -1437800400, -1437798600,\n               -1437796800, -1437795000, -1437793200, -1437791400, -1437789600,\n               -1437787800, -1437786000, -1437784200])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 13, 18)),\n            [('2 hours',\n              ['10:00', '12:00', '14:00'],\n              [-1437832800, -1437825600, -1437818400]),\n             ('1 hour',\n              ['10:00', '11:00', '12:00', '13:00', '14:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000,\n               -1437818400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00', '11:15', '11:30',\n               '11:45', '12:00', '12:15', '12:30', '12:45', '13:00', '13:15',\n               '13:30'],\n              [-1437832800, -1437831900, -1437831000, -1437830100, -1437829200,\n               -1437828300, -1437827400, -1437826500, -1437825600, -1437824700,\n               -1437823800, -1437822900, -1437822000, -1437821100,\n               -1437820200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50', '11:00',\n               '11:10', '11:20', '11:30', '11:40', '11:50', '12:00', '12:10',\n               '12:20', '12:30', '12:40', '12:50', '13:00', '13:10', '13:20'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800, -1437829200, -1437828600, -1437828000, -1437827400,\n               -1437826800, -1437826200, -1437825600, -1437825000, -1437824400,\n               -1437823800, -1437823200, -1437822600, -1437822000, -1437821400,\n               -1437820800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50', '10:55', '11:00', '11:05',\n               '11:10', '11:15', '11:20', '11:25', '11:30', '11:35', '11:40',\n               '11:45', '11:50', '11:55', '12:00', '12:05', '12:10', '12:15',\n               '12:20', '12:25', '12:30', '12:35', '12:40', '12:45', '12:50',\n               '12:55', '13:00', '13:05', '13:10', '13:15', '13:20'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800, -1437829500, -1437829200, -1437828900, -1437828600,\n               -1437828300, -1437828000, -1437827700, -1437827400, -1437827100,\n               -1437826800, -1437826500, -1437826200, -1437825900, -1437825600,\n               -1437825300, -1437825000, -1437824700, -1437824400, -1437824100,\n               -1437823800, -1437823500, -1437823200, -1437822900, -1437822600,\n               -1437822300, -1437822000, -1437821700, -1437821400, -1437821100,\n               -1437820800])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 48)),\n            [('30 minutes',\n              ['10:00', '10:30', '11:00'],\n              [-1437832800, -1437831000, -1437829200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00'],\n              [-1437832800, -1437831900, -1437831000, -1437830100,\n               -1437829200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21', '10:22', '10:23', '10:24', '10:25', '10:26', '10:27',\n               '10:28', '10:29', '10:30', '10:31', '10:32', '10:33', '10:34',\n               '10:35', '10:36', '10:37', '10:38', '10:39', '10:40', '10:41',\n               '10:42', '10:43', '10:44', '10:45', '10:46', '10:47', '10:48',\n               '10:49'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540, -1437831480, -1437831420, -1437831360,\n               -1437831300, -1437831240, -1437831180, -1437831120, -1437831060,\n               -1437831000, -1437830940, -1437830880, -1437830820, -1437830760,\n               -1437830700, -1437830640, -1437830580, -1437830520, -1437830460,\n               -1437830400, -1437830340, -1437830280, -1437830220, -1437830160,\n               -1437830100, -1437830040, -1437829980, -1437829920, -1437829860]\n              )]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 20)),\n            [('15 minutes',\n              ['10:00', '10:15', '10:30'],\n              [-1437832800, -1437831900, -1437831000]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30'],\n              [-1437832800, -1437832200, -1437831600, -1437831000]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540]),\n             ('30 seconds',\n              ['10:00:00', '10:00:30', '10:01:00', '10:01:30', '10:02:00',\n               '10:02:30', '10:03:00', '10:03:30', '10:04:00', '10:04:30',\n               '10:05:00', '10:05:30', '10:06:00', '10:06:30', '10:07:00',\n               '10:07:30', '10:08:00', '10:08:30', '10:09:00', '10:09:30',\n               '10:10:00', '10:10:30', '10:11:00', '10:11:30', '10:12:00',\n               '10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30', '10:19:00', '10:19:30',\n               '10:20:00', '10:20:30'],\n              [-1437832800, -1437832770, -1437832740, -1437832710, -1437832680,\n               -1437832650, -1437832620, -1437832590, -1437832560, -1437832530,\n               -1437832500, -1437832470, -1437832440, -1437832410, -1437832380,\n               -1437832350, -1437832320, -1437832290, -1437832260, -1437832230,\n               -1437832200, -1437832170, -1437832140, -1437832110, -1437832080,\n               -1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690, -1437831660, -1437831630,\n               -1437831600, -1437831570])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 18, 12)),\n            [('5 minutes',\n              ['10:10', '10:15', '10:20'],\n              [-1437832200, -1437831900, -1437831600]),\n             ('1 minute',\n              ['10:12', '10:13', '10:14', '10:15', '10:16', '10:17', '10:18',\n               '10:19'],\n              [-1437832080, -1437832020, -1437831960, -1437831900, -1437831840,\n               -1437831780, -1437831720, -1437831660]),\n             ('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30'],\n              [-1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15', '10:13:30',\n               '10:13:45', '10:14:00', '10:14:15', '10:14:30', '10:14:45',\n               '10:15:00', '10:15:15', '10:15:30', '10:15:45', '10:16:00',\n               '10:16:15', '10:16:30', '10:16:45', '10:17:00', '10:17:15',\n               '10:17:30', '10:17:45', '10:18:00', '10:18:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005, -1437831990,\n               -1437831975, -1437831960, -1437831945, -1437831930, -1437831915,\n               -1437831900, -1437831885, -1437831870, -1437831855, -1437831840,\n               -1437831825, -1437831810, -1437831795, -1437831780, -1437831765,\n               -1437831750, -1437831735, -1437831720, -1437831705]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20', '10:13:30', '10:13:40', '10:13:50', '10:14:00',\n               '10:14:10', '10:14:20', '10:14:30', '10:14:40', '10:14:50',\n               '10:15:00', '10:15:10', '10:15:20', '10:15:30', '10:15:40',\n               '10:15:50', '10:16:00', '10:16:10', '10:16:20', '10:16:30',\n               '10:16:40', '10:16:50', '10:17:00', '10:17:10', '10:17:20',\n               '10:17:30', '10:17:40', '10:17:50', '10:18:00', '10:18:10',\n               '10:18:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000, -1437831990, -1437831980, -1437831970, -1437831960,\n               -1437831950, -1437831940, -1437831930, -1437831920, -1437831910,\n               -1437831900, -1437831890, -1437831880, -1437831870, -1437831860,\n               -1437831850, -1437831840, -1437831830, -1437831820, -1437831810,\n               -1437831800, -1437831790, -1437831780, -1437831770, -1437831760,\n               -1437831750, -1437831740, -1437831730, -1437831720, -1437831710,\n               -1437831700])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 13, 12)),\n            [('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30'],\n              [-1437832050, -1437832020, -1437831990]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000]),\n             ('5 seconds',\n              ['10:12:30', '10:12:35', '10:12:40', '10:12:45', '10:12:50',\n               '10:12:55', '10:13:00', '10:13:05', '10:13:10', '10:13:15'],\n              [-1437832050, -1437832045, -1437832040, -1437832035, -1437832030,\n               -1437832025, -1437832020, -1437832015, -1437832010,\n               -1437832005]),\n             ('1 second',\n              ['10:12:33', '10:12:34', '10:12:35', '10:12:36', '10:12:37',\n               '10:12:38', '10:12:39', '10:12:40', '10:12:41', '10:12:42',\n               '10:12:43', '10:12:44', '10:12:45', '10:12:46', '10:12:47',\n               '10:12:48', '10:12:49', '10:12:50', '10:12:51', '10:12:52',\n               '10:12:53', '10:12:54', '10:12:55', '10:12:56', '10:12:57',\n               '10:12:58', '10:12:59', '10:13:00', '10:13:01', '10:13:02',\n               '10:13:03', '10:13:04', '10:13:05', '10:13:06', '10:13:07',\n               '10:13:08', '10:13:09', '10:13:10', '10:13:11', '10:13:12',\n               '10:13:13'],\n              [-1437832047, -1437832046, -1437832045, -1437832044, -1437832043,\n               -1437832042, -1437832041, -1437832040, -1437832039, -1437832038,\n               -1437832037, -1437832036, -1437832035, -1437832034, -1437832033,\n               -1437832032, -1437832031, -1437832030, -1437832029, -1437832028,\n               -1437832027, -1437832026, -1437832025, -1437832024, -1437832023,\n               -1437832022, -1437832021, -1437832020, -1437832019, -1437832018,\n               -1437832017, -1437832016, -1437832015, -1437832014, -1437832013,\n               -1437832012, -1437832011, -1437832010, -1437832009, -1437832008,\n               -1437832007])])\n\n    def test_min_unique(self):\n        bins = time_binnings(self.dates, min_unique=7)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_add_unique(self):\n        bins = time_binnings(self.dates, add_unique=7)\n        self.assertNotEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_limits(self):\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=17)},\n            {9, 17})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=16)},\n            {9})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=10, max_bins=17)},\n            {17})\n\n    def test_single_value(self):\n        dates = np.array([42])\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_no_values(self):\n        dates = np.array([])\n        self.assertRaises(ValueError, time_binnings, dates)\n\n        dates = np.array([np.nan, np.nan])\n        self.assertRaises(ValueError, time_binnings, dates)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 16,
                            "end_lineno": 664,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 64,
                            "length": 10
                        },
                        "new_range": {
                            "start": 65,
                            "length": 10
                        },
                        "section": "class TestTimeBinning(unittest.TestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        self.assertEqual(",
                                "type": "context"
                            },
                            {
                                "content": "            testbin((1975, 4, 2), (1978, 3, 1)),",
                                "type": "context"
                            },
                            {
                                "content": "            [('2 years',",
                                "type": "context"
                            },
                            {
                                "content": "              ['74', '76', '78', '80'],",
                                "type": "deleted"
                            },
                            {
                                "content": "              ['1974', '1976', '1978', '1980'],",
                                "type": "added"
                            },
                            {
                                "content": "              [126230400, 189302400, 252460800, 315532800]),",
                                "type": "context"
                            },
                            {
                                "content": "             ('1 year',",
                                "type": "context"
                            },
                            {
                                "content": "              ['75', '76', '77', '78', '79'],",
                                "type": "deleted"
                            },
                            {
                                "content": "              ['1975', '1976', '1977', '1978', '1979'],",
                                "type": "added"
                            },
                            {
                                "content": "              [157766400, 189302400, 220924800, 252460800, 283996800]),",
                                "type": "context"
                            },
                            {
                                "content": "             ('6 months',",
                                "type": "context"
                            },
                            {
                                "content": "              ['75 Jan', 'Jul',",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/preprocess/tests/test_discretize.py",
                            "type": "method",
                            "name": "TestTimeBinning.test_binning",
                            "content": "class TestTimeBinning(unittest.TestCase):\n    def setUp(self):\n        self.dates = [mktime(x) for x in\n            [(1975, 6, 9, 10, 0, 0, 0, 161, 0),\n             (1975, 6, 9, 10, 50, 0, 0, 161, 0),\n             (1975, 6, 9, 11, 40, 0, 0, 161, 0),\n             (1975, 6, 9, 12, 30, 0, 0, 161, 0),\n             (1975, 6, 9, 13, 20, 0, 0, 161, 0),\n             (1975, 6, 9, 14, 10, 0, 0, 161, 0)]]\n\n    def test_binning(self):\n        def testbin(start, end):\n            bins = _time_binnings(create(*start), create(*end), 3, 51)\n            return [(bin.width_label, bin.short_labels, bin.thresholds)\n                    for bin in reversed(bins)]\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1989, 3, 1)),\n            [('10 years',\n              ['70', '80', '90'],\n              [0, 315532800, 631152000]),\n             ('5 years',\n              ['75', '80', '85', '90'],\n              [157766400, 315532800, 473385600, 631152000]),\n             ('2 years',\n              ['74', '76', '78', '80', '82', '84', '86', '88', '90'],\n              [126230400, 189302400, 252460800, 315532800, 378691200, 441763200,\n               504921600, 567993600, 631152000]),\n             ('1 year',\n              ['75', '76', '77', '78', '79', '80', '81', '82', '83', '84', '85',\n               '86', '87', '88', '89', '90'],\n              [157766400, 189302400, 220924800, 252460800, 283996800, 315532800,\n               347155200, 378691200, 410227200, 441763200, 473385600, 504921600,\n               536457600, 567993600, 599616000, 631152000]),\n             ('6 months',\n              ['75 Jan', 'Jul', '76 Jan', 'Jul', '77 Jan', 'Jul', '78 Jan',\n               'Jul', '79 Jan', 'Jul', '80 Jan', 'Jul', '81 Jan', 'Jul',\n               '82 Jan', 'Jul', '83 Jan', 'Jul', '84 Jan', 'Jul', '85 Jan',\n               'Jul', '86 Jan', 'Jul', '87 Jan', 'Jul', '88 Jan', 'Jul',\n               '89 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200, 283996800, 299635200, 315532800, 331257600,\n               347155200, 362793600, 378691200, 394329600, 410227200, 425865600,\n               441763200, 457488000, 473385600, 489024000, 504921600, 520560000,\n               536457600, 552096000, 567993600, 583718400, 599616000,\n               615254400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1978, 3, 1)),\n            [('2 years',\n              ['74', '76', '78', '80'],\n              [126230400, 189302400, 252460800, 315532800]),\n             ('1 year',\n              ['75', '76', '77', '78', '79'],\n              [157766400, 189302400, 220924800, 252460800, 283996800]),\n             ('6 months',\n              ['75 Jan', 'Jul',\n               '76 Jan', 'Jul',\n               '77 Jan', 'Jul',\n               '78 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200]),\n             ('3 months',\n              ['75 Apr', 'Jul', 'Oct',\n               '76 Jan', 'Apr', 'Jul', 'Oct',\n               '77 Jan', 'Apr', 'Jul', 'Oct',\n               '78 Jan', 'Apr'],\n              [165542400, 173404800, 181353600, 189302400, 197164800, 205027200,\n               212976000, 220924800, 228700800, 236563200, 244512000, 252460800,\n               260236800]),\n             ('2 months',\n              ['75 Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '76 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '77 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '78 Jan', 'Mar', 'May'],\n              [162864000, 168134400, 173404800, 178761600, 184032000, 189302400,\n               194486400, 199756800, 205027200, 210384000, 215654400, 220924800,\n               226022400, 231292800, 236563200, 241920000, 247190400, 252460800,\n               257558400, 262828800]),\n             ('1 month',\n              ['75 Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '76 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '77 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '78 Jan', 'Feb', 'Mar', 'Apr'],\n              [165542400, 168134400, 170812800, 173404800, 176083200, 178761600,\n               181353600, 184032000, 186624000, 189302400, 191980800, 194486400,\n               197164800, 199756800, 202435200, 205027200, 207705600, 210384000,\n               212976000, 215654400, 218246400, 220924800, 223603200, 226022400,\n               228700800, 231292800, 233971200, 236563200, 239241600, 241920000,\n               244512000, 247190400, 249782400, 252460800, 255139200, 257558400,\n               260236800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 2), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('2 weeks',\n              ['75 Dec 03', '17', '31', '76 Jan 14'],\n              [186796800, 188006400, 189216000, 190425600]),\n             ('1 week',\n              ['75 Dec 03', '10', '17', '24', '31',\n               '76 Jan 07'],\n              [186796800, 187401600, 188006400, 188611200, 189216000,\n               189820800]),\n             ('1 day',\n              ['75 Dec 02', '03', '04', '05', '06', '07', '08', '09', '10',\n               '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21',\n               '22', '23', '24', '25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [186710400, 186796800, 186883200, 186969600, 187056000, 187142400,\n               187228800, 187315200, 187401600, 187488000, 187574400, 187660800,\n               187747200, 187833600, 187920000, 188006400, 188092800, 188179200,\n               188265600, 188352000, 188438400, 188524800, 188611200, 188697600,\n               188784000, 188870400, 188956800, 189043200, 189129600, 189216000,\n               189302400, 189388800, 189475200, 189561600])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 25), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [188697600, 188784000, 188870400, 188956800, 189043200, 189129600,\n               189216000, 189302400, 189388800, 189475200, 189561600]),\n             ('12 hours',\n              ['75 Dec 25 00:00', '12:00',\n               '26 00:00', '12:00',\n               '27 00:00', '12:00',\n               '28 00:00', '12:00',\n               '29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [188697600, 188740800, 188784000, 188827200, 188870400, 188913600,\n               188956800, 189000000, 189043200, 189086400, 189129600, 189172800,\n               189216000, 189259200, 189302400, 189345600, 189388800, 189432000,\n               189475200, 189518400]),\n             ('6 hours',\n              ['75 Dec 25 00:00', '06:00', '12:00', '18:00',\n               '26 00:00', '06:00', '12:00', '18:00',\n               '27 00:00', '06:00', '12:00', '18:00',\n               '28 00:00', '06:00', '12:00', '18:00',\n               '29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [188697600, 188719200, 188740800, 188762400, 188784000, 188805600,\n               188827200, 188848800, 188870400, 188892000, 188913600, 188935200,\n               188956800, 188978400, 189000000, 189021600, 189043200, 189064800,\n               189086400, 189108000, 189129600, 189151200, 189172800, 189194400,\n               189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200, 189388800, 189410400, 189432000, 189453600,\n               189475200, 189496800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 29), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [189043200, 189129600, 189216000, 189302400, 189388800, 189475200,\n               189561600]),\n             ('12 hours',\n              ['75 Dec 29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [189043200, 189086400, 189129600, 189172800, 189216000, 189259200,\n               189302400, 189345600, 189388800, 189432000, 189475200,\n               189518400]),\n             ('6 hours',\n              ['75 Dec 29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [189043200, 189064800, 189086400, 189108000, 189129600, 189151200,\n               189172800, 189194400, 189216000, 189237600, 189259200, 189280800,\n               189302400, 189324000, 189345600, 189367200, 189388800, 189410400,\n               189432000, 189453600, 189475200, 189496800]),\n             ('3 hours',\n              ['75 Dec 29 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '30 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '02 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '03 00:00', '03:00'],\n              [189043200, 189054000, 189064800, 189075600, 189086400, 189097200,\n               189108000, 189118800, 189129600, 189140400, 189151200, 189162000,\n               189172800, 189183600, 189194400, 189205200, 189216000, 189226800,\n               189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200, 189324000, 189334800, 189345600, 189356400,\n               189367200, 189378000, 189388800, 189399600, 189410400, 189421200,\n               189432000, 189442800, 189453600, 189464400, 189475200,\n               189486000])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 0, 0, 0), (1976, 1, 1, 14, 30)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00'],\n              [189216000, 189259200, 189302400, 189345600, 189388800]),\n             ('6 hours',\n              ['75 Dec 31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00'],\n              [189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200]),\n             ('3 hours',\n              ['75 Dec 31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00'],\n              [189216000, 189226800, 189237600, 189248400, 189259200, 189270000,\n               189280800, 189291600, 189302400, 189313200, 189324000, 189334800,\n               189345600, 189356400]),\n             ('2 hours',\n              ['75 Dec 31 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00'],\n              [189216000, 189223200, 189230400, 189237600, 189244800, 189252000,\n               189259200, 189266400, 189273600, 189280800, 189288000, 189295200,\n               189302400, 189309600, 189316800, 189324000, 189331200, 189338400,\n               189345600, 189352800, 189360000]),\n             ('1 hour',\n              ['75 Dec 31 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00',\n               '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00'],\n              [189216000, 189219600, 189223200, 189226800, 189230400, 189234000,\n               189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000, 189309600, 189313200, 189316800, 189320400,\n               189324000, 189327600, 189331200, 189334800, 189338400, 189342000,\n               189345600, 189349200, 189352800, 189356400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 6), (1976, 1, 1)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00'],\n              [189216000, 189259200, 189302400, 189345600]),\n             ('6 hours',\n              ['75 Dec 31 06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00'],\n              [189237600, 189259200, 189280800, 189302400, 189324000]),\n             ('3 hours',\n              ['75 Dec 31 06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00'],\n              [189237600, 189244800, 189252000, 189259200, 189266400, 189273600,\n               189280800, 189288000, 189295200, 189302400, 189309600]),\n             ('1 hour',\n              ['75 Dec 31 06:00', '07:00', '08:00', '09:00', '10:00', '11:00',\n               '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00',\n               '19:00', '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00'],\n              [189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000]),\n             ('30 minutes',\n              ['Dec 31 06:00', '06:30', '07:00', '07:30', '08:00', '08:30',\n               '09:00', '09:30', '10:00', '10:30', '11:00', '11:30', '12:00',\n               '12:30', '13:00', '13:30', '14:00', '14:30', '15:00', '15:30',\n               '16:00', '16:30', '17:00', '17:30', '18:00', '18:30', '19:00',\n               '19:30', '20:00', '20:30', '21:00', '21:30', '22:00', '22:30',\n               '23:00', '23:30',\n               'Jan 01 00:00', '00:30'],\n              [189237600, 189239400, 189241200, 189243000, 189244800, 189246600,\n               189248400, 189250200, 189252000, 189253800, 189255600, 189257400,\n               189259200, 189261000, 189262800, 189264600, 189266400, 189268200,\n               189270000, 189271800, 189273600, 189275400, 189277200, 189279000,\n               189280800, 189282600, 189284400, 189286200, 189288000, 189289800,\n               189291600, 189293400, 189295200, 189297000, 189298800, 189300600,\n               189302400, 189304200])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 23), (1976, 1, 1, 2)),\n            [('3 hours',\n              ['75 Dec 31 21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189291600, 189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 22:00',\n               '76 Jan 01 00:00', '02:00', '04:00'],\n              [189295200, 189302400, 189309600, 189316800]),\n             ('1 hour',\n              ['75 Dec 31 23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00'],\n              [189298800, 189302400, 189306000, 189309600, 189313200]),\n             ('30 minutes',\n              ['Dec 31 23:00', '23:30',\n               'Jan 01 00:00', '00:30', '01:00', '01:30', '02:00', '02:30'],\n              [189298800, 189300600, 189302400, 189304200, 189306000, 189307800,\n               189309600, 189311400]),\n             ('15 minutes',\n              ['Dec 31 23:00', '23:15', '23:30', '23:45',\n               'Jan 01 00:00', '00:15', '00:30', '00:45', '01:00', '01:15',\n               '01:30', '01:45', '02:00', '02:15'],\n              [189298800, 189299700, 189300600, 189301500, 189302400, 189303300,\n               189304200, 189305100, 189306000, 189306900, 189307800, 189308700,\n               189309600, 189310500]),\n             ('10 minutes',\n              ['Dec 31 23:00', '23:10', '23:20', '23:30', '23:40', '23:50',\n               'Jan 01 00:00', '00:10', '00:20', '00:30', '00:40', '00:50',\n               '01:00', '01:10', '01:20', '01:30', '01:40', '01:50', '02:00',\n               '02:10'],\n              [189298800, 189299400, 189300000, 189300600, 189301200, 189301800,\n               189302400, 189303000, 189303600, 189304200, 189304800, 189305400,\n               189306000, 189306600, 189307200, 189307800, 189308400, 189309000,\n               189309600, 189310200]),\n             ('5 minutes',\n              ['Dec 31 23:00', '23:05', '23:10', '23:15', '23:20', '23:25',\n               '23:30', '23:35', '23:40', '23:45', '23:50', '23:55',\n               'Jan 01 00:00', '00:05', '00:10', '00:15', '00:20', '00:25',\n               '00:30', '00:35', '00:40', '00:45', '00:50', '00:55', '01:00',\n               '01:05', '01:10', '01:15', '01:20', '01:25', '01:30', '01:35',\n               '01:40', '01:45', '01:50', '01:55', '02:00', '02:05'],\n              [189298800, 189299100, 189299400, 189299700, 189300000, 189300300,\n               189300600, 189300900, 189301200, 189301500, 189301800, 189302100,\n               189302400, 189302700, 189303000, 189303300, 189303600, 189303900,\n               189304200, 189304500, 189304800, 189305100, 189305400, 189305700,\n               189306000, 189306300, 189306600, 189306900, 189307200, 189307500,\n               189307800, 189308100, 189308400, 189308700, 189309000, 189309300,\n               189309600, 189309900])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 23, 18)),\n            [('12 hours',\n              ['Jun 09 00:00', '12:00', '10 00:00'],\n              [-1437868800, -1437825600, -1437782400]),\n             ('6 hours',\n              ['Jun 09 06:00', '12:00', '18:00', '10 00:00'],\n              [-1437847200, -1437825600, -1437804000, -1437782400]),\n             ('3 hours',\n              ['Jun 09 09:00', '12:00', '15:00', '18:00', '21:00', '10 00:00'],\n              [-1437836400, -1437825600, -1437814800, -1437804000, -1437793200,\n               -1437782400]),\n             ('2 hours',\n              ['Jun 09 10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00', '10 00:00'],\n              [-1437832800, -1437825600, -1437818400, -1437811200, -1437804000,\n               -1437796800, -1437789600, -1437782400]),\n             ('1 hour',\n              ['Jun 09 10:00', '11:00', '12:00', '13:00', '14:00', '15:00',\n               '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00',\n               '23:00',\n               '10 00:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000, -1437818400,\n               -1437814800, -1437811200, -1437807600, -1437804000, -1437800400,\n               -1437796800, -1437793200, -1437789600, -1437786000,\n               -1437782400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30', '14:00', '14:30', '15:00', '15:30', '16:00', '16:30',\n               '17:00', '17:30', '18:00', '18:30', '19:00', '19:30', '20:00',\n               '20:30', '21:00', '21:30', '22:00', '22:30', '23:00', '23:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200, -1437818400, -1437816600,\n               -1437814800, -1437813000, -1437811200, -1437809400, -1437807600,\n               -1437805800, -1437804000, -1437802200, -1437800400, -1437798600,\n               -1437796800, -1437795000, -1437793200, -1437791400, -1437789600,\n               -1437787800, -1437786000, -1437784200])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 13, 18)),\n            [('2 hours',\n              ['10:00', '12:00', '14:00'],\n              [-1437832800, -1437825600, -1437818400]),\n             ('1 hour',\n              ['10:00', '11:00', '12:00', '13:00', '14:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000,\n               -1437818400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00', '11:15', '11:30',\n               '11:45', '12:00', '12:15', '12:30', '12:45', '13:00', '13:15',\n               '13:30'],\n              [-1437832800, -1437831900, -1437831000, -1437830100, -1437829200,\n               -1437828300, -1437827400, -1437826500, -1437825600, -1437824700,\n               -1437823800, -1437822900, -1437822000, -1437821100,\n               -1437820200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50', '11:00',\n               '11:10', '11:20', '11:30', '11:40', '11:50', '12:00', '12:10',\n               '12:20', '12:30', '12:40', '12:50', '13:00', '13:10', '13:20'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800, -1437829200, -1437828600, -1437828000, -1437827400,\n               -1437826800, -1437826200, -1437825600, -1437825000, -1437824400,\n               -1437823800, -1437823200, -1437822600, -1437822000, -1437821400,\n               -1437820800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50', '10:55', '11:00', '11:05',\n               '11:10', '11:15', '11:20', '11:25', '11:30', '11:35', '11:40',\n               '11:45', '11:50', '11:55', '12:00', '12:05', '12:10', '12:15',\n               '12:20', '12:25', '12:30', '12:35', '12:40', '12:45', '12:50',\n               '12:55', '13:00', '13:05', '13:10', '13:15', '13:20'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800, -1437829500, -1437829200, -1437828900, -1437828600,\n               -1437828300, -1437828000, -1437827700, -1437827400, -1437827100,\n               -1437826800, -1437826500, -1437826200, -1437825900, -1437825600,\n               -1437825300, -1437825000, -1437824700, -1437824400, -1437824100,\n               -1437823800, -1437823500, -1437823200, -1437822900, -1437822600,\n               -1437822300, -1437822000, -1437821700, -1437821400, -1437821100,\n               -1437820800])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 48)),\n            [('30 minutes',\n              ['10:00', '10:30', '11:00'],\n              [-1437832800, -1437831000, -1437829200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00'],\n              [-1437832800, -1437831900, -1437831000, -1437830100,\n               -1437829200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21', '10:22', '10:23', '10:24', '10:25', '10:26', '10:27',\n               '10:28', '10:29', '10:30', '10:31', '10:32', '10:33', '10:34',\n               '10:35', '10:36', '10:37', '10:38', '10:39', '10:40', '10:41',\n               '10:42', '10:43', '10:44', '10:45', '10:46', '10:47', '10:48',\n               '10:49'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540, -1437831480, -1437831420, -1437831360,\n               -1437831300, -1437831240, -1437831180, -1437831120, -1437831060,\n               -1437831000, -1437830940, -1437830880, -1437830820, -1437830760,\n               -1437830700, -1437830640, -1437830580, -1437830520, -1437830460,\n               -1437830400, -1437830340, -1437830280, -1437830220, -1437830160,\n               -1437830100, -1437830040, -1437829980, -1437829920, -1437829860]\n              )]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 20)),\n            [('15 minutes',\n              ['10:00', '10:15', '10:30'],\n              [-1437832800, -1437831900, -1437831000]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30'],\n              [-1437832800, -1437832200, -1437831600, -1437831000]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540]),\n             ('30 seconds',\n              ['10:00:00', '10:00:30', '10:01:00', '10:01:30', '10:02:00',\n               '10:02:30', '10:03:00', '10:03:30', '10:04:00', '10:04:30',\n               '10:05:00', '10:05:30', '10:06:00', '10:06:30', '10:07:00',\n               '10:07:30', '10:08:00', '10:08:30', '10:09:00', '10:09:30',\n               '10:10:00', '10:10:30', '10:11:00', '10:11:30', '10:12:00',\n               '10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30', '10:19:00', '10:19:30',\n               '10:20:00', '10:20:30'],\n              [-1437832800, -1437832770, -1437832740, -1437832710, -1437832680,\n               -1437832650, -1437832620, -1437832590, -1437832560, -1437832530,\n               -1437832500, -1437832470, -1437832440, -1437832410, -1437832380,\n               -1437832350, -1437832320, -1437832290, -1437832260, -1437832230,\n               -1437832200, -1437832170, -1437832140, -1437832110, -1437832080,\n               -1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690, -1437831660, -1437831630,\n               -1437831600, -1437831570])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 18, 12)),\n            [('5 minutes',\n              ['10:10', '10:15', '10:20'],\n              [-1437832200, -1437831900, -1437831600]),\n             ('1 minute',\n              ['10:12', '10:13', '10:14', '10:15', '10:16', '10:17', '10:18',\n               '10:19'],\n              [-1437832080, -1437832020, -1437831960, -1437831900, -1437831840,\n               -1437831780, -1437831720, -1437831660]),\n             ('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30'],\n              [-1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15', '10:13:30',\n               '10:13:45', '10:14:00', '10:14:15', '10:14:30', '10:14:45',\n               '10:15:00', '10:15:15', '10:15:30', '10:15:45', '10:16:00',\n               '10:16:15', '10:16:30', '10:16:45', '10:17:00', '10:17:15',\n               '10:17:30', '10:17:45', '10:18:00', '10:18:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005, -1437831990,\n               -1437831975, -1437831960, -1437831945, -1437831930, -1437831915,\n               -1437831900, -1437831885, -1437831870, -1437831855, -1437831840,\n               -1437831825, -1437831810, -1437831795, -1437831780, -1437831765,\n               -1437831750, -1437831735, -1437831720, -1437831705]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20', '10:13:30', '10:13:40', '10:13:50', '10:14:00',\n               '10:14:10', '10:14:20', '10:14:30', '10:14:40', '10:14:50',\n               '10:15:00', '10:15:10', '10:15:20', '10:15:30', '10:15:40',\n               '10:15:50', '10:16:00', '10:16:10', '10:16:20', '10:16:30',\n               '10:16:40', '10:16:50', '10:17:00', '10:17:10', '10:17:20',\n               '10:17:30', '10:17:40', '10:17:50', '10:18:00', '10:18:10',\n               '10:18:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000, -1437831990, -1437831980, -1437831970, -1437831960,\n               -1437831950, -1437831940, -1437831930, -1437831920, -1437831910,\n               -1437831900, -1437831890, -1437831880, -1437831870, -1437831860,\n               -1437831850, -1437831840, -1437831830, -1437831820, -1437831810,\n               -1437831800, -1437831790, -1437831780, -1437831770, -1437831760,\n               -1437831750, -1437831740, -1437831730, -1437831720, -1437831710,\n               -1437831700])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 13, 12)),\n            [('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30'],\n              [-1437832050, -1437832020, -1437831990]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000]),\n             ('5 seconds',\n              ['10:12:30', '10:12:35', '10:12:40', '10:12:45', '10:12:50',\n               '10:12:55', '10:13:00', '10:13:05', '10:13:10', '10:13:15'],\n              [-1437832050, -1437832045, -1437832040, -1437832035, -1437832030,\n               -1437832025, -1437832020, -1437832015, -1437832010,\n               -1437832005]),\n             ('1 second',\n              ['10:12:33', '10:12:34', '10:12:35', '10:12:36', '10:12:37',\n               '10:12:38', '10:12:39', '10:12:40', '10:12:41', '10:12:42',\n               '10:12:43', '10:12:44', '10:12:45', '10:12:46', '10:12:47',\n               '10:12:48', '10:12:49', '10:12:50', '10:12:51', '10:12:52',\n               '10:12:53', '10:12:54', '10:12:55', '10:12:56', '10:12:57',\n               '10:12:58', '10:12:59', '10:13:00', '10:13:01', '10:13:02',\n               '10:13:03', '10:13:04', '10:13:05', '10:13:06', '10:13:07',\n               '10:13:08', '10:13:09', '10:13:10', '10:13:11', '10:13:12',\n               '10:13:13'],\n              [-1437832047, -1437832046, -1437832045, -1437832044, -1437832043,\n               -1437832042, -1437832041, -1437832040, -1437832039, -1437832038,\n               -1437832037, -1437832036, -1437832035, -1437832034, -1437832033,\n               -1437832032, -1437832031, -1437832030, -1437832029, -1437832028,\n               -1437832027, -1437832026, -1437832025, -1437832024, -1437832023,\n               -1437832022, -1437832021, -1437832020, -1437832019, -1437832018,\n               -1437832017, -1437832016, -1437832015, -1437832014, -1437832013,\n               -1437832012, -1437832011, -1437832010, -1437832009, -1437832008,\n               -1437832007])])\n\n    def test_min_unique(self):\n        bins = time_binnings(self.dates, min_unique=7)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_add_unique(self):\n        bins = time_binnings(self.dates, add_unique=7)\n        self.assertNotEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_limits(self):\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=17)},\n            {9, 17})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=16)},\n            {9})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=10, max_bins=17)},\n            {17})\n\n    def test_single_value(self):\n        dates = np.array([42])\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_no_values(self):\n        dates = np.array([])\n        self.assertRaises(ValueError, time_binnings, dates)\n\n        dates = np.array([np.nan, np.nan])\n        self.assertRaises(ValueError, time_binnings, dates)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 26,
                            "end_lineno": 627,
                            "parent": {
                                "file_name": "Orange/preprocess/tests/test_discretize.py",
                                "type": "class",
                                "name": "TestTimeBinning",
                                "content": "class TestTimeBinning(unittest.TestCase):\n    def setUp(self):\n        self.dates = [mktime(x) for x in\n            [(1975, 6, 9, 10, 0, 0, 0, 161, 0),\n             (1975, 6, 9, 10, 50, 0, 0, 161, 0),\n             (1975, 6, 9, 11, 40, 0, 0, 161, 0),\n             (1975, 6, 9, 12, 30, 0, 0, 161, 0),\n             (1975, 6, 9, 13, 20, 0, 0, 161, 0),\n             (1975, 6, 9, 14, 10, 0, 0, 161, 0)]]\n\n    def test_binning(self):\n        def testbin(start, end):\n            bins = _time_binnings(create(*start), create(*end), 3, 51)\n            return [(bin.width_label, bin.short_labels, bin.thresholds)\n                    for bin in reversed(bins)]\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1989, 3, 1)),\n            [('10 years',\n              ['70', '80', '90'],\n              [0, 315532800, 631152000]),\n             ('5 years',\n              ['75', '80', '85', '90'],\n              [157766400, 315532800, 473385600, 631152000]),\n             ('2 years',\n              ['74', '76', '78', '80', '82', '84', '86', '88', '90'],\n              [126230400, 189302400, 252460800, 315532800, 378691200, 441763200,\n               504921600, 567993600, 631152000]),\n             ('1 year',\n              ['75', '76', '77', '78', '79', '80', '81', '82', '83', '84', '85',\n               '86', '87', '88', '89', '90'],\n              [157766400, 189302400, 220924800, 252460800, 283996800, 315532800,\n               347155200, 378691200, 410227200, 441763200, 473385600, 504921600,\n               536457600, 567993600, 599616000, 631152000]),\n             ('6 months',\n              ['75 Jan', 'Jul', '76 Jan', 'Jul', '77 Jan', 'Jul', '78 Jan',\n               'Jul', '79 Jan', 'Jul', '80 Jan', 'Jul', '81 Jan', 'Jul',\n               '82 Jan', 'Jul', '83 Jan', 'Jul', '84 Jan', 'Jul', '85 Jan',\n               'Jul', '86 Jan', 'Jul', '87 Jan', 'Jul', '88 Jan', 'Jul',\n               '89 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200, 283996800, 299635200, 315532800, 331257600,\n               347155200, 362793600, 378691200, 394329600, 410227200, 425865600,\n               441763200, 457488000, 473385600, 489024000, 504921600, 520560000,\n               536457600, 552096000, 567993600, 583718400, 599616000,\n               615254400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1978, 3, 1)),\n            [('2 years',\n              ['74', '76', '78', '80'],\n              [126230400, 189302400, 252460800, 315532800]),\n             ('1 year',\n              ['75', '76', '77', '78', '79'],\n              [157766400, 189302400, 220924800, 252460800, 283996800]),\n             ('6 months',\n              ['75 Jan', 'Jul',\n               '76 Jan', 'Jul',\n               '77 Jan', 'Jul',\n               '78 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200]),\n             ('3 months',\n              ['75 Apr', 'Jul', 'Oct',\n               '76 Jan', 'Apr', 'Jul', 'Oct',\n               '77 Jan', 'Apr', 'Jul', 'Oct',\n               '78 Jan', 'Apr'],\n              [165542400, 173404800, 181353600, 189302400, 197164800, 205027200,\n               212976000, 220924800, 228700800, 236563200, 244512000, 252460800,\n               260236800]),\n             ('2 months',\n              ['75 Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '76 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '77 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '78 Jan', 'Mar', 'May'],\n              [162864000, 168134400, 173404800, 178761600, 184032000, 189302400,\n               194486400, 199756800, 205027200, 210384000, 215654400, 220924800,\n               226022400, 231292800, 236563200, 241920000, 247190400, 252460800,\n               257558400, 262828800]),\n             ('1 month',\n              ['75 Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '76 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '77 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '78 Jan', 'Feb', 'Mar', 'Apr'],\n              [165542400, 168134400, 170812800, 173404800, 176083200, 178761600,\n               181353600, 184032000, 186624000, 189302400, 191980800, 194486400,\n               197164800, 199756800, 202435200, 205027200, 207705600, 210384000,\n               212976000, 215654400, 218246400, 220924800, 223603200, 226022400,\n               228700800, 231292800, 233971200, 236563200, 239241600, 241920000,\n               244512000, 247190400, 249782400, 252460800, 255139200, 257558400,\n               260236800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 2), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('2 weeks',\n              ['75 Dec 03', '17', '31', '76 Jan 14'],\n              [186796800, 188006400, 189216000, 190425600]),\n             ('1 week',\n              ['75 Dec 03', '10', '17', '24', '31',\n               '76 Jan 07'],\n              [186796800, 187401600, 188006400, 188611200, 189216000,\n               189820800]),\n             ('1 day',\n              ['75 Dec 02', '03', '04', '05', '06', '07', '08', '09', '10',\n               '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21',\n               '22', '23', '24', '25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [186710400, 186796800, 186883200, 186969600, 187056000, 187142400,\n               187228800, 187315200, 187401600, 187488000, 187574400, 187660800,\n               187747200, 187833600, 187920000, 188006400, 188092800, 188179200,\n               188265600, 188352000, 188438400, 188524800, 188611200, 188697600,\n               188784000, 188870400, 188956800, 189043200, 189129600, 189216000,\n               189302400, 189388800, 189475200, 189561600])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 25), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [188697600, 188784000, 188870400, 188956800, 189043200, 189129600,\n               189216000, 189302400, 189388800, 189475200, 189561600]),\n             ('12 hours',\n              ['75 Dec 25 00:00', '12:00',\n               '26 00:00', '12:00',\n               '27 00:00', '12:00',\n               '28 00:00', '12:00',\n               '29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [188697600, 188740800, 188784000, 188827200, 188870400, 188913600,\n               188956800, 189000000, 189043200, 189086400, 189129600, 189172800,\n               189216000, 189259200, 189302400, 189345600, 189388800, 189432000,\n               189475200, 189518400]),\n             ('6 hours',\n              ['75 Dec 25 00:00', '06:00', '12:00', '18:00',\n               '26 00:00', '06:00', '12:00', '18:00',\n               '27 00:00', '06:00', '12:00', '18:00',\n               '28 00:00', '06:00', '12:00', '18:00',\n               '29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [188697600, 188719200, 188740800, 188762400, 188784000, 188805600,\n               188827200, 188848800, 188870400, 188892000, 188913600, 188935200,\n               188956800, 188978400, 189000000, 189021600, 189043200, 189064800,\n               189086400, 189108000, 189129600, 189151200, 189172800, 189194400,\n               189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200, 189388800, 189410400, 189432000, 189453600,\n               189475200, 189496800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 29), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [189043200, 189129600, 189216000, 189302400, 189388800, 189475200,\n               189561600]),\n             ('12 hours',\n              ['75 Dec 29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [189043200, 189086400, 189129600, 189172800, 189216000, 189259200,\n               189302400, 189345600, 189388800, 189432000, 189475200,\n               189518400]),\n             ('6 hours',\n              ['75 Dec 29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [189043200, 189064800, 189086400, 189108000, 189129600, 189151200,\n               189172800, 189194400, 189216000, 189237600, 189259200, 189280800,\n               189302400, 189324000, 189345600, 189367200, 189388800, 189410400,\n               189432000, 189453600, 189475200, 189496800]),\n             ('3 hours',\n              ['75 Dec 29 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '30 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '02 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '03 00:00', '03:00'],\n              [189043200, 189054000, 189064800, 189075600, 189086400, 189097200,\n               189108000, 189118800, 189129600, 189140400, 189151200, 189162000,\n               189172800, 189183600, 189194400, 189205200, 189216000, 189226800,\n               189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200, 189324000, 189334800, 189345600, 189356400,\n               189367200, 189378000, 189388800, 189399600, 189410400, 189421200,\n               189432000, 189442800, 189453600, 189464400, 189475200,\n               189486000])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 0, 0, 0), (1976, 1, 1, 14, 30)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00'],\n              [189216000, 189259200, 189302400, 189345600, 189388800]),\n             ('6 hours',\n              ['75 Dec 31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00'],\n              [189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200]),\n             ('3 hours',\n              ['75 Dec 31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00'],\n              [189216000, 189226800, 189237600, 189248400, 189259200, 189270000,\n               189280800, 189291600, 189302400, 189313200, 189324000, 189334800,\n               189345600, 189356400]),\n             ('2 hours',\n              ['75 Dec 31 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00'],\n              [189216000, 189223200, 189230400, 189237600, 189244800, 189252000,\n               189259200, 189266400, 189273600, 189280800, 189288000, 189295200,\n               189302400, 189309600, 189316800, 189324000, 189331200, 189338400,\n               189345600, 189352800, 189360000]),\n             ('1 hour',\n              ['75 Dec 31 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00',\n               '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00'],\n              [189216000, 189219600, 189223200, 189226800, 189230400, 189234000,\n               189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000, 189309600, 189313200, 189316800, 189320400,\n               189324000, 189327600, 189331200, 189334800, 189338400, 189342000,\n               189345600, 189349200, 189352800, 189356400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 6), (1976, 1, 1)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00'],\n              [189216000, 189259200, 189302400, 189345600]),\n             ('6 hours',\n              ['75 Dec 31 06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00'],\n              [189237600, 189259200, 189280800, 189302400, 189324000]),\n             ('3 hours',\n              ['75 Dec 31 06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00'],\n              [189237600, 189244800, 189252000, 189259200, 189266400, 189273600,\n               189280800, 189288000, 189295200, 189302400, 189309600]),\n             ('1 hour',\n              ['75 Dec 31 06:00', '07:00', '08:00', '09:00', '10:00', '11:00',\n               '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00',\n               '19:00', '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00'],\n              [189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000]),\n             ('30 minutes',\n              ['Dec 31 06:00', '06:30', '07:00', '07:30', '08:00', '08:30',\n               '09:00', '09:30', '10:00', '10:30', '11:00', '11:30', '12:00',\n               '12:30', '13:00', '13:30', '14:00', '14:30', '15:00', '15:30',\n               '16:00', '16:30', '17:00', '17:30', '18:00', '18:30', '19:00',\n               '19:30', '20:00', '20:30', '21:00', '21:30', '22:00', '22:30',\n               '23:00', '23:30',\n               'Jan 01 00:00', '00:30'],\n              [189237600, 189239400, 189241200, 189243000, 189244800, 189246600,\n               189248400, 189250200, 189252000, 189253800, 189255600, 189257400,\n               189259200, 189261000, 189262800, 189264600, 189266400, 189268200,\n               189270000, 189271800, 189273600, 189275400, 189277200, 189279000,\n               189280800, 189282600, 189284400, 189286200, 189288000, 189289800,\n               189291600, 189293400, 189295200, 189297000, 189298800, 189300600,\n               189302400, 189304200])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 23), (1976, 1, 1, 2)),\n            [('3 hours',\n              ['75 Dec 31 21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189291600, 189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 22:00',\n               '76 Jan 01 00:00', '02:00', '04:00'],\n              [189295200, 189302400, 189309600, 189316800]),\n             ('1 hour',\n              ['75 Dec 31 23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00'],\n              [189298800, 189302400, 189306000, 189309600, 189313200]),\n             ('30 minutes',\n              ['Dec 31 23:00', '23:30',\n               'Jan 01 00:00', '00:30', '01:00', '01:30', '02:00', '02:30'],\n              [189298800, 189300600, 189302400, 189304200, 189306000, 189307800,\n               189309600, 189311400]),\n             ('15 minutes',\n              ['Dec 31 23:00', '23:15', '23:30', '23:45',\n               'Jan 01 00:00', '00:15', '00:30', '00:45', '01:00', '01:15',\n               '01:30', '01:45', '02:00', '02:15'],\n              [189298800, 189299700, 189300600, 189301500, 189302400, 189303300,\n               189304200, 189305100, 189306000, 189306900, 189307800, 189308700,\n               189309600, 189310500]),\n             ('10 minutes',\n              ['Dec 31 23:00', '23:10', '23:20', '23:30', '23:40', '23:50',\n               'Jan 01 00:00', '00:10', '00:20', '00:30', '00:40', '00:50',\n               '01:00', '01:10', '01:20', '01:30', '01:40', '01:50', '02:00',\n               '02:10'],\n              [189298800, 189299400, 189300000, 189300600, 189301200, 189301800,\n               189302400, 189303000, 189303600, 189304200, 189304800, 189305400,\n               189306000, 189306600, 189307200, 189307800, 189308400, 189309000,\n               189309600, 189310200]),\n             ('5 minutes',\n              ['Dec 31 23:00', '23:05', '23:10', '23:15', '23:20', '23:25',\n               '23:30', '23:35', '23:40', '23:45', '23:50', '23:55',\n               'Jan 01 00:00', '00:05', '00:10', '00:15', '00:20', '00:25',\n               '00:30', '00:35', '00:40', '00:45', '00:50', '00:55', '01:00',\n               '01:05', '01:10', '01:15', '01:20', '01:25', '01:30', '01:35',\n               '01:40', '01:45', '01:50', '01:55', '02:00', '02:05'],\n              [189298800, 189299100, 189299400, 189299700, 189300000, 189300300,\n               189300600, 189300900, 189301200, 189301500, 189301800, 189302100,\n               189302400, 189302700, 189303000, 189303300, 189303600, 189303900,\n               189304200, 189304500, 189304800, 189305100, 189305400, 189305700,\n               189306000, 189306300, 189306600, 189306900, 189307200, 189307500,\n               189307800, 189308100, 189308400, 189308700, 189309000, 189309300,\n               189309600, 189309900])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 23, 18)),\n            [('12 hours',\n              ['Jun 09 00:00', '12:00', '10 00:00'],\n              [-1437868800, -1437825600, -1437782400]),\n             ('6 hours',\n              ['Jun 09 06:00', '12:00', '18:00', '10 00:00'],\n              [-1437847200, -1437825600, -1437804000, -1437782400]),\n             ('3 hours',\n              ['Jun 09 09:00', '12:00', '15:00', '18:00', '21:00', '10 00:00'],\n              [-1437836400, -1437825600, -1437814800, -1437804000, -1437793200,\n               -1437782400]),\n             ('2 hours',\n              ['Jun 09 10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00', '10 00:00'],\n              [-1437832800, -1437825600, -1437818400, -1437811200, -1437804000,\n               -1437796800, -1437789600, -1437782400]),\n             ('1 hour',\n              ['Jun 09 10:00', '11:00', '12:00', '13:00', '14:00', '15:00',\n               '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00',\n               '23:00',\n               '10 00:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000, -1437818400,\n               -1437814800, -1437811200, -1437807600, -1437804000, -1437800400,\n               -1437796800, -1437793200, -1437789600, -1437786000,\n               -1437782400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30', '14:00', '14:30', '15:00', '15:30', '16:00', '16:30',\n               '17:00', '17:30', '18:00', '18:30', '19:00', '19:30', '20:00',\n               '20:30', '21:00', '21:30', '22:00', '22:30', '23:00', '23:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200, -1437818400, -1437816600,\n               -1437814800, -1437813000, -1437811200, -1437809400, -1437807600,\n               -1437805800, -1437804000, -1437802200, -1437800400, -1437798600,\n               -1437796800, -1437795000, -1437793200, -1437791400, -1437789600,\n               -1437787800, -1437786000, -1437784200])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 13, 18)),\n            [('2 hours',\n              ['10:00', '12:00', '14:00'],\n              [-1437832800, -1437825600, -1437818400]),\n             ('1 hour',\n              ['10:00', '11:00', '12:00', '13:00', '14:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000,\n               -1437818400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00', '11:15', '11:30',\n               '11:45', '12:00', '12:15', '12:30', '12:45', '13:00', '13:15',\n               '13:30'],\n              [-1437832800, -1437831900, -1437831000, -1437830100, -1437829200,\n               -1437828300, -1437827400, -1437826500, -1437825600, -1437824700,\n               -1437823800, -1437822900, -1437822000, -1437821100,\n               -1437820200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50', '11:00',\n               '11:10', '11:20', '11:30', '11:40', '11:50', '12:00', '12:10',\n               '12:20', '12:30', '12:40', '12:50', '13:00', '13:10', '13:20'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800, -1437829200, -1437828600, -1437828000, -1437827400,\n               -1437826800, -1437826200, -1437825600, -1437825000, -1437824400,\n               -1437823800, -1437823200, -1437822600, -1437822000, -1437821400,\n               -1437820800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50', '10:55', '11:00', '11:05',\n               '11:10', '11:15', '11:20', '11:25', '11:30', '11:35', '11:40',\n               '11:45', '11:50', '11:55', '12:00', '12:05', '12:10', '12:15',\n               '12:20', '12:25', '12:30', '12:35', '12:40', '12:45', '12:50',\n               '12:55', '13:00', '13:05', '13:10', '13:15', '13:20'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800, -1437829500, -1437829200, -1437828900, -1437828600,\n               -1437828300, -1437828000, -1437827700, -1437827400, -1437827100,\n               -1437826800, -1437826500, -1437826200, -1437825900, -1437825600,\n               -1437825300, -1437825000, -1437824700, -1437824400, -1437824100,\n               -1437823800, -1437823500, -1437823200, -1437822900, -1437822600,\n               -1437822300, -1437822000, -1437821700, -1437821400, -1437821100,\n               -1437820800])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 48)),\n            [('30 minutes',\n              ['10:00', '10:30', '11:00'],\n              [-1437832800, -1437831000, -1437829200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00'],\n              [-1437832800, -1437831900, -1437831000, -1437830100,\n               -1437829200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21', '10:22', '10:23', '10:24', '10:25', '10:26', '10:27',\n               '10:28', '10:29', '10:30', '10:31', '10:32', '10:33', '10:34',\n               '10:35', '10:36', '10:37', '10:38', '10:39', '10:40', '10:41',\n               '10:42', '10:43', '10:44', '10:45', '10:46', '10:47', '10:48',\n               '10:49'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540, -1437831480, -1437831420, -1437831360,\n               -1437831300, -1437831240, -1437831180, -1437831120, -1437831060,\n               -1437831000, -1437830940, -1437830880, -1437830820, -1437830760,\n               -1437830700, -1437830640, -1437830580, -1437830520, -1437830460,\n               -1437830400, -1437830340, -1437830280, -1437830220, -1437830160,\n               -1437830100, -1437830040, -1437829980, -1437829920, -1437829860]\n              )]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 20)),\n            [('15 minutes',\n              ['10:00', '10:15', '10:30'],\n              [-1437832800, -1437831900, -1437831000]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30'],\n              [-1437832800, -1437832200, -1437831600, -1437831000]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540]),\n             ('30 seconds',\n              ['10:00:00', '10:00:30', '10:01:00', '10:01:30', '10:02:00',\n               '10:02:30', '10:03:00', '10:03:30', '10:04:00', '10:04:30',\n               '10:05:00', '10:05:30', '10:06:00', '10:06:30', '10:07:00',\n               '10:07:30', '10:08:00', '10:08:30', '10:09:00', '10:09:30',\n               '10:10:00', '10:10:30', '10:11:00', '10:11:30', '10:12:00',\n               '10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30', '10:19:00', '10:19:30',\n               '10:20:00', '10:20:30'],\n              [-1437832800, -1437832770, -1437832740, -1437832710, -1437832680,\n               -1437832650, -1437832620, -1437832590, -1437832560, -1437832530,\n               -1437832500, -1437832470, -1437832440, -1437832410, -1437832380,\n               -1437832350, -1437832320, -1437832290, -1437832260, -1437832230,\n               -1437832200, -1437832170, -1437832140, -1437832110, -1437832080,\n               -1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690, -1437831660, -1437831630,\n               -1437831600, -1437831570])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 18, 12)),\n            [('5 minutes',\n              ['10:10', '10:15', '10:20'],\n              [-1437832200, -1437831900, -1437831600]),\n             ('1 minute',\n              ['10:12', '10:13', '10:14', '10:15', '10:16', '10:17', '10:18',\n               '10:19'],\n              [-1437832080, -1437832020, -1437831960, -1437831900, -1437831840,\n               -1437831780, -1437831720, -1437831660]),\n             ('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30'],\n              [-1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15', '10:13:30',\n               '10:13:45', '10:14:00', '10:14:15', '10:14:30', '10:14:45',\n               '10:15:00', '10:15:15', '10:15:30', '10:15:45', '10:16:00',\n               '10:16:15', '10:16:30', '10:16:45', '10:17:00', '10:17:15',\n               '10:17:30', '10:17:45', '10:18:00', '10:18:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005, -1437831990,\n               -1437831975, -1437831960, -1437831945, -1437831930, -1437831915,\n               -1437831900, -1437831885, -1437831870, -1437831855, -1437831840,\n               -1437831825, -1437831810, -1437831795, -1437831780, -1437831765,\n               -1437831750, -1437831735, -1437831720, -1437831705]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20', '10:13:30', '10:13:40', '10:13:50', '10:14:00',\n               '10:14:10', '10:14:20', '10:14:30', '10:14:40', '10:14:50',\n               '10:15:00', '10:15:10', '10:15:20', '10:15:30', '10:15:40',\n               '10:15:50', '10:16:00', '10:16:10', '10:16:20', '10:16:30',\n               '10:16:40', '10:16:50', '10:17:00', '10:17:10', '10:17:20',\n               '10:17:30', '10:17:40', '10:17:50', '10:18:00', '10:18:10',\n               '10:18:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000, -1437831990, -1437831980, -1437831970, -1437831960,\n               -1437831950, -1437831940, -1437831930, -1437831920, -1437831910,\n               -1437831900, -1437831890, -1437831880, -1437831870, -1437831860,\n               -1437831850, -1437831840, -1437831830, -1437831820, -1437831810,\n               -1437831800, -1437831790, -1437831780, -1437831770, -1437831760,\n               -1437831750, -1437831740, -1437831730, -1437831720, -1437831710,\n               -1437831700])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 13, 12)),\n            [('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30'],\n              [-1437832050, -1437832020, -1437831990]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000]),\n             ('5 seconds',\n              ['10:12:30', '10:12:35', '10:12:40', '10:12:45', '10:12:50',\n               '10:12:55', '10:13:00', '10:13:05', '10:13:10', '10:13:15'],\n              [-1437832050, -1437832045, -1437832040, -1437832035, -1437832030,\n               -1437832025, -1437832020, -1437832015, -1437832010,\n               -1437832005]),\n             ('1 second',\n              ['10:12:33', '10:12:34', '10:12:35', '10:12:36', '10:12:37',\n               '10:12:38', '10:12:39', '10:12:40', '10:12:41', '10:12:42',\n               '10:12:43', '10:12:44', '10:12:45', '10:12:46', '10:12:47',\n               '10:12:48', '10:12:49', '10:12:50', '10:12:51', '10:12:52',\n               '10:12:53', '10:12:54', '10:12:55', '10:12:56', '10:12:57',\n               '10:12:58', '10:12:59', '10:13:00', '10:13:01', '10:13:02',\n               '10:13:03', '10:13:04', '10:13:05', '10:13:06', '10:13:07',\n               '10:13:08', '10:13:09', '10:13:10', '10:13:11', '10:13:12',\n               '10:13:13'],\n              [-1437832047, -1437832046, -1437832045, -1437832044, -1437832043,\n               -1437832042, -1437832041, -1437832040, -1437832039, -1437832038,\n               -1437832037, -1437832036, -1437832035, -1437832034, -1437832033,\n               -1437832032, -1437832031, -1437832030, -1437832029, -1437832028,\n               -1437832027, -1437832026, -1437832025, -1437832024, -1437832023,\n               -1437832022, -1437832021, -1437832020, -1437832019, -1437832018,\n               -1437832017, -1437832016, -1437832015, -1437832014, -1437832013,\n               -1437832012, -1437832011, -1437832010, -1437832009, -1437832008,\n               -1437832007])])\n\n    def test_min_unique(self):\n        bins = time_binnings(self.dates, min_unique=7)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_add_unique(self):\n        bins = time_binnings(self.dates, add_unique=7)\n        self.assertNotEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_limits(self):\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=17)},\n            {9, 17})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=16)},\n            {9})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=10, max_bins=17)},\n            {17})\n\n    def test_single_value(self):\n        dates = np.array([42])\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_no_values(self):\n        dates = np.array([])\n        self.assertRaises(ValueError, time_binnings, dates)\n\n        dates = np.array([np.nan, np.nan])\n        self.assertRaises(ValueError, time_binnings, dates)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 16,
                                "end_lineno": 664,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "Orange/preprocess/tests/test_discretize.py",
                            "type": "class",
                            "name": "TestTimeBinning",
                            "content": "class TestTimeBinning(unittest.TestCase):\n    def setUp(self):\n        self.dates = [mktime(x) for x in\n            [(1975, 6, 9, 10, 0, 0, 0, 161, 0),\n             (1975, 6, 9, 10, 50, 0, 0, 161, 0),\n             (1975, 6, 9, 11, 40, 0, 0, 161, 0),\n             (1975, 6, 9, 12, 30, 0, 0, 161, 0),\n             (1975, 6, 9, 13, 20, 0, 0, 161, 0),\n             (1975, 6, 9, 14, 10, 0, 0, 161, 0)]]\n\n    def test_binning(self):\n        def testbin(start, end):\n            bins = _time_binnings(create(*start), create(*end), 3, 51)\n            return [(bin.width_label, bin.short_labels, bin.thresholds)\n                    for bin in reversed(bins)]\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1989, 3, 1)),\n            [('10 years',\n              ['70', '80', '90'],\n              [0, 315532800, 631152000]),\n             ('5 years',\n              ['75', '80', '85', '90'],\n              [157766400, 315532800, 473385600, 631152000]),\n             ('2 years',\n              ['74', '76', '78', '80', '82', '84', '86', '88', '90'],\n              [126230400, 189302400, 252460800, 315532800, 378691200, 441763200,\n               504921600, 567993600, 631152000]),\n             ('1 year',\n              ['75', '76', '77', '78', '79', '80', '81', '82', '83', '84', '85',\n               '86', '87', '88', '89', '90'],\n              [157766400, 189302400, 220924800, 252460800, 283996800, 315532800,\n               347155200, 378691200, 410227200, 441763200, 473385600, 504921600,\n               536457600, 567993600, 599616000, 631152000]),\n             ('6 months',\n              ['75 Jan', 'Jul', '76 Jan', 'Jul', '77 Jan', 'Jul', '78 Jan',\n               'Jul', '79 Jan', 'Jul', '80 Jan', 'Jul', '81 Jan', 'Jul',\n               '82 Jan', 'Jul', '83 Jan', 'Jul', '84 Jan', 'Jul', '85 Jan',\n               'Jul', '86 Jan', 'Jul', '87 Jan', 'Jul', '88 Jan', 'Jul',\n               '89 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200, 283996800, 299635200, 315532800, 331257600,\n               347155200, 362793600, 378691200, 394329600, 410227200, 425865600,\n               441763200, 457488000, 473385600, 489024000, 504921600, 520560000,\n               536457600, 552096000, 567993600, 583718400, 599616000,\n               615254400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1978, 3, 1)),\n            [('2 years',\n              ['74', '76', '78', '80'],\n              [126230400, 189302400, 252460800, 315532800]),\n             ('1 year',\n              ['75', '76', '77', '78', '79'],\n              [157766400, 189302400, 220924800, 252460800, 283996800]),\n             ('6 months',\n              ['75 Jan', 'Jul',\n               '76 Jan', 'Jul',\n               '77 Jan', 'Jul',\n               '78 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200]),\n             ('3 months',\n              ['75 Apr', 'Jul', 'Oct',\n               '76 Jan', 'Apr', 'Jul', 'Oct',\n               '77 Jan', 'Apr', 'Jul', 'Oct',\n               '78 Jan', 'Apr'],\n              [165542400, 173404800, 181353600, 189302400, 197164800, 205027200,\n               212976000, 220924800, 228700800, 236563200, 244512000, 252460800,\n               260236800]),\n             ('2 months',\n              ['75 Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '76 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '77 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '78 Jan', 'Mar', 'May'],\n              [162864000, 168134400, 173404800, 178761600, 184032000, 189302400,\n               194486400, 199756800, 205027200, 210384000, 215654400, 220924800,\n               226022400, 231292800, 236563200, 241920000, 247190400, 252460800,\n               257558400, 262828800]),\n             ('1 month',\n              ['75 Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '76 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '77 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '78 Jan', 'Feb', 'Mar', 'Apr'],\n              [165542400, 168134400, 170812800, 173404800, 176083200, 178761600,\n               181353600, 184032000, 186624000, 189302400, 191980800, 194486400,\n               197164800, 199756800, 202435200, 205027200, 207705600, 210384000,\n               212976000, 215654400, 218246400, 220924800, 223603200, 226022400,\n               228700800, 231292800, 233971200, 236563200, 239241600, 241920000,\n               244512000, 247190400, 249782400, 252460800, 255139200, 257558400,\n               260236800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 2), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('2 weeks',\n              ['75 Dec 03', '17', '31', '76 Jan 14'],\n              [186796800, 188006400, 189216000, 190425600]),\n             ('1 week',\n              ['75 Dec 03', '10', '17', '24', '31',\n               '76 Jan 07'],\n              [186796800, 187401600, 188006400, 188611200, 189216000,\n               189820800]),\n             ('1 day',\n              ['75 Dec 02', '03', '04', '05', '06', '07', '08', '09', '10',\n               '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21',\n               '22', '23', '24', '25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [186710400, 186796800, 186883200, 186969600, 187056000, 187142400,\n               187228800, 187315200, 187401600, 187488000, 187574400, 187660800,\n               187747200, 187833600, 187920000, 188006400, 188092800, 188179200,\n               188265600, 188352000, 188438400, 188524800, 188611200, 188697600,\n               188784000, 188870400, 188956800, 189043200, 189129600, 189216000,\n               189302400, 189388800, 189475200, 189561600])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 25), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [188697600, 188784000, 188870400, 188956800, 189043200, 189129600,\n               189216000, 189302400, 189388800, 189475200, 189561600]),\n             ('12 hours',\n              ['75 Dec 25 00:00', '12:00',\n               '26 00:00', '12:00',\n               '27 00:00', '12:00',\n               '28 00:00', '12:00',\n               '29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [188697600, 188740800, 188784000, 188827200, 188870400, 188913600,\n               188956800, 189000000, 189043200, 189086400, 189129600, 189172800,\n               189216000, 189259200, 189302400, 189345600, 189388800, 189432000,\n               189475200, 189518400]),\n             ('6 hours',\n              ['75 Dec 25 00:00', '06:00', '12:00', '18:00',\n               '26 00:00', '06:00', '12:00', '18:00',\n               '27 00:00', '06:00', '12:00', '18:00',\n               '28 00:00', '06:00', '12:00', '18:00',\n               '29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [188697600, 188719200, 188740800, 188762400, 188784000, 188805600,\n               188827200, 188848800, 188870400, 188892000, 188913600, 188935200,\n               188956800, 188978400, 189000000, 189021600, 189043200, 189064800,\n               189086400, 189108000, 189129600, 189151200, 189172800, 189194400,\n               189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200, 189388800, 189410400, 189432000, 189453600,\n               189475200, 189496800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 29), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [189043200, 189129600, 189216000, 189302400, 189388800, 189475200,\n               189561600]),\n             ('12 hours',\n              ['75 Dec 29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [189043200, 189086400, 189129600, 189172800, 189216000, 189259200,\n               189302400, 189345600, 189388800, 189432000, 189475200,\n               189518400]),\n             ('6 hours',\n              ['75 Dec 29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [189043200, 189064800, 189086400, 189108000, 189129600, 189151200,\n               189172800, 189194400, 189216000, 189237600, 189259200, 189280800,\n               189302400, 189324000, 189345600, 189367200, 189388800, 189410400,\n               189432000, 189453600, 189475200, 189496800]),\n             ('3 hours',\n              ['75 Dec 29 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '30 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '02 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '03 00:00', '03:00'],\n              [189043200, 189054000, 189064800, 189075600, 189086400, 189097200,\n               189108000, 189118800, 189129600, 189140400, 189151200, 189162000,\n               189172800, 189183600, 189194400, 189205200, 189216000, 189226800,\n               189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200, 189324000, 189334800, 189345600, 189356400,\n               189367200, 189378000, 189388800, 189399600, 189410400, 189421200,\n               189432000, 189442800, 189453600, 189464400, 189475200,\n               189486000])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 0, 0, 0), (1976, 1, 1, 14, 30)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00'],\n              [189216000, 189259200, 189302400, 189345600, 189388800]),\n             ('6 hours',\n              ['75 Dec 31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00'],\n              [189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200]),\n             ('3 hours',\n              ['75 Dec 31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00'],\n              [189216000, 189226800, 189237600, 189248400, 189259200, 189270000,\n               189280800, 189291600, 189302400, 189313200, 189324000, 189334800,\n               189345600, 189356400]),\n             ('2 hours',\n              ['75 Dec 31 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00'],\n              [189216000, 189223200, 189230400, 189237600, 189244800, 189252000,\n               189259200, 189266400, 189273600, 189280800, 189288000, 189295200,\n               189302400, 189309600, 189316800, 189324000, 189331200, 189338400,\n               189345600, 189352800, 189360000]),\n             ('1 hour',\n              ['75 Dec 31 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00',\n               '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00'],\n              [189216000, 189219600, 189223200, 189226800, 189230400, 189234000,\n               189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000, 189309600, 189313200, 189316800, 189320400,\n               189324000, 189327600, 189331200, 189334800, 189338400, 189342000,\n               189345600, 189349200, 189352800, 189356400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 6), (1976, 1, 1)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00'],\n              [189216000, 189259200, 189302400, 189345600]),\n             ('6 hours',\n              ['75 Dec 31 06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00'],\n              [189237600, 189259200, 189280800, 189302400, 189324000]),\n             ('3 hours',\n              ['75 Dec 31 06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00'],\n              [189237600, 189244800, 189252000, 189259200, 189266400, 189273600,\n               189280800, 189288000, 189295200, 189302400, 189309600]),\n             ('1 hour',\n              ['75 Dec 31 06:00', '07:00', '08:00', '09:00', '10:00', '11:00',\n               '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00',\n               '19:00', '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00'],\n              [189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000]),\n             ('30 minutes',\n              ['Dec 31 06:00', '06:30', '07:00', '07:30', '08:00', '08:30',\n               '09:00', '09:30', '10:00', '10:30', '11:00', '11:30', '12:00',\n               '12:30', '13:00', '13:30', '14:00', '14:30', '15:00', '15:30',\n               '16:00', '16:30', '17:00', '17:30', '18:00', '18:30', '19:00',\n               '19:30', '20:00', '20:30', '21:00', '21:30', '22:00', '22:30',\n               '23:00', '23:30',\n               'Jan 01 00:00', '00:30'],\n              [189237600, 189239400, 189241200, 189243000, 189244800, 189246600,\n               189248400, 189250200, 189252000, 189253800, 189255600, 189257400,\n               189259200, 189261000, 189262800, 189264600, 189266400, 189268200,\n               189270000, 189271800, 189273600, 189275400, 189277200, 189279000,\n               189280800, 189282600, 189284400, 189286200, 189288000, 189289800,\n               189291600, 189293400, 189295200, 189297000, 189298800, 189300600,\n               189302400, 189304200])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 23), (1976, 1, 1, 2)),\n            [('3 hours',\n              ['75 Dec 31 21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189291600, 189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 22:00',\n               '76 Jan 01 00:00', '02:00', '04:00'],\n              [189295200, 189302400, 189309600, 189316800]),\n             ('1 hour',\n              ['75 Dec 31 23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00'],\n              [189298800, 189302400, 189306000, 189309600, 189313200]),\n             ('30 minutes',\n              ['Dec 31 23:00', '23:30',\n               'Jan 01 00:00', '00:30', '01:00', '01:30', '02:00', '02:30'],\n              [189298800, 189300600, 189302400, 189304200, 189306000, 189307800,\n               189309600, 189311400]),\n             ('15 minutes',\n              ['Dec 31 23:00', '23:15', '23:30', '23:45',\n               'Jan 01 00:00', '00:15', '00:30', '00:45', '01:00', '01:15',\n               '01:30', '01:45', '02:00', '02:15'],\n              [189298800, 189299700, 189300600, 189301500, 189302400, 189303300,\n               189304200, 189305100, 189306000, 189306900, 189307800, 189308700,\n               189309600, 189310500]),\n             ('10 minutes',\n              ['Dec 31 23:00', '23:10', '23:20', '23:30', '23:40', '23:50',\n               'Jan 01 00:00', '00:10', '00:20', '00:30', '00:40', '00:50',\n               '01:00', '01:10', '01:20', '01:30', '01:40', '01:50', '02:00',\n               '02:10'],\n              [189298800, 189299400, 189300000, 189300600, 189301200, 189301800,\n               189302400, 189303000, 189303600, 189304200, 189304800, 189305400,\n               189306000, 189306600, 189307200, 189307800, 189308400, 189309000,\n               189309600, 189310200]),\n             ('5 minutes',\n              ['Dec 31 23:00', '23:05', '23:10', '23:15', '23:20', '23:25',\n               '23:30', '23:35', '23:40', '23:45', '23:50', '23:55',\n               'Jan 01 00:00', '00:05', '00:10', '00:15', '00:20', '00:25',\n               '00:30', '00:35', '00:40', '00:45', '00:50', '00:55', '01:00',\n               '01:05', '01:10', '01:15', '01:20', '01:25', '01:30', '01:35',\n               '01:40', '01:45', '01:50', '01:55', '02:00', '02:05'],\n              [189298800, 189299100, 189299400, 189299700, 189300000, 189300300,\n               189300600, 189300900, 189301200, 189301500, 189301800, 189302100,\n               189302400, 189302700, 189303000, 189303300, 189303600, 189303900,\n               189304200, 189304500, 189304800, 189305100, 189305400, 189305700,\n               189306000, 189306300, 189306600, 189306900, 189307200, 189307500,\n               189307800, 189308100, 189308400, 189308700, 189309000, 189309300,\n               189309600, 189309900])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 23, 18)),\n            [('12 hours',\n              ['Jun 09 00:00', '12:00', '10 00:00'],\n              [-1437868800, -1437825600, -1437782400]),\n             ('6 hours',\n              ['Jun 09 06:00', '12:00', '18:00', '10 00:00'],\n              [-1437847200, -1437825600, -1437804000, -1437782400]),\n             ('3 hours',\n              ['Jun 09 09:00', '12:00', '15:00', '18:00', '21:00', '10 00:00'],\n              [-1437836400, -1437825600, -1437814800, -1437804000, -1437793200,\n               -1437782400]),\n             ('2 hours',\n              ['Jun 09 10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00', '10 00:00'],\n              [-1437832800, -1437825600, -1437818400, -1437811200, -1437804000,\n               -1437796800, -1437789600, -1437782400]),\n             ('1 hour',\n              ['Jun 09 10:00', '11:00', '12:00', '13:00', '14:00', '15:00',\n               '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00',\n               '23:00',\n               '10 00:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000, -1437818400,\n               -1437814800, -1437811200, -1437807600, -1437804000, -1437800400,\n               -1437796800, -1437793200, -1437789600, -1437786000,\n               -1437782400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30', '14:00', '14:30', '15:00', '15:30', '16:00', '16:30',\n               '17:00', '17:30', '18:00', '18:30', '19:00', '19:30', '20:00',\n               '20:30', '21:00', '21:30', '22:00', '22:30', '23:00', '23:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200, -1437818400, -1437816600,\n               -1437814800, -1437813000, -1437811200, -1437809400, -1437807600,\n               -1437805800, -1437804000, -1437802200, -1437800400, -1437798600,\n               -1437796800, -1437795000, -1437793200, -1437791400, -1437789600,\n               -1437787800, -1437786000, -1437784200])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 13, 18)),\n            [('2 hours',\n              ['10:00', '12:00', '14:00'],\n              [-1437832800, -1437825600, -1437818400]),\n             ('1 hour',\n              ['10:00', '11:00', '12:00', '13:00', '14:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000,\n               -1437818400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00', '11:15', '11:30',\n               '11:45', '12:00', '12:15', '12:30', '12:45', '13:00', '13:15',\n               '13:30'],\n              [-1437832800, -1437831900, -1437831000, -1437830100, -1437829200,\n               -1437828300, -1437827400, -1437826500, -1437825600, -1437824700,\n               -1437823800, -1437822900, -1437822000, -1437821100,\n               -1437820200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50', '11:00',\n               '11:10', '11:20', '11:30', '11:40', '11:50', '12:00', '12:10',\n               '12:20', '12:30', '12:40', '12:50', '13:00', '13:10', '13:20'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800, -1437829200, -1437828600, -1437828000, -1437827400,\n               -1437826800, -1437826200, -1437825600, -1437825000, -1437824400,\n               -1437823800, -1437823200, -1437822600, -1437822000, -1437821400,\n               -1437820800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50', '10:55', '11:00', '11:05',\n               '11:10', '11:15', '11:20', '11:25', '11:30', '11:35', '11:40',\n               '11:45', '11:50', '11:55', '12:00', '12:05', '12:10', '12:15',\n               '12:20', '12:25', '12:30', '12:35', '12:40', '12:45', '12:50',\n               '12:55', '13:00', '13:05', '13:10', '13:15', '13:20'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800, -1437829500, -1437829200, -1437828900, -1437828600,\n               -1437828300, -1437828000, -1437827700, -1437827400, -1437827100,\n               -1437826800, -1437826500, -1437826200, -1437825900, -1437825600,\n               -1437825300, -1437825000, -1437824700, -1437824400, -1437824100,\n               -1437823800, -1437823500, -1437823200, -1437822900, -1437822600,\n               -1437822300, -1437822000, -1437821700, -1437821400, -1437821100,\n               -1437820800])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 48)),\n            [('30 minutes',\n              ['10:00', '10:30', '11:00'],\n              [-1437832800, -1437831000, -1437829200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00'],\n              [-1437832800, -1437831900, -1437831000, -1437830100,\n               -1437829200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21', '10:22', '10:23', '10:24', '10:25', '10:26', '10:27',\n               '10:28', '10:29', '10:30', '10:31', '10:32', '10:33', '10:34',\n               '10:35', '10:36', '10:37', '10:38', '10:39', '10:40', '10:41',\n               '10:42', '10:43', '10:44', '10:45', '10:46', '10:47', '10:48',\n               '10:49'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540, -1437831480, -1437831420, -1437831360,\n               -1437831300, -1437831240, -1437831180, -1437831120, -1437831060,\n               -1437831000, -1437830940, -1437830880, -1437830820, -1437830760,\n               -1437830700, -1437830640, -1437830580, -1437830520, -1437830460,\n               -1437830400, -1437830340, -1437830280, -1437830220, -1437830160,\n               -1437830100, -1437830040, -1437829980, -1437829920, -1437829860]\n              )]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 20)),\n            [('15 minutes',\n              ['10:00', '10:15', '10:30'],\n              [-1437832800, -1437831900, -1437831000]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30'],\n              [-1437832800, -1437832200, -1437831600, -1437831000]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540]),\n             ('30 seconds',\n              ['10:00:00', '10:00:30', '10:01:00', '10:01:30', '10:02:00',\n               '10:02:30', '10:03:00', '10:03:30', '10:04:00', '10:04:30',\n               '10:05:00', '10:05:30', '10:06:00', '10:06:30', '10:07:00',\n               '10:07:30', '10:08:00', '10:08:30', '10:09:00', '10:09:30',\n               '10:10:00', '10:10:30', '10:11:00', '10:11:30', '10:12:00',\n               '10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30', '10:19:00', '10:19:30',\n               '10:20:00', '10:20:30'],\n              [-1437832800, -1437832770, -1437832740, -1437832710, -1437832680,\n               -1437832650, -1437832620, -1437832590, -1437832560, -1437832530,\n               -1437832500, -1437832470, -1437832440, -1437832410, -1437832380,\n               -1437832350, -1437832320, -1437832290, -1437832260, -1437832230,\n               -1437832200, -1437832170, -1437832140, -1437832110, -1437832080,\n               -1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690, -1437831660, -1437831630,\n               -1437831600, -1437831570])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 18, 12)),\n            [('5 minutes',\n              ['10:10', '10:15', '10:20'],\n              [-1437832200, -1437831900, -1437831600]),\n             ('1 minute',\n              ['10:12', '10:13', '10:14', '10:15', '10:16', '10:17', '10:18',\n               '10:19'],\n              [-1437832080, -1437832020, -1437831960, -1437831900, -1437831840,\n               -1437831780, -1437831720, -1437831660]),\n             ('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30'],\n              [-1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15', '10:13:30',\n               '10:13:45', '10:14:00', '10:14:15', '10:14:30', '10:14:45',\n               '10:15:00', '10:15:15', '10:15:30', '10:15:45', '10:16:00',\n               '10:16:15', '10:16:30', '10:16:45', '10:17:00', '10:17:15',\n               '10:17:30', '10:17:45', '10:18:00', '10:18:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005, -1437831990,\n               -1437831975, -1437831960, -1437831945, -1437831930, -1437831915,\n               -1437831900, -1437831885, -1437831870, -1437831855, -1437831840,\n               -1437831825, -1437831810, -1437831795, -1437831780, -1437831765,\n               -1437831750, -1437831735, -1437831720, -1437831705]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20', '10:13:30', '10:13:40', '10:13:50', '10:14:00',\n               '10:14:10', '10:14:20', '10:14:30', '10:14:40', '10:14:50',\n               '10:15:00', '10:15:10', '10:15:20', '10:15:30', '10:15:40',\n               '10:15:50', '10:16:00', '10:16:10', '10:16:20', '10:16:30',\n               '10:16:40', '10:16:50', '10:17:00', '10:17:10', '10:17:20',\n               '10:17:30', '10:17:40', '10:17:50', '10:18:00', '10:18:10',\n               '10:18:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000, -1437831990, -1437831980, -1437831970, -1437831960,\n               -1437831950, -1437831940, -1437831930, -1437831920, -1437831910,\n               -1437831900, -1437831890, -1437831880, -1437831870, -1437831860,\n               -1437831850, -1437831840, -1437831830, -1437831820, -1437831810,\n               -1437831800, -1437831790, -1437831780, -1437831770, -1437831760,\n               -1437831750, -1437831740, -1437831730, -1437831720, -1437831710,\n               -1437831700])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 13, 12)),\n            [('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30'],\n              [-1437832050, -1437832020, -1437831990]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000]),\n             ('5 seconds',\n              ['10:12:30', '10:12:35', '10:12:40', '10:12:45', '10:12:50',\n               '10:12:55', '10:13:00', '10:13:05', '10:13:10', '10:13:15'],\n              [-1437832050, -1437832045, -1437832040, -1437832035, -1437832030,\n               -1437832025, -1437832020, -1437832015, -1437832010,\n               -1437832005]),\n             ('1 second',\n              ['10:12:33', '10:12:34', '10:12:35', '10:12:36', '10:12:37',\n               '10:12:38', '10:12:39', '10:12:40', '10:12:41', '10:12:42',\n               '10:12:43', '10:12:44', '10:12:45', '10:12:46', '10:12:47',\n               '10:12:48', '10:12:49', '10:12:50', '10:12:51', '10:12:52',\n               '10:12:53', '10:12:54', '10:12:55', '10:12:56', '10:12:57',\n               '10:12:58', '10:12:59', '10:13:00', '10:13:01', '10:13:02',\n               '10:13:03', '10:13:04', '10:13:05', '10:13:06', '10:13:07',\n               '10:13:08', '10:13:09', '10:13:10', '10:13:11', '10:13:12',\n               '10:13:13'],\n              [-1437832047, -1437832046, -1437832045, -1437832044, -1437832043,\n               -1437832042, -1437832041, -1437832040, -1437832039, -1437832038,\n               -1437832037, -1437832036, -1437832035, -1437832034, -1437832033,\n               -1437832032, -1437832031, -1437832030, -1437832029, -1437832028,\n               -1437832027, -1437832026, -1437832025, -1437832024, -1437832023,\n               -1437832022, -1437832021, -1437832020, -1437832019, -1437832018,\n               -1437832017, -1437832016, -1437832015, -1437832014, -1437832013,\n               -1437832012, -1437832011, -1437832010, -1437832009, -1437832008,\n               -1437832007])])\n\n    def test_min_unique(self):\n        bins = time_binnings(self.dates, min_unique=7)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_add_unique(self):\n        bins = time_binnings(self.dates, add_unique=7)\n        self.assertNotEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_limits(self):\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=17)},\n            {9, 17})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=16)},\n            {9})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=10, max_bins=17)},\n            {17})\n\n    def test_single_value(self):\n        dates = np.array([42])\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_no_values(self):\n        dates = np.array([])\n        self.assertRaises(ValueError, time_binnings, dates)\n\n        dates = np.array([np.nan, np.nan])\n        self.assertRaises(ValueError, time_binnings, dates)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 16,
                            "end_lineno": 664,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 626,
                            "length": 6
                        },
                        "new_range": {
                            "start": 627,
                            "length": 50
                        },
                        "section": "class TestTimeBinning(unittest.TestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "               -1437832012, -1437832011, -1437832010, -1437832009, -1437832008,",
                                "type": "context"
                            },
                            {
                                "content": "               -1437832007])])",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertEqual(",
                                "type": "added"
                            },
                            {
                                "content": "            testbin((1973, 9, 14), (2010, 9, 8)),",
                                "type": "added"
                            },
                            {
                                "content": "            [",
                                "type": "added"
                            },
                            {
                                "content": "                ('50 years',",
                                "type": "added"
                            },
                            {
                                "content": "                 ['1950', '2000', '2050'],",
                                "type": "added"
                            },
                            {
                                "content": "                 [-631152000, 946684800, 2524608000]),",
                                "type": "added"
                            },
                            {
                                "content": "                ('25 years',",
                                "type": "added"
                            },
                            {
                                "content": "                 ['1950', '1975', '2000', '2025'],",
                                "type": "added"
                            },
                            {
                                "content": "                 [-631152000, 157766400, 946684800, 1735689600]),",
                                "type": "added"
                            },
                            {
                                "content": "                ('10 years',",
                                "type": "added"
                            },
                            {
                                "content": "                 ['1970', '1980', '1990', '2000', '2010', '2020'],",
                                "type": "added"
                            },
                            {
                                "content": "                 [0, 315532800, 631152000, 946684800, 1262304000, 1577836800]),",
                                "type": "added"
                            },
                            {
                                "content": "                ('5 years',",
                                "type": "added"
                            },
                            {
                                "content": "                 ['1970', '1975', '1980', '1985', '1990', '1995', '2000',",
                                "type": "added"
                            },
                            {
                                "content": "                  '2005', '2010', '2015'],",
                                "type": "added"
                            },
                            {
                                "content": "                 [0, 157766400, 315532800, 473385600, 631152000, 788918400,",
                                "type": "added"
                            },
                            {
                                "content": "                  946684800, 1104537600, 1262304000, 1420070400]),",
                                "type": "added"
                            },
                            {
                                "content": "                ('2 years',",
                                "type": "added"
                            },
                            {
                                "content": "                 ['1972', '1974', '1976', '1978', '1980', '1982', '1984',",
                                "type": "added"
                            },
                            {
                                "content": "                  '1986', '1988', '1990', '1992', '1994', '1996', '1998',",
                                "type": "added"
                            },
                            {
                                "content": "                  '2000', '2002', '2004', '2006', '2008', '2010', '2012'],",
                                "type": "added"
                            },
                            {
                                "content": "                 [63072000, 126230400, 189302400, 252460800, 315532800,",
                                "type": "added"
                            },
                            {
                                "content": "                  378691200, 441763200, 504921600, 567993600, 631152000,",
                                "type": "added"
                            },
                            {
                                "content": "                  694224000, 757382400, 820454400, 883612800, 946684800,",
                                "type": "added"
                            },
                            {
                                "content": "                  1009843200, 1072915200, 1136073600, 1199145600, 1262304000,",
                                "type": "added"
                            },
                            {
                                "content": "                  1325376000]),",
                                "type": "added"
                            },
                            {
                                "content": "                ('1 year',",
                                "type": "added"
                            },
                            {
                                "content": "                 ['1973', '1974', '1975', '1976', '1977', '1978', '1979',",
                                "type": "added"
                            },
                            {
                                "content": "                  '1980', '1981', '1982', '1983', '1984', '1985', '1986',",
                                "type": "added"
                            },
                            {
                                "content": "                  '1987', '1988', '1989', '1990', '1991', '1992', '1993',",
                                "type": "added"
                            },
                            {
                                "content": "                  '1994', '1995', '1996', '1997', '1998', '1999', '2000',",
                                "type": "added"
                            },
                            {
                                "content": "                  '2001', '2002', '2003', '2004', '2005', '2006', '2007',",
                                "type": "added"
                            },
                            {
                                "content": "                  '2008', '2009', '2010', '2011'],",
                                "type": "added"
                            },
                            {
                                "content": "                 [94694400, 126230400, 157766400, 189302400, 220924800,",
                                "type": "added"
                            },
                            {
                                "content": "                  252460800, 283996800, 315532800, 347155200, 378691200,",
                                "type": "added"
                            },
                            {
                                "content": "                  410227200, 441763200, 473385600, 504921600, 536457600,",
                                "type": "added"
                            },
                            {
                                "content": "                  567993600, 599616000, 631152000, 662688000, 694224000,",
                                "type": "added"
                            },
                            {
                                "content": "                  725846400, 757382400, 788918400, 820454400, 852076800,",
                                "type": "added"
                            },
                            {
                                "content": "                  883612800, 915148800, 946684800, 978307200, 1009843200,",
                                "type": "added"
                            },
                            {
                                "content": "                  1041379200, 1072915200, 1104537600, 1136073600, 1167609600,",
                                "type": "added"
                            },
                            {
                                "content": "                  1199145600, 1230768000, 1262304000, 1293840000])",
                                "type": "added"
                            },
                            {
                                "content": "            ]",
                                "type": "added"
                            },
                            {
                                "content": "        )",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    def test_min_unique(self):",
                                "type": "context"
                            },
                            {
                                "content": "        bins = time_binnings(self.dates, min_unique=7)",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertEqual(len(bins), 1)",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/preprocess/tests/test_discretize.py",
                            "type": "method",
                            "name": "TestTimeBinning.test_binning",
                            "content": "class TestTimeBinning(unittest.TestCase):\n    def setUp(self):\n        self.dates = [mktime(x) for x in\n            [(1975, 6, 9, 10, 0, 0, 0, 161, 0),\n             (1975, 6, 9, 10, 50, 0, 0, 161, 0),\n             (1975, 6, 9, 11, 40, 0, 0, 161, 0),\n             (1975, 6, 9, 12, 30, 0, 0, 161, 0),\n             (1975, 6, 9, 13, 20, 0, 0, 161, 0),\n             (1975, 6, 9, 14, 10, 0, 0, 161, 0)]]\n\n    def test_binning(self):\n        def testbin(start, end):\n            bins = _time_binnings(create(*start), create(*end), 3, 51)\n            return [(bin.width_label, bin.short_labels, bin.thresholds)\n                    for bin in reversed(bins)]\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1989, 3, 1)),\n            [('10 years',\n              ['1970', '1980', '1990'],\n              [0, 315532800, 631152000]),\n             ('5 years',\n              ['1975', '1980', '1985', '1990'],\n              [157766400, 315532800, 473385600, 631152000]),\n             ('2 years',\n              ['1974', '1976', '1978', '1980', '1982', '1984', '1986', '1988',\n               '1990'],\n              [126230400, 189302400, 252460800, 315532800, 378691200, 441763200,\n               504921600, 567993600, 631152000]),\n             ('1 year',\n              ['1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982',\n               '1983', '1984', '1985', '1986', '1987', '1988', '1989', '1990'],\n              [157766400, 189302400, 220924800, 252460800, 283996800, 315532800,\n               347155200, 378691200, 410227200, 441763200, 473385600, 504921600,\n               536457600, 567993600, 599616000, 631152000]),\n             ('6 months',\n              ['75 Jan', 'Jul', '76 Jan', 'Jul', '77 Jan', 'Jul', '78 Jan',\n               'Jul', '79 Jan', 'Jul', '80 Jan', 'Jul', '81 Jan', 'Jul',\n               '82 Jan', 'Jul', '83 Jan', 'Jul', '84 Jan', 'Jul', '85 Jan',\n               'Jul', '86 Jan', 'Jul', '87 Jan', 'Jul', '88 Jan', 'Jul',\n               '89 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200, 283996800, 299635200, 315532800, 331257600,\n               347155200, 362793600, 378691200, 394329600, 410227200, 425865600,\n               441763200, 457488000, 473385600, 489024000, 504921600, 520560000,\n               536457600, 552096000, 567993600, 583718400, 599616000,\n               615254400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1978, 3, 1)),\n            [('2 years',\n              ['1974', '1976', '1978', '1980'],\n              [126230400, 189302400, 252460800, 315532800]),\n             ('1 year',\n              ['1975', '1976', '1977', '1978', '1979'],\n              [157766400, 189302400, 220924800, 252460800, 283996800]),\n             ('6 months',\n              ['75 Jan', 'Jul',\n               '76 Jan', 'Jul',\n               '77 Jan', 'Jul',\n               '78 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200]),\n             ('3 months',\n              ['75 Apr', 'Jul', 'Oct',\n               '76 Jan', 'Apr', 'Jul', 'Oct',\n               '77 Jan', 'Apr', 'Jul', 'Oct',\n               '78 Jan', 'Apr'],\n              [165542400, 173404800, 181353600, 189302400, 197164800, 205027200,\n               212976000, 220924800, 228700800, 236563200, 244512000, 252460800,\n               260236800]),\n             ('2 months',\n              ['75 Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '76 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '77 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '78 Jan', 'Mar', 'May'],\n              [162864000, 168134400, 173404800, 178761600, 184032000, 189302400,\n               194486400, 199756800, 205027200, 210384000, 215654400, 220924800,\n               226022400, 231292800, 236563200, 241920000, 247190400, 252460800,\n               257558400, 262828800]),\n             ('1 month',\n              ['75 Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '76 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '77 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '78 Jan', 'Feb', 'Mar', 'Apr'],\n              [165542400, 168134400, 170812800, 173404800, 176083200, 178761600,\n               181353600, 184032000, 186624000, 189302400, 191980800, 194486400,\n               197164800, 199756800, 202435200, 205027200, 207705600, 210384000,\n               212976000, 215654400, 218246400, 220924800, 223603200, 226022400,\n               228700800, 231292800, 233971200, 236563200, 239241600, 241920000,\n               244512000, 247190400, 249782400, 252460800, 255139200, 257558400,\n               260236800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 2), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('2 weeks',\n              ['75 Dec 03', '17', '31', '76 Jan 14'],\n              [186796800, 188006400, 189216000, 190425600]),\n             ('1 week',\n              ['75 Dec 03', '10', '17', '24', '31',\n               '76 Jan 07'],\n              [186796800, 187401600, 188006400, 188611200, 189216000,\n               189820800]),\n             ('1 day',\n              ['75 Dec 02', '03', '04', '05', '06', '07', '08', '09', '10',\n               '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21',\n               '22', '23', '24', '25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [186710400, 186796800, 186883200, 186969600, 187056000, 187142400,\n               187228800, 187315200, 187401600, 187488000, 187574400, 187660800,\n               187747200, 187833600, 187920000, 188006400, 188092800, 188179200,\n               188265600, 188352000, 188438400, 188524800, 188611200, 188697600,\n               188784000, 188870400, 188956800, 189043200, 189129600, 189216000,\n               189302400, 189388800, 189475200, 189561600])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 25), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [188697600, 188784000, 188870400, 188956800, 189043200, 189129600,\n               189216000, 189302400, 189388800, 189475200, 189561600]),\n             ('12 hours',\n              ['75 Dec 25 00:00', '12:00',\n               '26 00:00', '12:00',\n               '27 00:00', '12:00',\n               '28 00:00', '12:00',\n               '29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [188697600, 188740800, 188784000, 188827200, 188870400, 188913600,\n               188956800, 189000000, 189043200, 189086400, 189129600, 189172800,\n               189216000, 189259200, 189302400, 189345600, 189388800, 189432000,\n               189475200, 189518400]),\n             ('6 hours',\n              ['75 Dec 25 00:00', '06:00', '12:00', '18:00',\n               '26 00:00', '06:00', '12:00', '18:00',\n               '27 00:00', '06:00', '12:00', '18:00',\n               '28 00:00', '06:00', '12:00', '18:00',\n               '29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [188697600, 188719200, 188740800, 188762400, 188784000, 188805600,\n               188827200, 188848800, 188870400, 188892000, 188913600, 188935200,\n               188956800, 188978400, 189000000, 189021600, 189043200, 189064800,\n               189086400, 189108000, 189129600, 189151200, 189172800, 189194400,\n               189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200, 189388800, 189410400, 189432000, 189453600,\n               189475200, 189496800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 29), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [189043200, 189129600, 189216000, 189302400, 189388800, 189475200,\n               189561600]),\n             ('12 hours',\n              ['75 Dec 29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [189043200, 189086400, 189129600, 189172800, 189216000, 189259200,\n               189302400, 189345600, 189388800, 189432000, 189475200,\n               189518400]),\n             ('6 hours',\n              ['75 Dec 29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [189043200, 189064800, 189086400, 189108000, 189129600, 189151200,\n               189172800, 189194400, 189216000, 189237600, 189259200, 189280800,\n               189302400, 189324000, 189345600, 189367200, 189388800, 189410400,\n               189432000, 189453600, 189475200, 189496800]),\n             ('3 hours',\n              ['75 Dec 29 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '30 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '02 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '03 00:00', '03:00'],\n              [189043200, 189054000, 189064800, 189075600, 189086400, 189097200,\n               189108000, 189118800, 189129600, 189140400, 189151200, 189162000,\n               189172800, 189183600, 189194400, 189205200, 189216000, 189226800,\n               189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200, 189324000, 189334800, 189345600, 189356400,\n               189367200, 189378000, 189388800, 189399600, 189410400, 189421200,\n               189432000, 189442800, 189453600, 189464400, 189475200,\n               189486000])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 0, 0, 0), (1976, 1, 1, 14, 30)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00'],\n              [189216000, 189259200, 189302400, 189345600, 189388800]),\n             ('6 hours',\n              ['75 Dec 31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00'],\n              [189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200]),\n             ('3 hours',\n              ['75 Dec 31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00'],\n              [189216000, 189226800, 189237600, 189248400, 189259200, 189270000,\n               189280800, 189291600, 189302400, 189313200, 189324000, 189334800,\n               189345600, 189356400]),\n             ('2 hours',\n              ['75 Dec 31 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00'],\n              [189216000, 189223200, 189230400, 189237600, 189244800, 189252000,\n               189259200, 189266400, 189273600, 189280800, 189288000, 189295200,\n               189302400, 189309600, 189316800, 189324000, 189331200, 189338400,\n               189345600, 189352800, 189360000]),\n             ('1 hour',\n              ['75 Dec 31 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00',\n               '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00'],\n              [189216000, 189219600, 189223200, 189226800, 189230400, 189234000,\n               189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000, 189309600, 189313200, 189316800, 189320400,\n               189324000, 189327600, 189331200, 189334800, 189338400, 189342000,\n               189345600, 189349200, 189352800, 189356400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 6), (1976, 1, 1)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00'],\n              [189216000, 189259200, 189302400, 189345600]),\n             ('6 hours',\n              ['75 Dec 31 06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00'],\n              [189237600, 189259200, 189280800, 189302400, 189324000]),\n             ('3 hours',\n              ['75 Dec 31 06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00'],\n              [189237600, 189244800, 189252000, 189259200, 189266400, 189273600,\n               189280800, 189288000, 189295200, 189302400, 189309600]),\n             ('1 hour',\n              ['75 Dec 31 06:00', '07:00', '08:00', '09:00', '10:00', '11:00',\n               '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00',\n               '19:00', '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00'],\n              [189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000]),\n             ('30 minutes',\n              ['Dec 31 06:00', '06:30', '07:00', '07:30', '08:00', '08:30',\n               '09:00', '09:30', '10:00', '10:30', '11:00', '11:30', '12:00',\n               '12:30', '13:00', '13:30', '14:00', '14:30', '15:00', '15:30',\n               '16:00', '16:30', '17:00', '17:30', '18:00', '18:30', '19:00',\n               '19:30', '20:00', '20:30', '21:00', '21:30', '22:00', '22:30',\n               '23:00', '23:30',\n               'Jan 01 00:00', '00:30'],\n              [189237600, 189239400, 189241200, 189243000, 189244800, 189246600,\n               189248400, 189250200, 189252000, 189253800, 189255600, 189257400,\n               189259200, 189261000, 189262800, 189264600, 189266400, 189268200,\n               189270000, 189271800, 189273600, 189275400, 189277200, 189279000,\n               189280800, 189282600, 189284400, 189286200, 189288000, 189289800,\n               189291600, 189293400, 189295200, 189297000, 189298800, 189300600,\n               189302400, 189304200])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 23), (1976, 1, 1, 2)),\n            [('3 hours',\n              ['75 Dec 31 21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189291600, 189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 22:00',\n               '76 Jan 01 00:00', '02:00', '04:00'],\n              [189295200, 189302400, 189309600, 189316800]),\n             ('1 hour',\n              ['75 Dec 31 23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00'],\n              [189298800, 189302400, 189306000, 189309600, 189313200]),\n             ('30 minutes',\n              ['Dec 31 23:00', '23:30',\n               'Jan 01 00:00', '00:30', '01:00', '01:30', '02:00', '02:30'],\n              [189298800, 189300600, 189302400, 189304200, 189306000, 189307800,\n               189309600, 189311400]),\n             ('15 minutes',\n              ['Dec 31 23:00', '23:15', '23:30', '23:45',\n               'Jan 01 00:00', '00:15', '00:30', '00:45', '01:00', '01:15',\n               '01:30', '01:45', '02:00', '02:15'],\n              [189298800, 189299700, 189300600, 189301500, 189302400, 189303300,\n               189304200, 189305100, 189306000, 189306900, 189307800, 189308700,\n               189309600, 189310500]),\n             ('10 minutes',\n              ['Dec 31 23:00', '23:10', '23:20', '23:30', '23:40', '23:50',\n               'Jan 01 00:00', '00:10', '00:20', '00:30', '00:40', '00:50',\n               '01:00', '01:10', '01:20', '01:30', '01:40', '01:50', '02:00',\n               '02:10'],\n              [189298800, 189299400, 189300000, 189300600, 189301200, 189301800,\n               189302400, 189303000, 189303600, 189304200, 189304800, 189305400,\n               189306000, 189306600, 189307200, 189307800, 189308400, 189309000,\n               189309600, 189310200]),\n             ('5 minutes',\n              ['Dec 31 23:00', '23:05', '23:10', '23:15', '23:20', '23:25',\n               '23:30', '23:35', '23:40', '23:45', '23:50', '23:55',\n               'Jan 01 00:00', '00:05', '00:10', '00:15', '00:20', '00:25',\n               '00:30', '00:35', '00:40', '00:45', '00:50', '00:55', '01:00',\n               '01:05', '01:10', '01:15', '01:20', '01:25', '01:30', '01:35',\n               '01:40', '01:45', '01:50', '01:55', '02:00', '02:05'],\n              [189298800, 189299100, 189299400, 189299700, 189300000, 189300300,\n               189300600, 189300900, 189301200, 189301500, 189301800, 189302100,\n               189302400, 189302700, 189303000, 189303300, 189303600, 189303900,\n               189304200, 189304500, 189304800, 189305100, 189305400, 189305700,\n               189306000, 189306300, 189306600, 189306900, 189307200, 189307500,\n               189307800, 189308100, 189308400, 189308700, 189309000, 189309300,\n               189309600, 189309900])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 23, 18)),\n            [('12 hours',\n              ['Jun 09 00:00', '12:00', '10 00:00'],\n              [-1437868800, -1437825600, -1437782400]),\n             ('6 hours',\n              ['Jun 09 06:00', '12:00', '18:00', '10 00:00'],\n              [-1437847200, -1437825600, -1437804000, -1437782400]),\n             ('3 hours',\n              ['Jun 09 09:00', '12:00', '15:00', '18:00', '21:00', '10 00:00'],\n              [-1437836400, -1437825600, -1437814800, -1437804000, -1437793200,\n               -1437782400]),\n             ('2 hours',\n              ['Jun 09 10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00', '10 00:00'],\n              [-1437832800, -1437825600, -1437818400, -1437811200, -1437804000,\n               -1437796800, -1437789600, -1437782400]),\n             ('1 hour',\n              ['Jun 09 10:00', '11:00', '12:00', '13:00', '14:00', '15:00',\n               '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00',\n               '23:00',\n               '10 00:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000, -1437818400,\n               -1437814800, -1437811200, -1437807600, -1437804000, -1437800400,\n               -1437796800, -1437793200, -1437789600, -1437786000,\n               -1437782400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30', '14:00', '14:30', '15:00', '15:30', '16:00', '16:30',\n               '17:00', '17:30', '18:00', '18:30', '19:00', '19:30', '20:00',\n               '20:30', '21:00', '21:30', '22:00', '22:30', '23:00', '23:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200, -1437818400, -1437816600,\n               -1437814800, -1437813000, -1437811200, -1437809400, -1437807600,\n               -1437805800, -1437804000, -1437802200, -1437800400, -1437798600,\n               -1437796800, -1437795000, -1437793200, -1437791400, -1437789600,\n               -1437787800, -1437786000, -1437784200])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 13, 18)),\n            [('2 hours',\n              ['10:00', '12:00', '14:00'],\n              [-1437832800, -1437825600, -1437818400]),\n             ('1 hour',\n              ['10:00', '11:00', '12:00', '13:00', '14:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000,\n               -1437818400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00', '11:15', '11:30',\n               '11:45', '12:00', '12:15', '12:30', '12:45', '13:00', '13:15',\n               '13:30'],\n              [-1437832800, -1437831900, -1437831000, -1437830100, -1437829200,\n               -1437828300, -1437827400, -1437826500, -1437825600, -1437824700,\n               -1437823800, -1437822900, -1437822000, -1437821100,\n               -1437820200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50', '11:00',\n               '11:10', '11:20', '11:30', '11:40', '11:50', '12:00', '12:10',\n               '12:20', '12:30', '12:40', '12:50', '13:00', '13:10', '13:20'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800, -1437829200, -1437828600, -1437828000, -1437827400,\n               -1437826800, -1437826200, -1437825600, -1437825000, -1437824400,\n               -1437823800, -1437823200, -1437822600, -1437822000, -1437821400,\n               -1437820800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50', '10:55', '11:00', '11:05',\n               '11:10', '11:15', '11:20', '11:25', '11:30', '11:35', '11:40',\n               '11:45', '11:50', '11:55', '12:00', '12:05', '12:10', '12:15',\n               '12:20', '12:25', '12:30', '12:35', '12:40', '12:45', '12:50',\n               '12:55', '13:00', '13:05', '13:10', '13:15', '13:20'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800, -1437829500, -1437829200, -1437828900, -1437828600,\n               -1437828300, -1437828000, -1437827700, -1437827400, -1437827100,\n               -1437826800, -1437826500, -1437826200, -1437825900, -1437825600,\n               -1437825300, -1437825000, -1437824700, -1437824400, -1437824100,\n               -1437823800, -1437823500, -1437823200, -1437822900, -1437822600,\n               -1437822300, -1437822000, -1437821700, -1437821400, -1437821100,\n               -1437820800])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 48)),\n            [('30 minutes',\n              ['10:00', '10:30', '11:00'],\n              [-1437832800, -1437831000, -1437829200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00'],\n              [-1437832800, -1437831900, -1437831000, -1437830100,\n               -1437829200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21', '10:22', '10:23', '10:24', '10:25', '10:26', '10:27',\n               '10:28', '10:29', '10:30', '10:31', '10:32', '10:33', '10:34',\n               '10:35', '10:36', '10:37', '10:38', '10:39', '10:40', '10:41',\n               '10:42', '10:43', '10:44', '10:45', '10:46', '10:47', '10:48',\n               '10:49'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540, -1437831480, -1437831420, -1437831360,\n               -1437831300, -1437831240, -1437831180, -1437831120, -1437831060,\n               -1437831000, -1437830940, -1437830880, -1437830820, -1437830760,\n               -1437830700, -1437830640, -1437830580, -1437830520, -1437830460,\n               -1437830400, -1437830340, -1437830280, -1437830220, -1437830160,\n               -1437830100, -1437830040, -1437829980, -1437829920, -1437829860]\n              )]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 20)),\n            [('15 minutes',\n              ['10:00', '10:15', '10:30'],\n              [-1437832800, -1437831900, -1437831000]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30'],\n              [-1437832800, -1437832200, -1437831600, -1437831000]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540]),\n             ('30 seconds',\n              ['10:00:00', '10:00:30', '10:01:00', '10:01:30', '10:02:00',\n               '10:02:30', '10:03:00', '10:03:30', '10:04:00', '10:04:30',\n               '10:05:00', '10:05:30', '10:06:00', '10:06:30', '10:07:00',\n               '10:07:30', '10:08:00', '10:08:30', '10:09:00', '10:09:30',\n               '10:10:00', '10:10:30', '10:11:00', '10:11:30', '10:12:00',\n               '10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30', '10:19:00', '10:19:30',\n               '10:20:00', '10:20:30'],\n              [-1437832800, -1437832770, -1437832740, -1437832710, -1437832680,\n               -1437832650, -1437832620, -1437832590, -1437832560, -1437832530,\n               -1437832500, -1437832470, -1437832440, -1437832410, -1437832380,\n               -1437832350, -1437832320, -1437832290, -1437832260, -1437832230,\n               -1437832200, -1437832170, -1437832140, -1437832110, -1437832080,\n               -1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690, -1437831660, -1437831630,\n               -1437831600, -1437831570])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 18, 12)),\n            [('5 minutes',\n              ['10:10', '10:15', '10:20'],\n              [-1437832200, -1437831900, -1437831600]),\n             ('1 minute',\n              ['10:12', '10:13', '10:14', '10:15', '10:16', '10:17', '10:18',\n               '10:19'],\n              [-1437832080, -1437832020, -1437831960, -1437831900, -1437831840,\n               -1437831780, -1437831720, -1437831660]),\n             ('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30'],\n              [-1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15', '10:13:30',\n               '10:13:45', '10:14:00', '10:14:15', '10:14:30', '10:14:45',\n               '10:15:00', '10:15:15', '10:15:30', '10:15:45', '10:16:00',\n               '10:16:15', '10:16:30', '10:16:45', '10:17:00', '10:17:15',\n               '10:17:30', '10:17:45', '10:18:00', '10:18:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005, -1437831990,\n               -1437831975, -1437831960, -1437831945, -1437831930, -1437831915,\n               -1437831900, -1437831885, -1437831870, -1437831855, -1437831840,\n               -1437831825, -1437831810, -1437831795, -1437831780, -1437831765,\n               -1437831750, -1437831735, -1437831720, -1437831705]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20', '10:13:30', '10:13:40', '10:13:50', '10:14:00',\n               '10:14:10', '10:14:20', '10:14:30', '10:14:40', '10:14:50',\n               '10:15:00', '10:15:10', '10:15:20', '10:15:30', '10:15:40',\n               '10:15:50', '10:16:00', '10:16:10', '10:16:20', '10:16:30',\n               '10:16:40', '10:16:50', '10:17:00', '10:17:10', '10:17:20',\n               '10:17:30', '10:17:40', '10:17:50', '10:18:00', '10:18:10',\n               '10:18:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000, -1437831990, -1437831980, -1437831970, -1437831960,\n               -1437831950, -1437831940, -1437831930, -1437831920, -1437831910,\n               -1437831900, -1437831890, -1437831880, -1437831870, -1437831860,\n               -1437831850, -1437831840, -1437831830, -1437831820, -1437831810,\n               -1437831800, -1437831790, -1437831780, -1437831770, -1437831760,\n               -1437831750, -1437831740, -1437831730, -1437831720, -1437831710,\n               -1437831700])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 13, 12)),\n            [('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30'],\n              [-1437832050, -1437832020, -1437831990]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000]),\n             ('5 seconds',\n              ['10:12:30', '10:12:35', '10:12:40', '10:12:45', '10:12:50',\n               '10:12:55', '10:13:00', '10:13:05', '10:13:10', '10:13:15'],\n              [-1437832050, -1437832045, -1437832040, -1437832035, -1437832030,\n               -1437832025, -1437832020, -1437832015, -1437832010,\n               -1437832005]),\n             ('1 second',\n              ['10:12:33', '10:12:34', '10:12:35', '10:12:36', '10:12:37',\n               '10:12:38', '10:12:39', '10:12:40', '10:12:41', '10:12:42',\n               '10:12:43', '10:12:44', '10:12:45', '10:12:46', '10:12:47',\n               '10:12:48', '10:12:49', '10:12:50', '10:12:51', '10:12:52',\n               '10:12:53', '10:12:54', '10:12:55', '10:12:56', '10:12:57',\n               '10:12:58', '10:12:59', '10:13:00', '10:13:01', '10:13:02',\n               '10:13:03', '10:13:04', '10:13:05', '10:13:06', '10:13:07',\n               '10:13:08', '10:13:09', '10:13:10', '10:13:11', '10:13:12',\n               '10:13:13'],\n              [-1437832047, -1437832046, -1437832045, -1437832044, -1437832043,\n               -1437832042, -1437832041, -1437832040, -1437832039, -1437832038,\n               -1437832037, -1437832036, -1437832035, -1437832034, -1437832033,\n               -1437832032, -1437832031, -1437832030, -1437832029, -1437832028,\n               -1437832027, -1437832026, -1437832025, -1437832024, -1437832023,\n               -1437832022, -1437832021, -1437832020, -1437832019, -1437832018,\n               -1437832017, -1437832016, -1437832015, -1437832014, -1437832013,\n               -1437832012, -1437832011, -1437832010, -1437832009, -1437832008,\n               -1437832007])])\n\n        self.assertEqual(\n            testbin((1973, 9, 14), (2010, 9, 8)),\n            [\n                ('50 years',\n                 ['1950', '2000', '2050'],\n                 [-631152000, 946684800, 2524608000]),\n                ('25 years',\n                 ['1950', '1975', '2000', '2025'],\n                 [-631152000, 157766400, 946684800, 1735689600]),\n                ('10 years',\n                 ['1970', '1980', '1990', '2000', '2010', '2020'],\n                 [0, 315532800, 631152000, 946684800, 1262304000, 1577836800]),\n                ('5 years',\n                 ['1970', '1975', '1980', '1985', '1990', '1995', '2000',\n                  '2005', '2010', '2015'],\n                 [0, 157766400, 315532800, 473385600, 631152000, 788918400,\n                  946684800, 1104537600, 1262304000, 1420070400]),\n                ('2 years',\n                 ['1972', '1974', '1976', '1978', '1980', '1982', '1984',\n                  '1986', '1988', '1990', '1992', '1994', '1996', '1998',\n                  '2000', '2002', '2004', '2006', '2008', '2010', '2012'],\n                 [63072000, 126230400, 189302400, 252460800, 315532800,\n                  378691200, 441763200, 504921600, 567993600, 631152000,\n                  694224000, 757382400, 820454400, 883612800, 946684800,\n                  1009843200, 1072915200, 1136073600, 1199145600, 1262304000,\n                  1325376000]),\n                ('1 year',\n                 ['1973', '1974', '1975', '1976', '1977', '1978', '1979',\n                  '1980', '1981', '1982', '1983', '1984', '1985', '1986',\n                  '1987', '1988', '1989', '1990', '1991', '1992', '1993',\n                  '1994', '1995', '1996', '1997', '1998', '1999', '2000',\n                  '2001', '2002', '2003', '2004', '2005', '2006', '2007',\n                  '2008', '2009', '2010', '2011'],\n                 [94694400, 126230400, 157766400, 189302400, 220924800,\n                  252460800, 283996800, 315532800, 347155200, 378691200,\n                  410227200, 441763200, 473385600, 504921600, 536457600,\n                  567993600, 599616000, 631152000, 662688000, 694224000,\n                  725846400, 757382400, 788918400, 820454400, 852076800,\n                  883612800, 915148800, 946684800, 978307200, 1009843200,\n                  1041379200, 1072915200, 1104537600, 1136073600, 1167609600,\n                  1199145600, 1230768000, 1262304000, 1293840000])\n            ]\n        )\n\n    def test_min_unique(self):\n        bins = time_binnings(self.dates, min_unique=7)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_add_unique(self):\n        bins = time_binnings(self.dates, add_unique=7)\n        self.assertNotEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_limits(self):\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=17)},\n            {9, 17})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=16)},\n            {9})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=10, max_bins=17)},\n            {17})\n\n    def test_single_value(self):\n        dates = np.array([42])\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_multiple_identical(self):\n        dates = np.array([42] * 5)\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_no_values(self):\n        dates = np.array([])\n        self.assertRaises(ValueError, time_binnings, dates)\n\n        dates = np.array([np.nan, np.nan])\n        self.assertRaises(ValueError, time_binnings, dates)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 26,
                            "end_lineno": 672,
                            "parent": {
                                "file_name": "Orange/preprocess/tests/test_discretize.py",
                                "type": "class",
                                "name": "TestTimeBinning",
                                "content": "class TestTimeBinning(unittest.TestCase):\n    def setUp(self):\n        self.dates = [mktime(x) for x in\n            [(1975, 6, 9, 10, 0, 0, 0, 161, 0),\n             (1975, 6, 9, 10, 50, 0, 0, 161, 0),\n             (1975, 6, 9, 11, 40, 0, 0, 161, 0),\n             (1975, 6, 9, 12, 30, 0, 0, 161, 0),\n             (1975, 6, 9, 13, 20, 0, 0, 161, 0),\n             (1975, 6, 9, 14, 10, 0, 0, 161, 0)]]\n\n    def test_binning(self):\n        def testbin(start, end):\n            bins = _time_binnings(create(*start), create(*end), 3, 51)\n            return [(bin.width_label, bin.short_labels, bin.thresholds)\n                    for bin in reversed(bins)]\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1989, 3, 1)),\n            [('10 years',\n              ['1970', '1980', '1990'],\n              [0, 315532800, 631152000]),\n             ('5 years',\n              ['1975', '1980', '1985', '1990'],\n              [157766400, 315532800, 473385600, 631152000]),\n             ('2 years',\n              ['1974', '1976', '1978', '1980', '1982', '1984', '1986', '1988',\n               '1990'],\n              [126230400, 189302400, 252460800, 315532800, 378691200, 441763200,\n               504921600, 567993600, 631152000]),\n             ('1 year',\n              ['1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982',\n               '1983', '1984', '1985', '1986', '1987', '1988', '1989', '1990'],\n              [157766400, 189302400, 220924800, 252460800, 283996800, 315532800,\n               347155200, 378691200, 410227200, 441763200, 473385600, 504921600,\n               536457600, 567993600, 599616000, 631152000]),\n             ('6 months',\n              ['75 Jan', 'Jul', '76 Jan', 'Jul', '77 Jan', 'Jul', '78 Jan',\n               'Jul', '79 Jan', 'Jul', '80 Jan', 'Jul', '81 Jan', 'Jul',\n               '82 Jan', 'Jul', '83 Jan', 'Jul', '84 Jan', 'Jul', '85 Jan',\n               'Jul', '86 Jan', 'Jul', '87 Jan', 'Jul', '88 Jan', 'Jul',\n               '89 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200, 283996800, 299635200, 315532800, 331257600,\n               347155200, 362793600, 378691200, 394329600, 410227200, 425865600,\n               441763200, 457488000, 473385600, 489024000, 504921600, 520560000,\n               536457600, 552096000, 567993600, 583718400, 599616000,\n               615254400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1978, 3, 1)),\n            [('2 years',\n              ['1974', '1976', '1978', '1980'],\n              [126230400, 189302400, 252460800, 315532800]),\n             ('1 year',\n              ['1975', '1976', '1977', '1978', '1979'],\n              [157766400, 189302400, 220924800, 252460800, 283996800]),\n             ('6 months',\n              ['75 Jan', 'Jul',\n               '76 Jan', 'Jul',\n               '77 Jan', 'Jul',\n               '78 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200]),\n             ('3 months',\n              ['75 Apr', 'Jul', 'Oct',\n               '76 Jan', 'Apr', 'Jul', 'Oct',\n               '77 Jan', 'Apr', 'Jul', 'Oct',\n               '78 Jan', 'Apr'],\n              [165542400, 173404800, 181353600, 189302400, 197164800, 205027200,\n               212976000, 220924800, 228700800, 236563200, 244512000, 252460800,\n               260236800]),\n             ('2 months',\n              ['75 Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '76 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '77 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '78 Jan', 'Mar', 'May'],\n              [162864000, 168134400, 173404800, 178761600, 184032000, 189302400,\n               194486400, 199756800, 205027200, 210384000, 215654400, 220924800,\n               226022400, 231292800, 236563200, 241920000, 247190400, 252460800,\n               257558400, 262828800]),\n             ('1 month',\n              ['75 Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '76 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '77 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '78 Jan', 'Feb', 'Mar', 'Apr'],\n              [165542400, 168134400, 170812800, 173404800, 176083200, 178761600,\n               181353600, 184032000, 186624000, 189302400, 191980800, 194486400,\n               197164800, 199756800, 202435200, 205027200, 207705600, 210384000,\n               212976000, 215654400, 218246400, 220924800, 223603200, 226022400,\n               228700800, 231292800, 233971200, 236563200, 239241600, 241920000,\n               244512000, 247190400, 249782400, 252460800, 255139200, 257558400,\n               260236800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 2), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('2 weeks',\n              ['75 Dec 03', '17', '31', '76 Jan 14'],\n              [186796800, 188006400, 189216000, 190425600]),\n             ('1 week',\n              ['75 Dec 03', '10', '17', '24', '31',\n               '76 Jan 07'],\n              [186796800, 187401600, 188006400, 188611200, 189216000,\n               189820800]),\n             ('1 day',\n              ['75 Dec 02', '03', '04', '05', '06', '07', '08', '09', '10',\n               '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21',\n               '22', '23', '24', '25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [186710400, 186796800, 186883200, 186969600, 187056000, 187142400,\n               187228800, 187315200, 187401600, 187488000, 187574400, 187660800,\n               187747200, 187833600, 187920000, 188006400, 188092800, 188179200,\n               188265600, 188352000, 188438400, 188524800, 188611200, 188697600,\n               188784000, 188870400, 188956800, 189043200, 189129600, 189216000,\n               189302400, 189388800, 189475200, 189561600])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 25), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [188697600, 188784000, 188870400, 188956800, 189043200, 189129600,\n               189216000, 189302400, 189388800, 189475200, 189561600]),\n             ('12 hours',\n              ['75 Dec 25 00:00', '12:00',\n               '26 00:00', '12:00',\n               '27 00:00', '12:00',\n               '28 00:00', '12:00',\n               '29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [188697600, 188740800, 188784000, 188827200, 188870400, 188913600,\n               188956800, 189000000, 189043200, 189086400, 189129600, 189172800,\n               189216000, 189259200, 189302400, 189345600, 189388800, 189432000,\n               189475200, 189518400]),\n             ('6 hours',\n              ['75 Dec 25 00:00', '06:00', '12:00', '18:00',\n               '26 00:00', '06:00', '12:00', '18:00',\n               '27 00:00', '06:00', '12:00', '18:00',\n               '28 00:00', '06:00', '12:00', '18:00',\n               '29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [188697600, 188719200, 188740800, 188762400, 188784000, 188805600,\n               188827200, 188848800, 188870400, 188892000, 188913600, 188935200,\n               188956800, 188978400, 189000000, 189021600, 189043200, 189064800,\n               189086400, 189108000, 189129600, 189151200, 189172800, 189194400,\n               189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200, 189388800, 189410400, 189432000, 189453600,\n               189475200, 189496800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 29), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [189043200, 189129600, 189216000, 189302400, 189388800, 189475200,\n               189561600]),\n             ('12 hours',\n              ['75 Dec 29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [189043200, 189086400, 189129600, 189172800, 189216000, 189259200,\n               189302400, 189345600, 189388800, 189432000, 189475200,\n               189518400]),\n             ('6 hours',\n              ['75 Dec 29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [189043200, 189064800, 189086400, 189108000, 189129600, 189151200,\n               189172800, 189194400, 189216000, 189237600, 189259200, 189280800,\n               189302400, 189324000, 189345600, 189367200, 189388800, 189410400,\n               189432000, 189453600, 189475200, 189496800]),\n             ('3 hours',\n              ['75 Dec 29 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '30 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '02 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '03 00:00', '03:00'],\n              [189043200, 189054000, 189064800, 189075600, 189086400, 189097200,\n               189108000, 189118800, 189129600, 189140400, 189151200, 189162000,\n               189172800, 189183600, 189194400, 189205200, 189216000, 189226800,\n               189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200, 189324000, 189334800, 189345600, 189356400,\n               189367200, 189378000, 189388800, 189399600, 189410400, 189421200,\n               189432000, 189442800, 189453600, 189464400, 189475200,\n               189486000])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 0, 0, 0), (1976, 1, 1, 14, 30)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00'],\n              [189216000, 189259200, 189302400, 189345600, 189388800]),\n             ('6 hours',\n              ['75 Dec 31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00'],\n              [189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200]),\n             ('3 hours',\n              ['75 Dec 31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00'],\n              [189216000, 189226800, 189237600, 189248400, 189259200, 189270000,\n               189280800, 189291600, 189302400, 189313200, 189324000, 189334800,\n               189345600, 189356400]),\n             ('2 hours',\n              ['75 Dec 31 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00'],\n              [189216000, 189223200, 189230400, 189237600, 189244800, 189252000,\n               189259200, 189266400, 189273600, 189280800, 189288000, 189295200,\n               189302400, 189309600, 189316800, 189324000, 189331200, 189338400,\n               189345600, 189352800, 189360000]),\n             ('1 hour',\n              ['75 Dec 31 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00',\n               '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00'],\n              [189216000, 189219600, 189223200, 189226800, 189230400, 189234000,\n               189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000, 189309600, 189313200, 189316800, 189320400,\n               189324000, 189327600, 189331200, 189334800, 189338400, 189342000,\n               189345600, 189349200, 189352800, 189356400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 6), (1976, 1, 1)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00'],\n              [189216000, 189259200, 189302400, 189345600]),\n             ('6 hours',\n              ['75 Dec 31 06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00'],\n              [189237600, 189259200, 189280800, 189302400, 189324000]),\n             ('3 hours',\n              ['75 Dec 31 06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00'],\n              [189237600, 189244800, 189252000, 189259200, 189266400, 189273600,\n               189280800, 189288000, 189295200, 189302400, 189309600]),\n             ('1 hour',\n              ['75 Dec 31 06:00', '07:00', '08:00', '09:00', '10:00', '11:00',\n               '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00',\n               '19:00', '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00'],\n              [189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000]),\n             ('30 minutes',\n              ['Dec 31 06:00', '06:30', '07:00', '07:30', '08:00', '08:30',\n               '09:00', '09:30', '10:00', '10:30', '11:00', '11:30', '12:00',\n               '12:30', '13:00', '13:30', '14:00', '14:30', '15:00', '15:30',\n               '16:00', '16:30', '17:00', '17:30', '18:00', '18:30', '19:00',\n               '19:30', '20:00', '20:30', '21:00', '21:30', '22:00', '22:30',\n               '23:00', '23:30',\n               'Jan 01 00:00', '00:30'],\n              [189237600, 189239400, 189241200, 189243000, 189244800, 189246600,\n               189248400, 189250200, 189252000, 189253800, 189255600, 189257400,\n               189259200, 189261000, 189262800, 189264600, 189266400, 189268200,\n               189270000, 189271800, 189273600, 189275400, 189277200, 189279000,\n               189280800, 189282600, 189284400, 189286200, 189288000, 189289800,\n               189291600, 189293400, 189295200, 189297000, 189298800, 189300600,\n               189302400, 189304200])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 23), (1976, 1, 1, 2)),\n            [('3 hours',\n              ['75 Dec 31 21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189291600, 189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 22:00',\n               '76 Jan 01 00:00', '02:00', '04:00'],\n              [189295200, 189302400, 189309600, 189316800]),\n             ('1 hour',\n              ['75 Dec 31 23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00'],\n              [189298800, 189302400, 189306000, 189309600, 189313200]),\n             ('30 minutes',\n              ['Dec 31 23:00', '23:30',\n               'Jan 01 00:00', '00:30', '01:00', '01:30', '02:00', '02:30'],\n              [189298800, 189300600, 189302400, 189304200, 189306000, 189307800,\n               189309600, 189311400]),\n             ('15 minutes',\n              ['Dec 31 23:00', '23:15', '23:30', '23:45',\n               'Jan 01 00:00', '00:15', '00:30', '00:45', '01:00', '01:15',\n               '01:30', '01:45', '02:00', '02:15'],\n              [189298800, 189299700, 189300600, 189301500, 189302400, 189303300,\n               189304200, 189305100, 189306000, 189306900, 189307800, 189308700,\n               189309600, 189310500]),\n             ('10 minutes',\n              ['Dec 31 23:00', '23:10', '23:20', '23:30', '23:40', '23:50',\n               'Jan 01 00:00', '00:10', '00:20', '00:30', '00:40', '00:50',\n               '01:00', '01:10', '01:20', '01:30', '01:40', '01:50', '02:00',\n               '02:10'],\n              [189298800, 189299400, 189300000, 189300600, 189301200, 189301800,\n               189302400, 189303000, 189303600, 189304200, 189304800, 189305400,\n               189306000, 189306600, 189307200, 189307800, 189308400, 189309000,\n               189309600, 189310200]),\n             ('5 minutes',\n              ['Dec 31 23:00', '23:05', '23:10', '23:15', '23:20', '23:25',\n               '23:30', '23:35', '23:40', '23:45', '23:50', '23:55',\n               'Jan 01 00:00', '00:05', '00:10', '00:15', '00:20', '00:25',\n               '00:30', '00:35', '00:40', '00:45', '00:50', '00:55', '01:00',\n               '01:05', '01:10', '01:15', '01:20', '01:25', '01:30', '01:35',\n               '01:40', '01:45', '01:50', '01:55', '02:00', '02:05'],\n              [189298800, 189299100, 189299400, 189299700, 189300000, 189300300,\n               189300600, 189300900, 189301200, 189301500, 189301800, 189302100,\n               189302400, 189302700, 189303000, 189303300, 189303600, 189303900,\n               189304200, 189304500, 189304800, 189305100, 189305400, 189305700,\n               189306000, 189306300, 189306600, 189306900, 189307200, 189307500,\n               189307800, 189308100, 189308400, 189308700, 189309000, 189309300,\n               189309600, 189309900])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 23, 18)),\n            [('12 hours',\n              ['Jun 09 00:00', '12:00', '10 00:00'],\n              [-1437868800, -1437825600, -1437782400]),\n             ('6 hours',\n              ['Jun 09 06:00', '12:00', '18:00', '10 00:00'],\n              [-1437847200, -1437825600, -1437804000, -1437782400]),\n             ('3 hours',\n              ['Jun 09 09:00', '12:00', '15:00', '18:00', '21:00', '10 00:00'],\n              [-1437836400, -1437825600, -1437814800, -1437804000, -1437793200,\n               -1437782400]),\n             ('2 hours',\n              ['Jun 09 10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00', '10 00:00'],\n              [-1437832800, -1437825600, -1437818400, -1437811200, -1437804000,\n               -1437796800, -1437789600, -1437782400]),\n             ('1 hour',\n              ['Jun 09 10:00', '11:00', '12:00', '13:00', '14:00', '15:00',\n               '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00',\n               '23:00',\n               '10 00:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000, -1437818400,\n               -1437814800, -1437811200, -1437807600, -1437804000, -1437800400,\n               -1437796800, -1437793200, -1437789600, -1437786000,\n               -1437782400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30', '14:00', '14:30', '15:00', '15:30', '16:00', '16:30',\n               '17:00', '17:30', '18:00', '18:30', '19:00', '19:30', '20:00',\n               '20:30', '21:00', '21:30', '22:00', '22:30', '23:00', '23:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200, -1437818400, -1437816600,\n               -1437814800, -1437813000, -1437811200, -1437809400, -1437807600,\n               -1437805800, -1437804000, -1437802200, -1437800400, -1437798600,\n               -1437796800, -1437795000, -1437793200, -1437791400, -1437789600,\n               -1437787800, -1437786000, -1437784200])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 13, 18)),\n            [('2 hours',\n              ['10:00', '12:00', '14:00'],\n              [-1437832800, -1437825600, -1437818400]),\n             ('1 hour',\n              ['10:00', '11:00', '12:00', '13:00', '14:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000,\n               -1437818400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00', '11:15', '11:30',\n               '11:45', '12:00', '12:15', '12:30', '12:45', '13:00', '13:15',\n               '13:30'],\n              [-1437832800, -1437831900, -1437831000, -1437830100, -1437829200,\n               -1437828300, -1437827400, -1437826500, -1437825600, -1437824700,\n               -1437823800, -1437822900, -1437822000, -1437821100,\n               -1437820200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50', '11:00',\n               '11:10', '11:20', '11:30', '11:40', '11:50', '12:00', '12:10',\n               '12:20', '12:30', '12:40', '12:50', '13:00', '13:10', '13:20'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800, -1437829200, -1437828600, -1437828000, -1437827400,\n               -1437826800, -1437826200, -1437825600, -1437825000, -1437824400,\n               -1437823800, -1437823200, -1437822600, -1437822000, -1437821400,\n               -1437820800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50', '10:55', '11:00', '11:05',\n               '11:10', '11:15', '11:20', '11:25', '11:30', '11:35', '11:40',\n               '11:45', '11:50', '11:55', '12:00', '12:05', '12:10', '12:15',\n               '12:20', '12:25', '12:30', '12:35', '12:40', '12:45', '12:50',\n               '12:55', '13:00', '13:05', '13:10', '13:15', '13:20'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800, -1437829500, -1437829200, -1437828900, -1437828600,\n               -1437828300, -1437828000, -1437827700, -1437827400, -1437827100,\n               -1437826800, -1437826500, -1437826200, -1437825900, -1437825600,\n               -1437825300, -1437825000, -1437824700, -1437824400, -1437824100,\n               -1437823800, -1437823500, -1437823200, -1437822900, -1437822600,\n               -1437822300, -1437822000, -1437821700, -1437821400, -1437821100,\n               -1437820800])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 48)),\n            [('30 minutes',\n              ['10:00', '10:30', '11:00'],\n              [-1437832800, -1437831000, -1437829200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00'],\n              [-1437832800, -1437831900, -1437831000, -1437830100,\n               -1437829200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21', '10:22', '10:23', '10:24', '10:25', '10:26', '10:27',\n               '10:28', '10:29', '10:30', '10:31', '10:32', '10:33', '10:34',\n               '10:35', '10:36', '10:37', '10:38', '10:39', '10:40', '10:41',\n               '10:42', '10:43', '10:44', '10:45', '10:46', '10:47', '10:48',\n               '10:49'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540, -1437831480, -1437831420, -1437831360,\n               -1437831300, -1437831240, -1437831180, -1437831120, -1437831060,\n               -1437831000, -1437830940, -1437830880, -1437830820, -1437830760,\n               -1437830700, -1437830640, -1437830580, -1437830520, -1437830460,\n               -1437830400, -1437830340, -1437830280, -1437830220, -1437830160,\n               -1437830100, -1437830040, -1437829980, -1437829920, -1437829860]\n              )]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 20)),\n            [('15 minutes',\n              ['10:00', '10:15', '10:30'],\n              [-1437832800, -1437831900, -1437831000]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30'],\n              [-1437832800, -1437832200, -1437831600, -1437831000]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540]),\n             ('30 seconds',\n              ['10:00:00', '10:00:30', '10:01:00', '10:01:30', '10:02:00',\n               '10:02:30', '10:03:00', '10:03:30', '10:04:00', '10:04:30',\n               '10:05:00', '10:05:30', '10:06:00', '10:06:30', '10:07:00',\n               '10:07:30', '10:08:00', '10:08:30', '10:09:00', '10:09:30',\n               '10:10:00', '10:10:30', '10:11:00', '10:11:30', '10:12:00',\n               '10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30', '10:19:00', '10:19:30',\n               '10:20:00', '10:20:30'],\n              [-1437832800, -1437832770, -1437832740, -1437832710, -1437832680,\n               -1437832650, -1437832620, -1437832590, -1437832560, -1437832530,\n               -1437832500, -1437832470, -1437832440, -1437832410, -1437832380,\n               -1437832350, -1437832320, -1437832290, -1437832260, -1437832230,\n               -1437832200, -1437832170, -1437832140, -1437832110, -1437832080,\n               -1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690, -1437831660, -1437831630,\n               -1437831600, -1437831570])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 18, 12)),\n            [('5 minutes',\n              ['10:10', '10:15', '10:20'],\n              [-1437832200, -1437831900, -1437831600]),\n             ('1 minute',\n              ['10:12', '10:13', '10:14', '10:15', '10:16', '10:17', '10:18',\n               '10:19'],\n              [-1437832080, -1437832020, -1437831960, -1437831900, -1437831840,\n               -1437831780, -1437831720, -1437831660]),\n             ('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30'],\n              [-1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15', '10:13:30',\n               '10:13:45', '10:14:00', '10:14:15', '10:14:30', '10:14:45',\n               '10:15:00', '10:15:15', '10:15:30', '10:15:45', '10:16:00',\n               '10:16:15', '10:16:30', '10:16:45', '10:17:00', '10:17:15',\n               '10:17:30', '10:17:45', '10:18:00', '10:18:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005, -1437831990,\n               -1437831975, -1437831960, -1437831945, -1437831930, -1437831915,\n               -1437831900, -1437831885, -1437831870, -1437831855, -1437831840,\n               -1437831825, -1437831810, -1437831795, -1437831780, -1437831765,\n               -1437831750, -1437831735, -1437831720, -1437831705]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20', '10:13:30', '10:13:40', '10:13:50', '10:14:00',\n               '10:14:10', '10:14:20', '10:14:30', '10:14:40', '10:14:50',\n               '10:15:00', '10:15:10', '10:15:20', '10:15:30', '10:15:40',\n               '10:15:50', '10:16:00', '10:16:10', '10:16:20', '10:16:30',\n               '10:16:40', '10:16:50', '10:17:00', '10:17:10', '10:17:20',\n               '10:17:30', '10:17:40', '10:17:50', '10:18:00', '10:18:10',\n               '10:18:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000, -1437831990, -1437831980, -1437831970, -1437831960,\n               -1437831950, -1437831940, -1437831930, -1437831920, -1437831910,\n               -1437831900, -1437831890, -1437831880, -1437831870, -1437831860,\n               -1437831850, -1437831840, -1437831830, -1437831820, -1437831810,\n               -1437831800, -1437831790, -1437831780, -1437831770, -1437831760,\n               -1437831750, -1437831740, -1437831730, -1437831720, -1437831710,\n               -1437831700])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 13, 12)),\n            [('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30'],\n              [-1437832050, -1437832020, -1437831990]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000]),\n             ('5 seconds',\n              ['10:12:30', '10:12:35', '10:12:40', '10:12:45', '10:12:50',\n               '10:12:55', '10:13:00', '10:13:05', '10:13:10', '10:13:15'],\n              [-1437832050, -1437832045, -1437832040, -1437832035, -1437832030,\n               -1437832025, -1437832020, -1437832015, -1437832010,\n               -1437832005]),\n             ('1 second',\n              ['10:12:33', '10:12:34', '10:12:35', '10:12:36', '10:12:37',\n               '10:12:38', '10:12:39', '10:12:40', '10:12:41', '10:12:42',\n               '10:12:43', '10:12:44', '10:12:45', '10:12:46', '10:12:47',\n               '10:12:48', '10:12:49', '10:12:50', '10:12:51', '10:12:52',\n               '10:12:53', '10:12:54', '10:12:55', '10:12:56', '10:12:57',\n               '10:12:58', '10:12:59', '10:13:00', '10:13:01', '10:13:02',\n               '10:13:03', '10:13:04', '10:13:05', '10:13:06', '10:13:07',\n               '10:13:08', '10:13:09', '10:13:10', '10:13:11', '10:13:12',\n               '10:13:13'],\n              [-1437832047, -1437832046, -1437832045, -1437832044, -1437832043,\n               -1437832042, -1437832041, -1437832040, -1437832039, -1437832038,\n               -1437832037, -1437832036, -1437832035, -1437832034, -1437832033,\n               -1437832032, -1437832031, -1437832030, -1437832029, -1437832028,\n               -1437832027, -1437832026, -1437832025, -1437832024, -1437832023,\n               -1437832022, -1437832021, -1437832020, -1437832019, -1437832018,\n               -1437832017, -1437832016, -1437832015, -1437832014, -1437832013,\n               -1437832012, -1437832011, -1437832010, -1437832009, -1437832008,\n               -1437832007])])\n\n        self.assertEqual(\n            testbin((1973, 9, 14), (2010, 9, 8)),\n            [\n                ('50 years',\n                 ['1950', '2000', '2050'],\n                 [-631152000, 946684800, 2524608000]),\n                ('25 years',\n                 ['1950', '1975', '2000', '2025'],\n                 [-631152000, 157766400, 946684800, 1735689600]),\n                ('10 years',\n                 ['1970', '1980', '1990', '2000', '2010', '2020'],\n                 [0, 315532800, 631152000, 946684800, 1262304000, 1577836800]),\n                ('5 years',\n                 ['1970', '1975', '1980', '1985', '1990', '1995', '2000',\n                  '2005', '2010', '2015'],\n                 [0, 157766400, 315532800, 473385600, 631152000, 788918400,\n                  946684800, 1104537600, 1262304000, 1420070400]),\n                ('2 years',\n                 ['1972', '1974', '1976', '1978', '1980', '1982', '1984',\n                  '1986', '1988', '1990', '1992', '1994', '1996', '1998',\n                  '2000', '2002', '2004', '2006', '2008', '2010', '2012'],\n                 [63072000, 126230400, 189302400, 252460800, 315532800,\n                  378691200, 441763200, 504921600, 567993600, 631152000,\n                  694224000, 757382400, 820454400, 883612800, 946684800,\n                  1009843200, 1072915200, 1136073600, 1199145600, 1262304000,\n                  1325376000]),\n                ('1 year',\n                 ['1973', '1974', '1975', '1976', '1977', '1978', '1979',\n                  '1980', '1981', '1982', '1983', '1984', '1985', '1986',\n                  '1987', '1988', '1989', '1990', '1991', '1992', '1993',\n                  '1994', '1995', '1996', '1997', '1998', '1999', '2000',\n                  '2001', '2002', '2003', '2004', '2005', '2006', '2007',\n                  '2008', '2009', '2010', '2011'],\n                 [94694400, 126230400, 157766400, 189302400, 220924800,\n                  252460800, 283996800, 315532800, 347155200, 378691200,\n                  410227200, 441763200, 473385600, 504921600, 536457600,\n                  567993600, 599616000, 631152000, 662688000, 694224000,\n                  725846400, 757382400, 788918400, 820454400, 852076800,\n                  883612800, 915148800, 946684800, 978307200, 1009843200,\n                  1041379200, 1072915200, 1104537600, 1136073600, 1167609600,\n                  1199145600, 1230768000, 1262304000, 1293840000])\n            ]\n        )\n\n    def test_min_unique(self):\n        bins = time_binnings(self.dates, min_unique=7)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_add_unique(self):\n        bins = time_binnings(self.dates, add_unique=7)\n        self.assertNotEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_limits(self):\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=17)},\n            {9, 17})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=16)},\n            {9})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=10, max_bins=17)},\n            {17})\n\n    def test_single_value(self):\n        dates = np.array([42])\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_multiple_identical(self):\n        dates = np.array([42] * 5)\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_no_values(self):\n        dates = np.array([])\n        self.assertRaises(ValueError, time_binnings, dates)\n\n        dates = np.array([np.nan, np.nan])\n        self.assertRaises(ValueError, time_binnings, dates)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 16,
                                "end_lineno": 715,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "Orange/preprocess/tests/test_discretize.py",
                            "type": "class",
                            "name": "TestTimeBinning",
                            "content": "class TestTimeBinning(unittest.TestCase):\n    def setUp(self):\n        self.dates = [mktime(x) for x in\n            [(1975, 6, 9, 10, 0, 0, 0, 161, 0),\n             (1975, 6, 9, 10, 50, 0, 0, 161, 0),\n             (1975, 6, 9, 11, 40, 0, 0, 161, 0),\n             (1975, 6, 9, 12, 30, 0, 0, 161, 0),\n             (1975, 6, 9, 13, 20, 0, 0, 161, 0),\n             (1975, 6, 9, 14, 10, 0, 0, 161, 0)]]\n\n    def test_binning(self):\n        def testbin(start, end):\n            bins = _time_binnings(create(*start), create(*end), 3, 51)\n            return [(bin.width_label, bin.short_labels, bin.thresholds)\n                    for bin in reversed(bins)]\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1989, 3, 1)),\n            [('10 years',\n              ['1970', '1980', '1990'],\n              [0, 315532800, 631152000]),\n             ('5 years',\n              ['1975', '1980', '1985', '1990'],\n              [157766400, 315532800, 473385600, 631152000]),\n             ('2 years',\n              ['1974', '1976', '1978', '1980', '1982', '1984', '1986', '1988',\n               '1990'],\n              [126230400, 189302400, 252460800, 315532800, 378691200, 441763200,\n               504921600, 567993600, 631152000]),\n             ('1 year',\n              ['1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982',\n               '1983', '1984', '1985', '1986', '1987', '1988', '1989', '1990'],\n              [157766400, 189302400, 220924800, 252460800, 283996800, 315532800,\n               347155200, 378691200, 410227200, 441763200, 473385600, 504921600,\n               536457600, 567993600, 599616000, 631152000]),\n             ('6 months',\n              ['75 Jan', 'Jul', '76 Jan', 'Jul', '77 Jan', 'Jul', '78 Jan',\n               'Jul', '79 Jan', 'Jul', '80 Jan', 'Jul', '81 Jan', 'Jul',\n               '82 Jan', 'Jul', '83 Jan', 'Jul', '84 Jan', 'Jul', '85 Jan',\n               'Jul', '86 Jan', 'Jul', '87 Jan', 'Jul', '88 Jan', 'Jul',\n               '89 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200, 283996800, 299635200, 315532800, 331257600,\n               347155200, 362793600, 378691200, 394329600, 410227200, 425865600,\n               441763200, 457488000, 473385600, 489024000, 504921600, 520560000,\n               536457600, 552096000, 567993600, 583718400, 599616000,\n               615254400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1978, 3, 1)),\n            [('2 years',\n              ['1974', '1976', '1978', '1980'],\n              [126230400, 189302400, 252460800, 315532800]),\n             ('1 year',\n              ['1975', '1976', '1977', '1978', '1979'],\n              [157766400, 189302400, 220924800, 252460800, 283996800]),\n             ('6 months',\n              ['75 Jan', 'Jul',\n               '76 Jan', 'Jul',\n               '77 Jan', 'Jul',\n               '78 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200]),\n             ('3 months',\n              ['75 Apr', 'Jul', 'Oct',\n               '76 Jan', 'Apr', 'Jul', 'Oct',\n               '77 Jan', 'Apr', 'Jul', 'Oct',\n               '78 Jan', 'Apr'],\n              [165542400, 173404800, 181353600, 189302400, 197164800, 205027200,\n               212976000, 220924800, 228700800, 236563200, 244512000, 252460800,\n               260236800]),\n             ('2 months',\n              ['75 Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '76 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '77 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '78 Jan', 'Mar', 'May'],\n              [162864000, 168134400, 173404800, 178761600, 184032000, 189302400,\n               194486400, 199756800, 205027200, 210384000, 215654400, 220924800,\n               226022400, 231292800, 236563200, 241920000, 247190400, 252460800,\n               257558400, 262828800]),\n             ('1 month',\n              ['75 Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '76 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '77 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '78 Jan', 'Feb', 'Mar', 'Apr'],\n              [165542400, 168134400, 170812800, 173404800, 176083200, 178761600,\n               181353600, 184032000, 186624000, 189302400, 191980800, 194486400,\n               197164800, 199756800, 202435200, 205027200, 207705600, 210384000,\n               212976000, 215654400, 218246400, 220924800, 223603200, 226022400,\n               228700800, 231292800, 233971200, 236563200, 239241600, 241920000,\n               244512000, 247190400, 249782400, 252460800, 255139200, 257558400,\n               260236800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 2), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('2 weeks',\n              ['75 Dec 03', '17', '31', '76 Jan 14'],\n              [186796800, 188006400, 189216000, 190425600]),\n             ('1 week',\n              ['75 Dec 03', '10', '17', '24', '31',\n               '76 Jan 07'],\n              [186796800, 187401600, 188006400, 188611200, 189216000,\n               189820800]),\n             ('1 day',\n              ['75 Dec 02', '03', '04', '05', '06', '07', '08', '09', '10',\n               '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21',\n               '22', '23', '24', '25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [186710400, 186796800, 186883200, 186969600, 187056000, 187142400,\n               187228800, 187315200, 187401600, 187488000, 187574400, 187660800,\n               187747200, 187833600, 187920000, 188006400, 188092800, 188179200,\n               188265600, 188352000, 188438400, 188524800, 188611200, 188697600,\n               188784000, 188870400, 188956800, 189043200, 189129600, 189216000,\n               189302400, 189388800, 189475200, 189561600])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 25), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [188697600, 188784000, 188870400, 188956800, 189043200, 189129600,\n               189216000, 189302400, 189388800, 189475200, 189561600]),\n             ('12 hours',\n              ['75 Dec 25 00:00', '12:00',\n               '26 00:00', '12:00',\n               '27 00:00', '12:00',\n               '28 00:00', '12:00',\n               '29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [188697600, 188740800, 188784000, 188827200, 188870400, 188913600,\n               188956800, 189000000, 189043200, 189086400, 189129600, 189172800,\n               189216000, 189259200, 189302400, 189345600, 189388800, 189432000,\n               189475200, 189518400]),\n             ('6 hours',\n              ['75 Dec 25 00:00', '06:00', '12:00', '18:00',\n               '26 00:00', '06:00', '12:00', '18:00',\n               '27 00:00', '06:00', '12:00', '18:00',\n               '28 00:00', '06:00', '12:00', '18:00',\n               '29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [188697600, 188719200, 188740800, 188762400, 188784000, 188805600,\n               188827200, 188848800, 188870400, 188892000, 188913600, 188935200,\n               188956800, 188978400, 189000000, 189021600, 189043200, 189064800,\n               189086400, 189108000, 189129600, 189151200, 189172800, 189194400,\n               189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200, 189388800, 189410400, 189432000, 189453600,\n               189475200, 189496800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 29), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [189043200, 189129600, 189216000, 189302400, 189388800, 189475200,\n               189561600]),\n             ('12 hours',\n              ['75 Dec 29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [189043200, 189086400, 189129600, 189172800, 189216000, 189259200,\n               189302400, 189345600, 189388800, 189432000, 189475200,\n               189518400]),\n             ('6 hours',\n              ['75 Dec 29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [189043200, 189064800, 189086400, 189108000, 189129600, 189151200,\n               189172800, 189194400, 189216000, 189237600, 189259200, 189280800,\n               189302400, 189324000, 189345600, 189367200, 189388800, 189410400,\n               189432000, 189453600, 189475200, 189496800]),\n             ('3 hours',\n              ['75 Dec 29 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '30 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '02 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '03 00:00', '03:00'],\n              [189043200, 189054000, 189064800, 189075600, 189086400, 189097200,\n               189108000, 189118800, 189129600, 189140400, 189151200, 189162000,\n               189172800, 189183600, 189194400, 189205200, 189216000, 189226800,\n               189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200, 189324000, 189334800, 189345600, 189356400,\n               189367200, 189378000, 189388800, 189399600, 189410400, 189421200,\n               189432000, 189442800, 189453600, 189464400, 189475200,\n               189486000])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 0, 0, 0), (1976, 1, 1, 14, 30)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00'],\n              [189216000, 189259200, 189302400, 189345600, 189388800]),\n             ('6 hours',\n              ['75 Dec 31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00'],\n              [189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200]),\n             ('3 hours',\n              ['75 Dec 31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00'],\n              [189216000, 189226800, 189237600, 189248400, 189259200, 189270000,\n               189280800, 189291600, 189302400, 189313200, 189324000, 189334800,\n               189345600, 189356400]),\n             ('2 hours',\n              ['75 Dec 31 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00'],\n              [189216000, 189223200, 189230400, 189237600, 189244800, 189252000,\n               189259200, 189266400, 189273600, 189280800, 189288000, 189295200,\n               189302400, 189309600, 189316800, 189324000, 189331200, 189338400,\n               189345600, 189352800, 189360000]),\n             ('1 hour',\n              ['75 Dec 31 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00',\n               '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00'],\n              [189216000, 189219600, 189223200, 189226800, 189230400, 189234000,\n               189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000, 189309600, 189313200, 189316800, 189320400,\n               189324000, 189327600, 189331200, 189334800, 189338400, 189342000,\n               189345600, 189349200, 189352800, 189356400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 6), (1976, 1, 1)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00'],\n              [189216000, 189259200, 189302400, 189345600]),\n             ('6 hours',\n              ['75 Dec 31 06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00'],\n              [189237600, 189259200, 189280800, 189302400, 189324000]),\n             ('3 hours',\n              ['75 Dec 31 06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00'],\n              [189237600, 189244800, 189252000, 189259200, 189266400, 189273600,\n               189280800, 189288000, 189295200, 189302400, 189309600]),\n             ('1 hour',\n              ['75 Dec 31 06:00', '07:00', '08:00', '09:00', '10:00', '11:00',\n               '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00',\n               '19:00', '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00'],\n              [189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000]),\n             ('30 minutes',\n              ['Dec 31 06:00', '06:30', '07:00', '07:30', '08:00', '08:30',\n               '09:00', '09:30', '10:00', '10:30', '11:00', '11:30', '12:00',\n               '12:30', '13:00', '13:30', '14:00', '14:30', '15:00', '15:30',\n               '16:00', '16:30', '17:00', '17:30', '18:00', '18:30', '19:00',\n               '19:30', '20:00', '20:30', '21:00', '21:30', '22:00', '22:30',\n               '23:00', '23:30',\n               'Jan 01 00:00', '00:30'],\n              [189237600, 189239400, 189241200, 189243000, 189244800, 189246600,\n               189248400, 189250200, 189252000, 189253800, 189255600, 189257400,\n               189259200, 189261000, 189262800, 189264600, 189266400, 189268200,\n               189270000, 189271800, 189273600, 189275400, 189277200, 189279000,\n               189280800, 189282600, 189284400, 189286200, 189288000, 189289800,\n               189291600, 189293400, 189295200, 189297000, 189298800, 189300600,\n               189302400, 189304200])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 23), (1976, 1, 1, 2)),\n            [('3 hours',\n              ['75 Dec 31 21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189291600, 189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 22:00',\n               '76 Jan 01 00:00', '02:00', '04:00'],\n              [189295200, 189302400, 189309600, 189316800]),\n             ('1 hour',\n              ['75 Dec 31 23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00'],\n              [189298800, 189302400, 189306000, 189309600, 189313200]),\n             ('30 minutes',\n              ['Dec 31 23:00', '23:30',\n               'Jan 01 00:00', '00:30', '01:00', '01:30', '02:00', '02:30'],\n              [189298800, 189300600, 189302400, 189304200, 189306000, 189307800,\n               189309600, 189311400]),\n             ('15 minutes',\n              ['Dec 31 23:00', '23:15', '23:30', '23:45',\n               'Jan 01 00:00', '00:15', '00:30', '00:45', '01:00', '01:15',\n               '01:30', '01:45', '02:00', '02:15'],\n              [189298800, 189299700, 189300600, 189301500, 189302400, 189303300,\n               189304200, 189305100, 189306000, 189306900, 189307800, 189308700,\n               189309600, 189310500]),\n             ('10 minutes',\n              ['Dec 31 23:00', '23:10', '23:20', '23:30', '23:40', '23:50',\n               'Jan 01 00:00', '00:10', '00:20', '00:30', '00:40', '00:50',\n               '01:00', '01:10', '01:20', '01:30', '01:40', '01:50', '02:00',\n               '02:10'],\n              [189298800, 189299400, 189300000, 189300600, 189301200, 189301800,\n               189302400, 189303000, 189303600, 189304200, 189304800, 189305400,\n               189306000, 189306600, 189307200, 189307800, 189308400, 189309000,\n               189309600, 189310200]),\n             ('5 minutes',\n              ['Dec 31 23:00', '23:05', '23:10', '23:15', '23:20', '23:25',\n               '23:30', '23:35', '23:40', '23:45', '23:50', '23:55',\n               'Jan 01 00:00', '00:05', '00:10', '00:15', '00:20', '00:25',\n               '00:30', '00:35', '00:40', '00:45', '00:50', '00:55', '01:00',\n               '01:05', '01:10', '01:15', '01:20', '01:25', '01:30', '01:35',\n               '01:40', '01:45', '01:50', '01:55', '02:00', '02:05'],\n              [189298800, 189299100, 189299400, 189299700, 189300000, 189300300,\n               189300600, 189300900, 189301200, 189301500, 189301800, 189302100,\n               189302400, 189302700, 189303000, 189303300, 189303600, 189303900,\n               189304200, 189304500, 189304800, 189305100, 189305400, 189305700,\n               189306000, 189306300, 189306600, 189306900, 189307200, 189307500,\n               189307800, 189308100, 189308400, 189308700, 189309000, 189309300,\n               189309600, 189309900])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 23, 18)),\n            [('12 hours',\n              ['Jun 09 00:00', '12:00', '10 00:00'],\n              [-1437868800, -1437825600, -1437782400]),\n             ('6 hours',\n              ['Jun 09 06:00', '12:00', '18:00', '10 00:00'],\n              [-1437847200, -1437825600, -1437804000, -1437782400]),\n             ('3 hours',\n              ['Jun 09 09:00', '12:00', '15:00', '18:00', '21:00', '10 00:00'],\n              [-1437836400, -1437825600, -1437814800, -1437804000, -1437793200,\n               -1437782400]),\n             ('2 hours',\n              ['Jun 09 10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00', '10 00:00'],\n              [-1437832800, -1437825600, -1437818400, -1437811200, -1437804000,\n               -1437796800, -1437789600, -1437782400]),\n             ('1 hour',\n              ['Jun 09 10:00', '11:00', '12:00', '13:00', '14:00', '15:00',\n               '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00',\n               '23:00',\n               '10 00:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000, -1437818400,\n               -1437814800, -1437811200, -1437807600, -1437804000, -1437800400,\n               -1437796800, -1437793200, -1437789600, -1437786000,\n               -1437782400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30', '14:00', '14:30', '15:00', '15:30', '16:00', '16:30',\n               '17:00', '17:30', '18:00', '18:30', '19:00', '19:30', '20:00',\n               '20:30', '21:00', '21:30', '22:00', '22:30', '23:00', '23:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200, -1437818400, -1437816600,\n               -1437814800, -1437813000, -1437811200, -1437809400, -1437807600,\n               -1437805800, -1437804000, -1437802200, -1437800400, -1437798600,\n               -1437796800, -1437795000, -1437793200, -1437791400, -1437789600,\n               -1437787800, -1437786000, -1437784200])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 13, 18)),\n            [('2 hours',\n              ['10:00', '12:00', '14:00'],\n              [-1437832800, -1437825600, -1437818400]),\n             ('1 hour',\n              ['10:00', '11:00', '12:00', '13:00', '14:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000,\n               -1437818400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00', '11:15', '11:30',\n               '11:45', '12:00', '12:15', '12:30', '12:45', '13:00', '13:15',\n               '13:30'],\n              [-1437832800, -1437831900, -1437831000, -1437830100, -1437829200,\n               -1437828300, -1437827400, -1437826500, -1437825600, -1437824700,\n               -1437823800, -1437822900, -1437822000, -1437821100,\n               -1437820200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50', '11:00',\n               '11:10', '11:20', '11:30', '11:40', '11:50', '12:00', '12:10',\n               '12:20', '12:30', '12:40', '12:50', '13:00', '13:10', '13:20'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800, -1437829200, -1437828600, -1437828000, -1437827400,\n               -1437826800, -1437826200, -1437825600, -1437825000, -1437824400,\n               -1437823800, -1437823200, -1437822600, -1437822000, -1437821400,\n               -1437820800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50', '10:55', '11:00', '11:05',\n               '11:10', '11:15', '11:20', '11:25', '11:30', '11:35', '11:40',\n               '11:45', '11:50', '11:55', '12:00', '12:05', '12:10', '12:15',\n               '12:20', '12:25', '12:30', '12:35', '12:40', '12:45', '12:50',\n               '12:55', '13:00', '13:05', '13:10', '13:15', '13:20'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800, -1437829500, -1437829200, -1437828900, -1437828600,\n               -1437828300, -1437828000, -1437827700, -1437827400, -1437827100,\n               -1437826800, -1437826500, -1437826200, -1437825900, -1437825600,\n               -1437825300, -1437825000, -1437824700, -1437824400, -1437824100,\n               -1437823800, -1437823500, -1437823200, -1437822900, -1437822600,\n               -1437822300, -1437822000, -1437821700, -1437821400, -1437821100,\n               -1437820800])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 48)),\n            [('30 minutes',\n              ['10:00', '10:30', '11:00'],\n              [-1437832800, -1437831000, -1437829200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00'],\n              [-1437832800, -1437831900, -1437831000, -1437830100,\n               -1437829200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21', '10:22', '10:23', '10:24', '10:25', '10:26', '10:27',\n               '10:28', '10:29', '10:30', '10:31', '10:32', '10:33', '10:34',\n               '10:35', '10:36', '10:37', '10:38', '10:39', '10:40', '10:41',\n               '10:42', '10:43', '10:44', '10:45', '10:46', '10:47', '10:48',\n               '10:49'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540, -1437831480, -1437831420, -1437831360,\n               -1437831300, -1437831240, -1437831180, -1437831120, -1437831060,\n               -1437831000, -1437830940, -1437830880, -1437830820, -1437830760,\n               -1437830700, -1437830640, -1437830580, -1437830520, -1437830460,\n               -1437830400, -1437830340, -1437830280, -1437830220, -1437830160,\n               -1437830100, -1437830040, -1437829980, -1437829920, -1437829860]\n              )]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 20)),\n            [('15 minutes',\n              ['10:00', '10:15', '10:30'],\n              [-1437832800, -1437831900, -1437831000]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30'],\n              [-1437832800, -1437832200, -1437831600, -1437831000]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540]),\n             ('30 seconds',\n              ['10:00:00', '10:00:30', '10:01:00', '10:01:30', '10:02:00',\n               '10:02:30', '10:03:00', '10:03:30', '10:04:00', '10:04:30',\n               '10:05:00', '10:05:30', '10:06:00', '10:06:30', '10:07:00',\n               '10:07:30', '10:08:00', '10:08:30', '10:09:00', '10:09:30',\n               '10:10:00', '10:10:30', '10:11:00', '10:11:30', '10:12:00',\n               '10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30', '10:19:00', '10:19:30',\n               '10:20:00', '10:20:30'],\n              [-1437832800, -1437832770, -1437832740, -1437832710, -1437832680,\n               -1437832650, -1437832620, -1437832590, -1437832560, -1437832530,\n               -1437832500, -1437832470, -1437832440, -1437832410, -1437832380,\n               -1437832350, -1437832320, -1437832290, -1437832260, -1437832230,\n               -1437832200, -1437832170, -1437832140, -1437832110, -1437832080,\n               -1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690, -1437831660, -1437831630,\n               -1437831600, -1437831570])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 18, 12)),\n            [('5 minutes',\n              ['10:10', '10:15', '10:20'],\n              [-1437832200, -1437831900, -1437831600]),\n             ('1 minute',\n              ['10:12', '10:13', '10:14', '10:15', '10:16', '10:17', '10:18',\n               '10:19'],\n              [-1437832080, -1437832020, -1437831960, -1437831900, -1437831840,\n               -1437831780, -1437831720, -1437831660]),\n             ('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30'],\n              [-1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15', '10:13:30',\n               '10:13:45', '10:14:00', '10:14:15', '10:14:30', '10:14:45',\n               '10:15:00', '10:15:15', '10:15:30', '10:15:45', '10:16:00',\n               '10:16:15', '10:16:30', '10:16:45', '10:17:00', '10:17:15',\n               '10:17:30', '10:17:45', '10:18:00', '10:18:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005, -1437831990,\n               -1437831975, -1437831960, -1437831945, -1437831930, -1437831915,\n               -1437831900, -1437831885, -1437831870, -1437831855, -1437831840,\n               -1437831825, -1437831810, -1437831795, -1437831780, -1437831765,\n               -1437831750, -1437831735, -1437831720, -1437831705]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20', '10:13:30', '10:13:40', '10:13:50', '10:14:00',\n               '10:14:10', '10:14:20', '10:14:30', '10:14:40', '10:14:50',\n               '10:15:00', '10:15:10', '10:15:20', '10:15:30', '10:15:40',\n               '10:15:50', '10:16:00', '10:16:10', '10:16:20', '10:16:30',\n               '10:16:40', '10:16:50', '10:17:00', '10:17:10', '10:17:20',\n               '10:17:30', '10:17:40', '10:17:50', '10:18:00', '10:18:10',\n               '10:18:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000, -1437831990, -1437831980, -1437831970, -1437831960,\n               -1437831950, -1437831940, -1437831930, -1437831920, -1437831910,\n               -1437831900, -1437831890, -1437831880, -1437831870, -1437831860,\n               -1437831850, -1437831840, -1437831830, -1437831820, -1437831810,\n               -1437831800, -1437831790, -1437831780, -1437831770, -1437831760,\n               -1437831750, -1437831740, -1437831730, -1437831720, -1437831710,\n               -1437831700])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 13, 12)),\n            [('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30'],\n              [-1437832050, -1437832020, -1437831990]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000]),\n             ('5 seconds',\n              ['10:12:30', '10:12:35', '10:12:40', '10:12:45', '10:12:50',\n               '10:12:55', '10:13:00', '10:13:05', '10:13:10', '10:13:15'],\n              [-1437832050, -1437832045, -1437832040, -1437832035, -1437832030,\n               -1437832025, -1437832020, -1437832015, -1437832010,\n               -1437832005]),\n             ('1 second',\n              ['10:12:33', '10:12:34', '10:12:35', '10:12:36', '10:12:37',\n               '10:12:38', '10:12:39', '10:12:40', '10:12:41', '10:12:42',\n               '10:12:43', '10:12:44', '10:12:45', '10:12:46', '10:12:47',\n               '10:12:48', '10:12:49', '10:12:50', '10:12:51', '10:12:52',\n               '10:12:53', '10:12:54', '10:12:55', '10:12:56', '10:12:57',\n               '10:12:58', '10:12:59', '10:13:00', '10:13:01', '10:13:02',\n               '10:13:03', '10:13:04', '10:13:05', '10:13:06', '10:13:07',\n               '10:13:08', '10:13:09', '10:13:10', '10:13:11', '10:13:12',\n               '10:13:13'],\n              [-1437832047, -1437832046, -1437832045, -1437832044, -1437832043,\n               -1437832042, -1437832041, -1437832040, -1437832039, -1437832038,\n               -1437832037, -1437832036, -1437832035, -1437832034, -1437832033,\n               -1437832032, -1437832031, -1437832030, -1437832029, -1437832028,\n               -1437832027, -1437832026, -1437832025, -1437832024, -1437832023,\n               -1437832022, -1437832021, -1437832020, -1437832019, -1437832018,\n               -1437832017, -1437832016, -1437832015, -1437832014, -1437832013,\n               -1437832012, -1437832011, -1437832010, -1437832009, -1437832008,\n               -1437832007])])\n\n        self.assertEqual(\n            testbin((1973, 9, 14), (2010, 9, 8)),\n            [\n                ('50 years',\n                 ['1950', '2000', '2050'],\n                 [-631152000, 946684800, 2524608000]),\n                ('25 years',\n                 ['1950', '1975', '2000', '2025'],\n                 [-631152000, 157766400, 946684800, 1735689600]),\n                ('10 years',\n                 ['1970', '1980', '1990', '2000', '2010', '2020'],\n                 [0, 315532800, 631152000, 946684800, 1262304000, 1577836800]),\n                ('5 years',\n                 ['1970', '1975', '1980', '1985', '1990', '1995', '2000',\n                  '2005', '2010', '2015'],\n                 [0, 157766400, 315532800, 473385600, 631152000, 788918400,\n                  946684800, 1104537600, 1262304000, 1420070400]),\n                ('2 years',\n                 ['1972', '1974', '1976', '1978', '1980', '1982', '1984',\n                  '1986', '1988', '1990', '1992', '1994', '1996', '1998',\n                  '2000', '2002', '2004', '2006', '2008', '2010', '2012'],\n                 [63072000, 126230400, 189302400, 252460800, 315532800,\n                  378691200, 441763200, 504921600, 567993600, 631152000,\n                  694224000, 757382400, 820454400, 883612800, 946684800,\n                  1009843200, 1072915200, 1136073600, 1199145600, 1262304000,\n                  1325376000]),\n                ('1 year',\n                 ['1973', '1974', '1975', '1976', '1977', '1978', '1979',\n                  '1980', '1981', '1982', '1983', '1984', '1985', '1986',\n                  '1987', '1988', '1989', '1990', '1991', '1992', '1993',\n                  '1994', '1995', '1996', '1997', '1998', '1999', '2000',\n                  '2001', '2002', '2003', '2004', '2005', '2006', '2007',\n                  '2008', '2009', '2010', '2011'],\n                 [94694400, 126230400, 157766400, 189302400, 220924800,\n                  252460800, 283996800, 315532800, 347155200, 378691200,\n                  410227200, 441763200, 473385600, 504921600, 536457600,\n                  567993600, 599616000, 631152000, 662688000, 694224000,\n                  725846400, 757382400, 788918400, 820454400, 852076800,\n                  883612800, 915148800, 946684800, 978307200, 1009843200,\n                  1041379200, 1072915200, 1104537600, 1136073600, 1167609600,\n                  1199145600, 1230768000, 1262304000, 1293840000])\n            ]\n        )\n\n    def test_min_unique(self):\n        bins = time_binnings(self.dates, min_unique=7)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_add_unique(self):\n        bins = time_binnings(self.dates, add_unique=7)\n        self.assertNotEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_limits(self):\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=17)},\n            {9, 17})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=16)},\n            {9})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=10, max_bins=17)},\n            {17})\n\n    def test_single_value(self):\n        dates = np.array([42])\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_multiple_identical(self):\n        dates = np.array([42] * 5)\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_no_values(self):\n        dates = np.array([])\n        self.assertRaises(ValueError, time_binnings, dates)\n\n        dates = np.array([np.nan, np.nan])\n        self.assertRaises(ValueError, time_binnings, dates)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 16,
                            "end_lineno": 715,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 656,
                            "length": 6
                        },
                        "new_range": {
                            "start": 701,
                            "length": 12
                        },
                        "section": "class TestTimeBinning(unittest.TestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        self.assertEqual(len(bins), 1)",
                                "type": "context"
                            },
                            {
                                "content": "        np.testing.assert_equal(bins[0].thresholds, [42, 43])",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    def test_multiple_identical(self):",
                                "type": "added"
                            },
                            {
                                "content": "        dates = np.array([42] * 5)",
                                "type": "added"
                            },
                            {
                                "content": "        bins = time_binnings(dates)",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertEqual(len(bins), 1)",
                                "type": "added"
                            },
                            {
                                "content": "        np.testing.assert_equal(bins[0].thresholds, [42, 43])",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    def test_no_values(self):",
                                "type": "context"
                            },
                            {
                                "content": "        dates = np.array([])",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertRaises(ValueError, time_binnings, dates)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/preprocess/tests/test_discretize.py",
                            "type": "class",
                            "name": "TestTimeBinning",
                            "content": "class TestTimeBinning(unittest.TestCase):\n    def setUp(self):\n        self.dates = [mktime(x) for x in\n            [(1975, 6, 9, 10, 0, 0, 0, 161, 0),\n             (1975, 6, 9, 10, 50, 0, 0, 161, 0),\n             (1975, 6, 9, 11, 40, 0, 0, 161, 0),\n             (1975, 6, 9, 12, 30, 0, 0, 161, 0),\n             (1975, 6, 9, 13, 20, 0, 0, 161, 0),\n             (1975, 6, 9, 14, 10, 0, 0, 161, 0)]]\n\n    def test_binning(self):\n        def testbin(start, end):\n            bins = _time_binnings(create(*start), create(*end), 3, 51)\n            return [(bin.width_label, bin.short_labels, bin.thresholds)\n                    for bin in reversed(bins)]\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1989, 3, 1)),\n            [('10 years',\n              ['1970', '1980', '1990'],\n              [0, 315532800, 631152000]),\n             ('5 years',\n              ['1975', '1980', '1985', '1990'],\n              [157766400, 315532800, 473385600, 631152000]),\n             ('2 years',\n              ['1974', '1976', '1978', '1980', '1982', '1984', '1986', '1988',\n               '1990'],\n              [126230400, 189302400, 252460800, 315532800, 378691200, 441763200,\n               504921600, 567993600, 631152000]),\n             ('1 year',\n              ['1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982',\n               '1983', '1984', '1985', '1986', '1987', '1988', '1989', '1990'],\n              [157766400, 189302400, 220924800, 252460800, 283996800, 315532800,\n               347155200, 378691200, 410227200, 441763200, 473385600, 504921600,\n               536457600, 567993600, 599616000, 631152000]),\n             ('6 months',\n              ['75 Jan', 'Jul', '76 Jan', 'Jul', '77 Jan', 'Jul', '78 Jan',\n               'Jul', '79 Jan', 'Jul', '80 Jan', 'Jul', '81 Jan', 'Jul',\n               '82 Jan', 'Jul', '83 Jan', 'Jul', '84 Jan', 'Jul', '85 Jan',\n               'Jul', '86 Jan', 'Jul', '87 Jan', 'Jul', '88 Jan', 'Jul',\n               '89 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200, 283996800, 299635200, 315532800, 331257600,\n               347155200, 362793600, 378691200, 394329600, 410227200, 425865600,\n               441763200, 457488000, 473385600, 489024000, 504921600, 520560000,\n               536457600, 552096000, 567993600, 583718400, 599616000,\n               615254400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1978, 3, 1)),\n            [('2 years',\n              ['1974', '1976', '1978', '1980'],\n              [126230400, 189302400, 252460800, 315532800]),\n             ('1 year',\n              ['1975', '1976', '1977', '1978', '1979'],\n              [157766400, 189302400, 220924800, 252460800, 283996800]),\n             ('6 months',\n              ['75 Jan', 'Jul',\n               '76 Jan', 'Jul',\n               '77 Jan', 'Jul',\n               '78 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200]),\n             ('3 months',\n              ['75 Apr', 'Jul', 'Oct',\n               '76 Jan', 'Apr', 'Jul', 'Oct',\n               '77 Jan', 'Apr', 'Jul', 'Oct',\n               '78 Jan', 'Apr'],\n              [165542400, 173404800, 181353600, 189302400, 197164800, 205027200,\n               212976000, 220924800, 228700800, 236563200, 244512000, 252460800,\n               260236800]),\n             ('2 months',\n              ['75 Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '76 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '77 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '78 Jan', 'Mar', 'May'],\n              [162864000, 168134400, 173404800, 178761600, 184032000, 189302400,\n               194486400, 199756800, 205027200, 210384000, 215654400, 220924800,\n               226022400, 231292800, 236563200, 241920000, 247190400, 252460800,\n               257558400, 262828800]),\n             ('1 month',\n              ['75 Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '76 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '77 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '78 Jan', 'Feb', 'Mar', 'Apr'],\n              [165542400, 168134400, 170812800, 173404800, 176083200, 178761600,\n               181353600, 184032000, 186624000, 189302400, 191980800, 194486400,\n               197164800, 199756800, 202435200, 205027200, 207705600, 210384000,\n               212976000, 215654400, 218246400, 220924800, 223603200, 226022400,\n               228700800, 231292800, 233971200, 236563200, 239241600, 241920000,\n               244512000, 247190400, 249782400, 252460800, 255139200, 257558400,\n               260236800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 2), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('2 weeks',\n              ['75 Dec 03', '17', '31', '76 Jan 14'],\n              [186796800, 188006400, 189216000, 190425600]),\n             ('1 week',\n              ['75 Dec 03', '10', '17', '24', '31',\n               '76 Jan 07'],\n              [186796800, 187401600, 188006400, 188611200, 189216000,\n               189820800]),\n             ('1 day',\n              ['75 Dec 02', '03', '04', '05', '06', '07', '08', '09', '10',\n               '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21',\n               '22', '23', '24', '25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [186710400, 186796800, 186883200, 186969600, 187056000, 187142400,\n               187228800, 187315200, 187401600, 187488000, 187574400, 187660800,\n               187747200, 187833600, 187920000, 188006400, 188092800, 188179200,\n               188265600, 188352000, 188438400, 188524800, 188611200, 188697600,\n               188784000, 188870400, 188956800, 189043200, 189129600, 189216000,\n               189302400, 189388800, 189475200, 189561600])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 25), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [188697600, 188784000, 188870400, 188956800, 189043200, 189129600,\n               189216000, 189302400, 189388800, 189475200, 189561600]),\n             ('12 hours',\n              ['75 Dec 25 00:00', '12:00',\n               '26 00:00', '12:00',\n               '27 00:00', '12:00',\n               '28 00:00', '12:00',\n               '29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [188697600, 188740800, 188784000, 188827200, 188870400, 188913600,\n               188956800, 189000000, 189043200, 189086400, 189129600, 189172800,\n               189216000, 189259200, 189302400, 189345600, 189388800, 189432000,\n               189475200, 189518400]),\n             ('6 hours',\n              ['75 Dec 25 00:00', '06:00', '12:00', '18:00',\n               '26 00:00', '06:00', '12:00', '18:00',\n               '27 00:00', '06:00', '12:00', '18:00',\n               '28 00:00', '06:00', '12:00', '18:00',\n               '29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [188697600, 188719200, 188740800, 188762400, 188784000, 188805600,\n               188827200, 188848800, 188870400, 188892000, 188913600, 188935200,\n               188956800, 188978400, 189000000, 189021600, 189043200, 189064800,\n               189086400, 189108000, 189129600, 189151200, 189172800, 189194400,\n               189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200, 189388800, 189410400, 189432000, 189453600,\n               189475200, 189496800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 29), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [189043200, 189129600, 189216000, 189302400, 189388800, 189475200,\n               189561600]),\n             ('12 hours',\n              ['75 Dec 29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [189043200, 189086400, 189129600, 189172800, 189216000, 189259200,\n               189302400, 189345600, 189388800, 189432000, 189475200,\n               189518400]),\n             ('6 hours',\n              ['75 Dec 29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [189043200, 189064800, 189086400, 189108000, 189129600, 189151200,\n               189172800, 189194400, 189216000, 189237600, 189259200, 189280800,\n               189302400, 189324000, 189345600, 189367200, 189388800, 189410400,\n               189432000, 189453600, 189475200, 189496800]),\n             ('3 hours',\n              ['75 Dec 29 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '30 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '02 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '03 00:00', '03:00'],\n              [189043200, 189054000, 189064800, 189075600, 189086400, 189097200,\n               189108000, 189118800, 189129600, 189140400, 189151200, 189162000,\n               189172800, 189183600, 189194400, 189205200, 189216000, 189226800,\n               189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200, 189324000, 189334800, 189345600, 189356400,\n               189367200, 189378000, 189388800, 189399600, 189410400, 189421200,\n               189432000, 189442800, 189453600, 189464400, 189475200,\n               189486000])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 0, 0, 0), (1976, 1, 1, 14, 30)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00'],\n              [189216000, 189259200, 189302400, 189345600, 189388800]),\n             ('6 hours',\n              ['75 Dec 31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00'],\n              [189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200]),\n             ('3 hours',\n              ['75 Dec 31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00'],\n              [189216000, 189226800, 189237600, 189248400, 189259200, 189270000,\n               189280800, 189291600, 189302400, 189313200, 189324000, 189334800,\n               189345600, 189356400]),\n             ('2 hours',\n              ['75 Dec 31 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00'],\n              [189216000, 189223200, 189230400, 189237600, 189244800, 189252000,\n               189259200, 189266400, 189273600, 189280800, 189288000, 189295200,\n               189302400, 189309600, 189316800, 189324000, 189331200, 189338400,\n               189345600, 189352800, 189360000]),\n             ('1 hour',\n              ['75 Dec 31 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00',\n               '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00'],\n              [189216000, 189219600, 189223200, 189226800, 189230400, 189234000,\n               189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000, 189309600, 189313200, 189316800, 189320400,\n               189324000, 189327600, 189331200, 189334800, 189338400, 189342000,\n               189345600, 189349200, 189352800, 189356400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 6), (1976, 1, 1)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00'],\n              [189216000, 189259200, 189302400, 189345600]),\n             ('6 hours',\n              ['75 Dec 31 06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00'],\n              [189237600, 189259200, 189280800, 189302400, 189324000]),\n             ('3 hours',\n              ['75 Dec 31 06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00'],\n              [189237600, 189244800, 189252000, 189259200, 189266400, 189273600,\n               189280800, 189288000, 189295200, 189302400, 189309600]),\n             ('1 hour',\n              ['75 Dec 31 06:00', '07:00', '08:00', '09:00', '10:00', '11:00',\n               '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00',\n               '19:00', '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00'],\n              [189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000]),\n             ('30 minutes',\n              ['Dec 31 06:00', '06:30', '07:00', '07:30', '08:00', '08:30',\n               '09:00', '09:30', '10:00', '10:30', '11:00', '11:30', '12:00',\n               '12:30', '13:00', '13:30', '14:00', '14:30', '15:00', '15:30',\n               '16:00', '16:30', '17:00', '17:30', '18:00', '18:30', '19:00',\n               '19:30', '20:00', '20:30', '21:00', '21:30', '22:00', '22:30',\n               '23:00', '23:30',\n               'Jan 01 00:00', '00:30'],\n              [189237600, 189239400, 189241200, 189243000, 189244800, 189246600,\n               189248400, 189250200, 189252000, 189253800, 189255600, 189257400,\n               189259200, 189261000, 189262800, 189264600, 189266400, 189268200,\n               189270000, 189271800, 189273600, 189275400, 189277200, 189279000,\n               189280800, 189282600, 189284400, 189286200, 189288000, 189289800,\n               189291600, 189293400, 189295200, 189297000, 189298800, 189300600,\n               189302400, 189304200])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 23), (1976, 1, 1, 2)),\n            [('3 hours',\n              ['75 Dec 31 21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189291600, 189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 22:00',\n               '76 Jan 01 00:00', '02:00', '04:00'],\n              [189295200, 189302400, 189309600, 189316800]),\n             ('1 hour',\n              ['75 Dec 31 23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00'],\n              [189298800, 189302400, 189306000, 189309600, 189313200]),\n             ('30 minutes',\n              ['Dec 31 23:00', '23:30',\n               'Jan 01 00:00', '00:30', '01:00', '01:30', '02:00', '02:30'],\n              [189298800, 189300600, 189302400, 189304200, 189306000, 189307800,\n               189309600, 189311400]),\n             ('15 minutes',\n              ['Dec 31 23:00', '23:15', '23:30', '23:45',\n               'Jan 01 00:00', '00:15', '00:30', '00:45', '01:00', '01:15',\n               '01:30', '01:45', '02:00', '02:15'],\n              [189298800, 189299700, 189300600, 189301500, 189302400, 189303300,\n               189304200, 189305100, 189306000, 189306900, 189307800, 189308700,\n               189309600, 189310500]),\n             ('10 minutes',\n              ['Dec 31 23:00', '23:10', '23:20', '23:30', '23:40', '23:50',\n               'Jan 01 00:00', '00:10', '00:20', '00:30', '00:40', '00:50',\n               '01:00', '01:10', '01:20', '01:30', '01:40', '01:50', '02:00',\n               '02:10'],\n              [189298800, 189299400, 189300000, 189300600, 189301200, 189301800,\n               189302400, 189303000, 189303600, 189304200, 189304800, 189305400,\n               189306000, 189306600, 189307200, 189307800, 189308400, 189309000,\n               189309600, 189310200]),\n             ('5 minutes',\n              ['Dec 31 23:00', '23:05', '23:10', '23:15', '23:20', '23:25',\n               '23:30', '23:35', '23:40', '23:45', '23:50', '23:55',\n               'Jan 01 00:00', '00:05', '00:10', '00:15', '00:20', '00:25',\n               '00:30', '00:35', '00:40', '00:45', '00:50', '00:55', '01:00',\n               '01:05', '01:10', '01:15', '01:20', '01:25', '01:30', '01:35',\n               '01:40', '01:45', '01:50', '01:55', '02:00', '02:05'],\n              [189298800, 189299100, 189299400, 189299700, 189300000, 189300300,\n               189300600, 189300900, 189301200, 189301500, 189301800, 189302100,\n               189302400, 189302700, 189303000, 189303300, 189303600, 189303900,\n               189304200, 189304500, 189304800, 189305100, 189305400, 189305700,\n               189306000, 189306300, 189306600, 189306900, 189307200, 189307500,\n               189307800, 189308100, 189308400, 189308700, 189309000, 189309300,\n               189309600, 189309900])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 23, 18)),\n            [('12 hours',\n              ['Jun 09 00:00', '12:00', '10 00:00'],\n              [-1437868800, -1437825600, -1437782400]),\n             ('6 hours',\n              ['Jun 09 06:00', '12:00', '18:00', '10 00:00'],\n              [-1437847200, -1437825600, -1437804000, -1437782400]),\n             ('3 hours',\n              ['Jun 09 09:00', '12:00', '15:00', '18:00', '21:00', '10 00:00'],\n              [-1437836400, -1437825600, -1437814800, -1437804000, -1437793200,\n               -1437782400]),\n             ('2 hours',\n              ['Jun 09 10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00', '10 00:00'],\n              [-1437832800, -1437825600, -1437818400, -1437811200, -1437804000,\n               -1437796800, -1437789600, -1437782400]),\n             ('1 hour',\n              ['Jun 09 10:00', '11:00', '12:00', '13:00', '14:00', '15:00',\n               '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00',\n               '23:00',\n               '10 00:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000, -1437818400,\n               -1437814800, -1437811200, -1437807600, -1437804000, -1437800400,\n               -1437796800, -1437793200, -1437789600, -1437786000,\n               -1437782400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30', '14:00', '14:30', '15:00', '15:30', '16:00', '16:30',\n               '17:00', '17:30', '18:00', '18:30', '19:00', '19:30', '20:00',\n               '20:30', '21:00', '21:30', '22:00', '22:30', '23:00', '23:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200, -1437818400, -1437816600,\n               -1437814800, -1437813000, -1437811200, -1437809400, -1437807600,\n               -1437805800, -1437804000, -1437802200, -1437800400, -1437798600,\n               -1437796800, -1437795000, -1437793200, -1437791400, -1437789600,\n               -1437787800, -1437786000, -1437784200])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 13, 18)),\n            [('2 hours',\n              ['10:00', '12:00', '14:00'],\n              [-1437832800, -1437825600, -1437818400]),\n             ('1 hour',\n              ['10:00', '11:00', '12:00', '13:00', '14:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000,\n               -1437818400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00', '11:15', '11:30',\n               '11:45', '12:00', '12:15', '12:30', '12:45', '13:00', '13:15',\n               '13:30'],\n              [-1437832800, -1437831900, -1437831000, -1437830100, -1437829200,\n               -1437828300, -1437827400, -1437826500, -1437825600, -1437824700,\n               -1437823800, -1437822900, -1437822000, -1437821100,\n               -1437820200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50', '11:00',\n               '11:10', '11:20', '11:30', '11:40', '11:50', '12:00', '12:10',\n               '12:20', '12:30', '12:40', '12:50', '13:00', '13:10', '13:20'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800, -1437829200, -1437828600, -1437828000, -1437827400,\n               -1437826800, -1437826200, -1437825600, -1437825000, -1437824400,\n               -1437823800, -1437823200, -1437822600, -1437822000, -1437821400,\n               -1437820800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50', '10:55', '11:00', '11:05',\n               '11:10', '11:15', '11:20', '11:25', '11:30', '11:35', '11:40',\n               '11:45', '11:50', '11:55', '12:00', '12:05', '12:10', '12:15',\n               '12:20', '12:25', '12:30', '12:35', '12:40', '12:45', '12:50',\n               '12:55', '13:00', '13:05', '13:10', '13:15', '13:20'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800, -1437829500, -1437829200, -1437828900, -1437828600,\n               -1437828300, -1437828000, -1437827700, -1437827400, -1437827100,\n               -1437826800, -1437826500, -1437826200, -1437825900, -1437825600,\n               -1437825300, -1437825000, -1437824700, -1437824400, -1437824100,\n               -1437823800, -1437823500, -1437823200, -1437822900, -1437822600,\n               -1437822300, -1437822000, -1437821700, -1437821400, -1437821100,\n               -1437820800])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 48)),\n            [('30 minutes',\n              ['10:00', '10:30', '11:00'],\n              [-1437832800, -1437831000, -1437829200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00'],\n              [-1437832800, -1437831900, -1437831000, -1437830100,\n               -1437829200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21', '10:22', '10:23', '10:24', '10:25', '10:26', '10:27',\n               '10:28', '10:29', '10:30', '10:31', '10:32', '10:33', '10:34',\n               '10:35', '10:36', '10:37', '10:38', '10:39', '10:40', '10:41',\n               '10:42', '10:43', '10:44', '10:45', '10:46', '10:47', '10:48',\n               '10:49'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540, -1437831480, -1437831420, -1437831360,\n               -1437831300, -1437831240, -1437831180, -1437831120, -1437831060,\n               -1437831000, -1437830940, -1437830880, -1437830820, -1437830760,\n               -1437830700, -1437830640, -1437830580, -1437830520, -1437830460,\n               -1437830400, -1437830340, -1437830280, -1437830220, -1437830160,\n               -1437830100, -1437830040, -1437829980, -1437829920, -1437829860]\n              )]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 20)),\n            [('15 minutes',\n              ['10:00', '10:15', '10:30'],\n              [-1437832800, -1437831900, -1437831000]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30'],\n              [-1437832800, -1437832200, -1437831600, -1437831000]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540]),\n             ('30 seconds',\n              ['10:00:00', '10:00:30', '10:01:00', '10:01:30', '10:02:00',\n               '10:02:30', '10:03:00', '10:03:30', '10:04:00', '10:04:30',\n               '10:05:00', '10:05:30', '10:06:00', '10:06:30', '10:07:00',\n               '10:07:30', '10:08:00', '10:08:30', '10:09:00', '10:09:30',\n               '10:10:00', '10:10:30', '10:11:00', '10:11:30', '10:12:00',\n               '10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30', '10:19:00', '10:19:30',\n               '10:20:00', '10:20:30'],\n              [-1437832800, -1437832770, -1437832740, -1437832710, -1437832680,\n               -1437832650, -1437832620, -1437832590, -1437832560, -1437832530,\n               -1437832500, -1437832470, -1437832440, -1437832410, -1437832380,\n               -1437832350, -1437832320, -1437832290, -1437832260, -1437832230,\n               -1437832200, -1437832170, -1437832140, -1437832110, -1437832080,\n               -1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690, -1437831660, -1437831630,\n               -1437831600, -1437831570])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 18, 12)),\n            [('5 minutes',\n              ['10:10', '10:15', '10:20'],\n              [-1437832200, -1437831900, -1437831600]),\n             ('1 minute',\n              ['10:12', '10:13', '10:14', '10:15', '10:16', '10:17', '10:18',\n               '10:19'],\n              [-1437832080, -1437832020, -1437831960, -1437831900, -1437831840,\n               -1437831780, -1437831720, -1437831660]),\n             ('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30'],\n              [-1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15', '10:13:30',\n               '10:13:45', '10:14:00', '10:14:15', '10:14:30', '10:14:45',\n               '10:15:00', '10:15:15', '10:15:30', '10:15:45', '10:16:00',\n               '10:16:15', '10:16:30', '10:16:45', '10:17:00', '10:17:15',\n               '10:17:30', '10:17:45', '10:18:00', '10:18:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005, -1437831990,\n               -1437831975, -1437831960, -1437831945, -1437831930, -1437831915,\n               -1437831900, -1437831885, -1437831870, -1437831855, -1437831840,\n               -1437831825, -1437831810, -1437831795, -1437831780, -1437831765,\n               -1437831750, -1437831735, -1437831720, -1437831705]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20', '10:13:30', '10:13:40', '10:13:50', '10:14:00',\n               '10:14:10', '10:14:20', '10:14:30', '10:14:40', '10:14:50',\n               '10:15:00', '10:15:10', '10:15:20', '10:15:30', '10:15:40',\n               '10:15:50', '10:16:00', '10:16:10', '10:16:20', '10:16:30',\n               '10:16:40', '10:16:50', '10:17:00', '10:17:10', '10:17:20',\n               '10:17:30', '10:17:40', '10:17:50', '10:18:00', '10:18:10',\n               '10:18:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000, -1437831990, -1437831980, -1437831970, -1437831960,\n               -1437831950, -1437831940, -1437831930, -1437831920, -1437831910,\n               -1437831900, -1437831890, -1437831880, -1437831870, -1437831860,\n               -1437831850, -1437831840, -1437831830, -1437831820, -1437831810,\n               -1437831800, -1437831790, -1437831780, -1437831770, -1437831760,\n               -1437831750, -1437831740, -1437831730, -1437831720, -1437831710,\n               -1437831700])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 13, 12)),\n            [('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30'],\n              [-1437832050, -1437832020, -1437831990]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000]),\n             ('5 seconds',\n              ['10:12:30', '10:12:35', '10:12:40', '10:12:45', '10:12:50',\n               '10:12:55', '10:13:00', '10:13:05', '10:13:10', '10:13:15'],\n              [-1437832050, -1437832045, -1437832040, -1437832035, -1437832030,\n               -1437832025, -1437832020, -1437832015, -1437832010,\n               -1437832005]),\n             ('1 second',\n              ['10:12:33', '10:12:34', '10:12:35', '10:12:36', '10:12:37',\n               '10:12:38', '10:12:39', '10:12:40', '10:12:41', '10:12:42',\n               '10:12:43', '10:12:44', '10:12:45', '10:12:46', '10:12:47',\n               '10:12:48', '10:12:49', '10:12:50', '10:12:51', '10:12:52',\n               '10:12:53', '10:12:54', '10:12:55', '10:12:56', '10:12:57',\n               '10:12:58', '10:12:59', '10:13:00', '10:13:01', '10:13:02',\n               '10:13:03', '10:13:04', '10:13:05', '10:13:06', '10:13:07',\n               '10:13:08', '10:13:09', '10:13:10', '10:13:11', '10:13:12',\n               '10:13:13'],\n              [-1437832047, -1437832046, -1437832045, -1437832044, -1437832043,\n               -1437832042, -1437832041, -1437832040, -1437832039, -1437832038,\n               -1437832037, -1437832036, -1437832035, -1437832034, -1437832033,\n               -1437832032, -1437832031, -1437832030, -1437832029, -1437832028,\n               -1437832027, -1437832026, -1437832025, -1437832024, -1437832023,\n               -1437832022, -1437832021, -1437832020, -1437832019, -1437832018,\n               -1437832017, -1437832016, -1437832015, -1437832014, -1437832013,\n               -1437832012, -1437832011, -1437832010, -1437832009, -1437832008,\n               -1437832007])])\n\n        self.assertEqual(\n            testbin((1973, 9, 14), (2010, 9, 8)),\n            [\n                ('50 years',\n                 ['1950', '2000', '2050'],\n                 [-631152000, 946684800, 2524608000]),\n                ('25 years',\n                 ['1950', '1975', '2000', '2025'],\n                 [-631152000, 157766400, 946684800, 1735689600]),\n                ('10 years',\n                 ['1970', '1980', '1990', '2000', '2010', '2020'],\n                 [0, 315532800, 631152000, 946684800, 1262304000, 1577836800]),\n                ('5 years',\n                 ['1970', '1975', '1980', '1985', '1990', '1995', '2000',\n                  '2005', '2010', '2015'],\n                 [0, 157766400, 315532800, 473385600, 631152000, 788918400,\n                  946684800, 1104537600, 1262304000, 1420070400]),\n                ('2 years',\n                 ['1972', '1974', '1976', '1978', '1980', '1982', '1984',\n                  '1986', '1988', '1990', '1992', '1994', '1996', '1998',\n                  '2000', '2002', '2004', '2006', '2008', '2010', '2012'],\n                 [63072000, 126230400, 189302400, 252460800, 315532800,\n                  378691200, 441763200, 504921600, 567993600, 631152000,\n                  694224000, 757382400, 820454400, 883612800, 946684800,\n                  1009843200, 1072915200, 1136073600, 1199145600, 1262304000,\n                  1325376000]),\n                ('1 year',\n                 ['1973', '1974', '1975', '1976', '1977', '1978', '1979',\n                  '1980', '1981', '1982', '1983', '1984', '1985', '1986',\n                  '1987', '1988', '1989', '1990', '1991', '1992', '1993',\n                  '1994', '1995', '1996', '1997', '1998', '1999', '2000',\n                  '2001', '2002', '2003', '2004', '2005', '2006', '2007',\n                  '2008', '2009', '2010', '2011'],\n                 [94694400, 126230400, 157766400, 189302400, 220924800,\n                  252460800, 283996800, 315532800, 347155200, 378691200,\n                  410227200, 441763200, 473385600, 504921600, 536457600,\n                  567993600, 599616000, 631152000, 662688000, 694224000,\n                  725846400, 757382400, 788918400, 820454400, 852076800,\n                  883612800, 915148800, 946684800, 978307200, 1009843200,\n                  1041379200, 1072915200, 1104537600, 1136073600, 1167609600,\n                  1199145600, 1230768000, 1262304000, 1293840000])\n            ]\n        )\n\n    def test_min_unique(self):\n        bins = time_binnings(self.dates, min_unique=7)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_add_unique(self):\n        bins = time_binnings(self.dates, add_unique=7)\n        self.assertNotEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_limits(self):\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=17)},\n            {9, 17})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=16)},\n            {9})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=10, max_bins=17)},\n            {17})\n\n    def test_single_value(self):\n        dates = np.array([42])\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_multiple_identical(self):\n        dates = np.array([42] * 5)\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_no_values(self):\n        dates = np.array([])\n        self.assertRaises(ValueError, time_binnings, dates)\n\n        dates = np.array([np.nan, np.nan])\n        self.assertRaises(ValueError, time_binnings, dates)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 16,
                            "end_lineno": 715,
                            "parent": null
                        }
                    ],
                    "added_entities": [
                        {
                            "file_name": "Orange/preprocess/tests/test_discretize.py",
                            "type": "method",
                            "name": "TestTimeBinning.test_multiple_identical",
                            "content": "class TestTimeBinning(unittest.TestCase):\n    def setUp(self):\n        self.dates = [mktime(x) for x in\n            [(1975, 6, 9, 10, 0, 0, 0, 161, 0),\n             (1975, 6, 9, 10, 50, 0, 0, 161, 0),\n             (1975, 6, 9, 11, 40, 0, 0, 161, 0),\n             (1975, 6, 9, 12, 30, 0, 0, 161, 0),\n             (1975, 6, 9, 13, 20, 0, 0, 161, 0),\n             (1975, 6, 9, 14, 10, 0, 0, 161, 0)]]\n\n    def test_binning(self):\n        def testbin(start, end):\n            bins = _time_binnings(create(*start), create(*end), 3, 51)\n            return [(bin.width_label, bin.short_labels, bin.thresholds)\n                    for bin in reversed(bins)]\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1989, 3, 1)),\n            [('10 years',\n              ['1970', '1980', '1990'],\n              [0, 315532800, 631152000]),\n             ('5 years',\n              ['1975', '1980', '1985', '1990'],\n              [157766400, 315532800, 473385600, 631152000]),\n             ('2 years',\n              ['1974', '1976', '1978', '1980', '1982', '1984', '1986', '1988',\n               '1990'],\n              [126230400, 189302400, 252460800, 315532800, 378691200, 441763200,\n               504921600, 567993600, 631152000]),\n             ('1 year',\n              ['1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982',\n               '1983', '1984', '1985', '1986', '1987', '1988', '1989', '1990'],\n              [157766400, 189302400, 220924800, 252460800, 283996800, 315532800,\n               347155200, 378691200, 410227200, 441763200, 473385600, 504921600,\n               536457600, 567993600, 599616000, 631152000]),\n             ('6 months',\n              ['75 Jan', 'Jul', '76 Jan', 'Jul', '77 Jan', 'Jul', '78 Jan',\n               'Jul', '79 Jan', 'Jul', '80 Jan', 'Jul', '81 Jan', 'Jul',\n               '82 Jan', 'Jul', '83 Jan', 'Jul', '84 Jan', 'Jul', '85 Jan',\n               'Jul', '86 Jan', 'Jul', '87 Jan', 'Jul', '88 Jan', 'Jul',\n               '89 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200, 283996800, 299635200, 315532800, 331257600,\n               347155200, 362793600, 378691200, 394329600, 410227200, 425865600,\n               441763200, 457488000, 473385600, 489024000, 504921600, 520560000,\n               536457600, 552096000, 567993600, 583718400, 599616000,\n               615254400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1978, 3, 1)),\n            [('2 years',\n              ['1974', '1976', '1978', '1980'],\n              [126230400, 189302400, 252460800, 315532800]),\n             ('1 year',\n              ['1975', '1976', '1977', '1978', '1979'],\n              [157766400, 189302400, 220924800, 252460800, 283996800]),\n             ('6 months',\n              ['75 Jan', 'Jul',\n               '76 Jan', 'Jul',\n               '77 Jan', 'Jul',\n               '78 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200]),\n             ('3 months',\n              ['75 Apr', 'Jul', 'Oct',\n               '76 Jan', 'Apr', 'Jul', 'Oct',\n               '77 Jan', 'Apr', 'Jul', 'Oct',\n               '78 Jan', 'Apr'],\n              [165542400, 173404800, 181353600, 189302400, 197164800, 205027200,\n               212976000, 220924800, 228700800, 236563200, 244512000, 252460800,\n               260236800]),\n             ('2 months',\n              ['75 Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '76 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '77 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '78 Jan', 'Mar', 'May'],\n              [162864000, 168134400, 173404800, 178761600, 184032000, 189302400,\n               194486400, 199756800, 205027200, 210384000, 215654400, 220924800,\n               226022400, 231292800, 236563200, 241920000, 247190400, 252460800,\n               257558400, 262828800]),\n             ('1 month',\n              ['75 Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '76 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '77 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '78 Jan', 'Feb', 'Mar', 'Apr'],\n              [165542400, 168134400, 170812800, 173404800, 176083200, 178761600,\n               181353600, 184032000, 186624000, 189302400, 191980800, 194486400,\n               197164800, 199756800, 202435200, 205027200, 207705600, 210384000,\n               212976000, 215654400, 218246400, 220924800, 223603200, 226022400,\n               228700800, 231292800, 233971200, 236563200, 239241600, 241920000,\n               244512000, 247190400, 249782400, 252460800, 255139200, 257558400,\n               260236800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 2), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('2 weeks',\n              ['75 Dec 03', '17', '31', '76 Jan 14'],\n              [186796800, 188006400, 189216000, 190425600]),\n             ('1 week',\n              ['75 Dec 03', '10', '17', '24', '31',\n               '76 Jan 07'],\n              [186796800, 187401600, 188006400, 188611200, 189216000,\n               189820800]),\n             ('1 day',\n              ['75 Dec 02', '03', '04', '05', '06', '07', '08', '09', '10',\n               '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21',\n               '22', '23', '24', '25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [186710400, 186796800, 186883200, 186969600, 187056000, 187142400,\n               187228800, 187315200, 187401600, 187488000, 187574400, 187660800,\n               187747200, 187833600, 187920000, 188006400, 188092800, 188179200,\n               188265600, 188352000, 188438400, 188524800, 188611200, 188697600,\n               188784000, 188870400, 188956800, 189043200, 189129600, 189216000,\n               189302400, 189388800, 189475200, 189561600])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 25), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [188697600, 188784000, 188870400, 188956800, 189043200, 189129600,\n               189216000, 189302400, 189388800, 189475200, 189561600]),\n             ('12 hours',\n              ['75 Dec 25 00:00', '12:00',\n               '26 00:00', '12:00',\n               '27 00:00', '12:00',\n               '28 00:00', '12:00',\n               '29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [188697600, 188740800, 188784000, 188827200, 188870400, 188913600,\n               188956800, 189000000, 189043200, 189086400, 189129600, 189172800,\n               189216000, 189259200, 189302400, 189345600, 189388800, 189432000,\n               189475200, 189518400]),\n             ('6 hours',\n              ['75 Dec 25 00:00', '06:00', '12:00', '18:00',\n               '26 00:00', '06:00', '12:00', '18:00',\n               '27 00:00', '06:00', '12:00', '18:00',\n               '28 00:00', '06:00', '12:00', '18:00',\n               '29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [188697600, 188719200, 188740800, 188762400, 188784000, 188805600,\n               188827200, 188848800, 188870400, 188892000, 188913600, 188935200,\n               188956800, 188978400, 189000000, 189021600, 189043200, 189064800,\n               189086400, 189108000, 189129600, 189151200, 189172800, 189194400,\n               189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200, 189388800, 189410400, 189432000, 189453600,\n               189475200, 189496800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 29), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [189043200, 189129600, 189216000, 189302400, 189388800, 189475200,\n               189561600]),\n             ('12 hours',\n              ['75 Dec 29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [189043200, 189086400, 189129600, 189172800, 189216000, 189259200,\n               189302400, 189345600, 189388800, 189432000, 189475200,\n               189518400]),\n             ('6 hours',\n              ['75 Dec 29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [189043200, 189064800, 189086400, 189108000, 189129600, 189151200,\n               189172800, 189194400, 189216000, 189237600, 189259200, 189280800,\n               189302400, 189324000, 189345600, 189367200, 189388800, 189410400,\n               189432000, 189453600, 189475200, 189496800]),\n             ('3 hours',\n              ['75 Dec 29 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '30 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '02 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '03 00:00', '03:00'],\n              [189043200, 189054000, 189064800, 189075600, 189086400, 189097200,\n               189108000, 189118800, 189129600, 189140400, 189151200, 189162000,\n               189172800, 189183600, 189194400, 189205200, 189216000, 189226800,\n               189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200, 189324000, 189334800, 189345600, 189356400,\n               189367200, 189378000, 189388800, 189399600, 189410400, 189421200,\n               189432000, 189442800, 189453600, 189464400, 189475200,\n               189486000])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 0, 0, 0), (1976, 1, 1, 14, 30)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00'],\n              [189216000, 189259200, 189302400, 189345600, 189388800]),\n             ('6 hours',\n              ['75 Dec 31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00'],\n              [189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200]),\n             ('3 hours',\n              ['75 Dec 31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00'],\n              [189216000, 189226800, 189237600, 189248400, 189259200, 189270000,\n               189280800, 189291600, 189302400, 189313200, 189324000, 189334800,\n               189345600, 189356400]),\n             ('2 hours',\n              ['75 Dec 31 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00'],\n              [189216000, 189223200, 189230400, 189237600, 189244800, 189252000,\n               189259200, 189266400, 189273600, 189280800, 189288000, 189295200,\n               189302400, 189309600, 189316800, 189324000, 189331200, 189338400,\n               189345600, 189352800, 189360000]),\n             ('1 hour',\n              ['75 Dec 31 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00',\n               '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00'],\n              [189216000, 189219600, 189223200, 189226800, 189230400, 189234000,\n               189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000, 189309600, 189313200, 189316800, 189320400,\n               189324000, 189327600, 189331200, 189334800, 189338400, 189342000,\n               189345600, 189349200, 189352800, 189356400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 6), (1976, 1, 1)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00'],\n              [189216000, 189259200, 189302400, 189345600]),\n             ('6 hours',\n              ['75 Dec 31 06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00'],\n              [189237600, 189259200, 189280800, 189302400, 189324000]),\n             ('3 hours',\n              ['75 Dec 31 06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00'],\n              [189237600, 189244800, 189252000, 189259200, 189266400, 189273600,\n               189280800, 189288000, 189295200, 189302400, 189309600]),\n             ('1 hour',\n              ['75 Dec 31 06:00', '07:00', '08:00', '09:00', '10:00', '11:00',\n               '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00',\n               '19:00', '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00'],\n              [189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000]),\n             ('30 minutes',\n              ['Dec 31 06:00', '06:30', '07:00', '07:30', '08:00', '08:30',\n               '09:00', '09:30', '10:00', '10:30', '11:00', '11:30', '12:00',\n               '12:30', '13:00', '13:30', '14:00', '14:30', '15:00', '15:30',\n               '16:00', '16:30', '17:00', '17:30', '18:00', '18:30', '19:00',\n               '19:30', '20:00', '20:30', '21:00', '21:30', '22:00', '22:30',\n               '23:00', '23:30',\n               'Jan 01 00:00', '00:30'],\n              [189237600, 189239400, 189241200, 189243000, 189244800, 189246600,\n               189248400, 189250200, 189252000, 189253800, 189255600, 189257400,\n               189259200, 189261000, 189262800, 189264600, 189266400, 189268200,\n               189270000, 189271800, 189273600, 189275400, 189277200, 189279000,\n               189280800, 189282600, 189284400, 189286200, 189288000, 189289800,\n               189291600, 189293400, 189295200, 189297000, 189298800, 189300600,\n               189302400, 189304200])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 23), (1976, 1, 1, 2)),\n            [('3 hours',\n              ['75 Dec 31 21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189291600, 189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 22:00',\n               '76 Jan 01 00:00', '02:00', '04:00'],\n              [189295200, 189302400, 189309600, 189316800]),\n             ('1 hour',\n              ['75 Dec 31 23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00'],\n              [189298800, 189302400, 189306000, 189309600, 189313200]),\n             ('30 minutes',\n              ['Dec 31 23:00', '23:30',\n               'Jan 01 00:00', '00:30', '01:00', '01:30', '02:00', '02:30'],\n              [189298800, 189300600, 189302400, 189304200, 189306000, 189307800,\n               189309600, 189311400]),\n             ('15 minutes',\n              ['Dec 31 23:00', '23:15', '23:30', '23:45',\n               'Jan 01 00:00', '00:15', '00:30', '00:45', '01:00', '01:15',\n               '01:30', '01:45', '02:00', '02:15'],\n              [189298800, 189299700, 189300600, 189301500, 189302400, 189303300,\n               189304200, 189305100, 189306000, 189306900, 189307800, 189308700,\n               189309600, 189310500]),\n             ('10 minutes',\n              ['Dec 31 23:00', '23:10', '23:20', '23:30', '23:40', '23:50',\n               'Jan 01 00:00', '00:10', '00:20', '00:30', '00:40', '00:50',\n               '01:00', '01:10', '01:20', '01:30', '01:40', '01:50', '02:00',\n               '02:10'],\n              [189298800, 189299400, 189300000, 189300600, 189301200, 189301800,\n               189302400, 189303000, 189303600, 189304200, 189304800, 189305400,\n               189306000, 189306600, 189307200, 189307800, 189308400, 189309000,\n               189309600, 189310200]),\n             ('5 minutes',\n              ['Dec 31 23:00', '23:05', '23:10', '23:15', '23:20', '23:25',\n               '23:30', '23:35', '23:40', '23:45', '23:50', '23:55',\n               'Jan 01 00:00', '00:05', '00:10', '00:15', '00:20', '00:25',\n               '00:30', '00:35', '00:40', '00:45', '00:50', '00:55', '01:00',\n               '01:05', '01:10', '01:15', '01:20', '01:25', '01:30', '01:35',\n               '01:40', '01:45', '01:50', '01:55', '02:00', '02:05'],\n              [189298800, 189299100, 189299400, 189299700, 189300000, 189300300,\n               189300600, 189300900, 189301200, 189301500, 189301800, 189302100,\n               189302400, 189302700, 189303000, 189303300, 189303600, 189303900,\n               189304200, 189304500, 189304800, 189305100, 189305400, 189305700,\n               189306000, 189306300, 189306600, 189306900, 189307200, 189307500,\n               189307800, 189308100, 189308400, 189308700, 189309000, 189309300,\n               189309600, 189309900])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 23, 18)),\n            [('12 hours',\n              ['Jun 09 00:00', '12:00', '10 00:00'],\n              [-1437868800, -1437825600, -1437782400]),\n             ('6 hours',\n              ['Jun 09 06:00', '12:00', '18:00', '10 00:00'],\n              [-1437847200, -1437825600, -1437804000, -1437782400]),\n             ('3 hours',\n              ['Jun 09 09:00', '12:00', '15:00', '18:00', '21:00', '10 00:00'],\n              [-1437836400, -1437825600, -1437814800, -1437804000, -1437793200,\n               -1437782400]),\n             ('2 hours',\n              ['Jun 09 10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00', '10 00:00'],\n              [-1437832800, -1437825600, -1437818400, -1437811200, -1437804000,\n               -1437796800, -1437789600, -1437782400]),\n             ('1 hour',\n              ['Jun 09 10:00', '11:00', '12:00', '13:00', '14:00', '15:00',\n               '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00',\n               '23:00',\n               '10 00:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000, -1437818400,\n               -1437814800, -1437811200, -1437807600, -1437804000, -1437800400,\n               -1437796800, -1437793200, -1437789600, -1437786000,\n               -1437782400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30', '14:00', '14:30', '15:00', '15:30', '16:00', '16:30',\n               '17:00', '17:30', '18:00', '18:30', '19:00', '19:30', '20:00',\n               '20:30', '21:00', '21:30', '22:00', '22:30', '23:00', '23:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200, -1437818400, -1437816600,\n               -1437814800, -1437813000, -1437811200, -1437809400, -1437807600,\n               -1437805800, -1437804000, -1437802200, -1437800400, -1437798600,\n               -1437796800, -1437795000, -1437793200, -1437791400, -1437789600,\n               -1437787800, -1437786000, -1437784200])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 13, 18)),\n            [('2 hours',\n              ['10:00', '12:00', '14:00'],\n              [-1437832800, -1437825600, -1437818400]),\n             ('1 hour',\n              ['10:00', '11:00', '12:00', '13:00', '14:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000,\n               -1437818400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00', '11:15', '11:30',\n               '11:45', '12:00', '12:15', '12:30', '12:45', '13:00', '13:15',\n               '13:30'],\n              [-1437832800, -1437831900, -1437831000, -1437830100, -1437829200,\n               -1437828300, -1437827400, -1437826500, -1437825600, -1437824700,\n               -1437823800, -1437822900, -1437822000, -1437821100,\n               -1437820200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50', '11:00',\n               '11:10', '11:20', '11:30', '11:40', '11:50', '12:00', '12:10',\n               '12:20', '12:30', '12:40', '12:50', '13:00', '13:10', '13:20'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800, -1437829200, -1437828600, -1437828000, -1437827400,\n               -1437826800, -1437826200, -1437825600, -1437825000, -1437824400,\n               -1437823800, -1437823200, -1437822600, -1437822000, -1437821400,\n               -1437820800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50', '10:55', '11:00', '11:05',\n               '11:10', '11:15', '11:20', '11:25', '11:30', '11:35', '11:40',\n               '11:45', '11:50', '11:55', '12:00', '12:05', '12:10', '12:15',\n               '12:20', '12:25', '12:30', '12:35', '12:40', '12:45', '12:50',\n               '12:55', '13:00', '13:05', '13:10', '13:15', '13:20'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800, -1437829500, -1437829200, -1437828900, -1437828600,\n               -1437828300, -1437828000, -1437827700, -1437827400, -1437827100,\n               -1437826800, -1437826500, -1437826200, -1437825900, -1437825600,\n               -1437825300, -1437825000, -1437824700, -1437824400, -1437824100,\n               -1437823800, -1437823500, -1437823200, -1437822900, -1437822600,\n               -1437822300, -1437822000, -1437821700, -1437821400, -1437821100,\n               -1437820800])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 48)),\n            [('30 minutes',\n              ['10:00', '10:30', '11:00'],\n              [-1437832800, -1437831000, -1437829200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00'],\n              [-1437832800, -1437831900, -1437831000, -1437830100,\n               -1437829200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21', '10:22', '10:23', '10:24', '10:25', '10:26', '10:27',\n               '10:28', '10:29', '10:30', '10:31', '10:32', '10:33', '10:34',\n               '10:35', '10:36', '10:37', '10:38', '10:39', '10:40', '10:41',\n               '10:42', '10:43', '10:44', '10:45', '10:46', '10:47', '10:48',\n               '10:49'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540, -1437831480, -1437831420, -1437831360,\n               -1437831300, -1437831240, -1437831180, -1437831120, -1437831060,\n               -1437831000, -1437830940, -1437830880, -1437830820, -1437830760,\n               -1437830700, -1437830640, -1437830580, -1437830520, -1437830460,\n               -1437830400, -1437830340, -1437830280, -1437830220, -1437830160,\n               -1437830100, -1437830040, -1437829980, -1437829920, -1437829860]\n              )]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 20)),\n            [('15 minutes',\n              ['10:00', '10:15', '10:30'],\n              [-1437832800, -1437831900, -1437831000]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30'],\n              [-1437832800, -1437832200, -1437831600, -1437831000]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540]),\n             ('30 seconds',\n              ['10:00:00', '10:00:30', '10:01:00', '10:01:30', '10:02:00',\n               '10:02:30', '10:03:00', '10:03:30', '10:04:00', '10:04:30',\n               '10:05:00', '10:05:30', '10:06:00', '10:06:30', '10:07:00',\n               '10:07:30', '10:08:00', '10:08:30', '10:09:00', '10:09:30',\n               '10:10:00', '10:10:30', '10:11:00', '10:11:30', '10:12:00',\n               '10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30', '10:19:00', '10:19:30',\n               '10:20:00', '10:20:30'],\n              [-1437832800, -1437832770, -1437832740, -1437832710, -1437832680,\n               -1437832650, -1437832620, -1437832590, -1437832560, -1437832530,\n               -1437832500, -1437832470, -1437832440, -1437832410, -1437832380,\n               -1437832350, -1437832320, -1437832290, -1437832260, -1437832230,\n               -1437832200, -1437832170, -1437832140, -1437832110, -1437832080,\n               -1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690, -1437831660, -1437831630,\n               -1437831600, -1437831570])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 18, 12)),\n            [('5 minutes',\n              ['10:10', '10:15', '10:20'],\n              [-1437832200, -1437831900, -1437831600]),\n             ('1 minute',\n              ['10:12', '10:13', '10:14', '10:15', '10:16', '10:17', '10:18',\n               '10:19'],\n              [-1437832080, -1437832020, -1437831960, -1437831900, -1437831840,\n               -1437831780, -1437831720, -1437831660]),\n             ('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30'],\n              [-1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15', '10:13:30',\n               '10:13:45', '10:14:00', '10:14:15', '10:14:30', '10:14:45',\n               '10:15:00', '10:15:15', '10:15:30', '10:15:45', '10:16:00',\n               '10:16:15', '10:16:30', '10:16:45', '10:17:00', '10:17:15',\n               '10:17:30', '10:17:45', '10:18:00', '10:18:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005, -1437831990,\n               -1437831975, -1437831960, -1437831945, -1437831930, -1437831915,\n               -1437831900, -1437831885, -1437831870, -1437831855, -1437831840,\n               -1437831825, -1437831810, -1437831795, -1437831780, -1437831765,\n               -1437831750, -1437831735, -1437831720, -1437831705]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20', '10:13:30', '10:13:40', '10:13:50', '10:14:00',\n               '10:14:10', '10:14:20', '10:14:30', '10:14:40', '10:14:50',\n               '10:15:00', '10:15:10', '10:15:20', '10:15:30', '10:15:40',\n               '10:15:50', '10:16:00', '10:16:10', '10:16:20', '10:16:30',\n               '10:16:40', '10:16:50', '10:17:00', '10:17:10', '10:17:20',\n               '10:17:30', '10:17:40', '10:17:50', '10:18:00', '10:18:10',\n               '10:18:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000, -1437831990, -1437831980, -1437831970, -1437831960,\n               -1437831950, -1437831940, -1437831930, -1437831920, -1437831910,\n               -1437831900, -1437831890, -1437831880, -1437831870, -1437831860,\n               -1437831850, -1437831840, -1437831830, -1437831820, -1437831810,\n               -1437831800, -1437831790, -1437831780, -1437831770, -1437831760,\n               -1437831750, -1437831740, -1437831730, -1437831720, -1437831710,\n               -1437831700])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 13, 12)),\n            [('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30'],\n              [-1437832050, -1437832020, -1437831990]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000]),\n             ('5 seconds',\n              ['10:12:30', '10:12:35', '10:12:40', '10:12:45', '10:12:50',\n               '10:12:55', '10:13:00', '10:13:05', '10:13:10', '10:13:15'],\n              [-1437832050, -1437832045, -1437832040, -1437832035, -1437832030,\n               -1437832025, -1437832020, -1437832015, -1437832010,\n               -1437832005]),\n             ('1 second',\n              ['10:12:33', '10:12:34', '10:12:35', '10:12:36', '10:12:37',\n               '10:12:38', '10:12:39', '10:12:40', '10:12:41', '10:12:42',\n               '10:12:43', '10:12:44', '10:12:45', '10:12:46', '10:12:47',\n               '10:12:48', '10:12:49', '10:12:50', '10:12:51', '10:12:52',\n               '10:12:53', '10:12:54', '10:12:55', '10:12:56', '10:12:57',\n               '10:12:58', '10:12:59', '10:13:00', '10:13:01', '10:13:02',\n               '10:13:03', '10:13:04', '10:13:05', '10:13:06', '10:13:07',\n               '10:13:08', '10:13:09', '10:13:10', '10:13:11', '10:13:12',\n               '10:13:13'],\n              [-1437832047, -1437832046, -1437832045, -1437832044, -1437832043,\n               -1437832042, -1437832041, -1437832040, -1437832039, -1437832038,\n               -1437832037, -1437832036, -1437832035, -1437832034, -1437832033,\n               -1437832032, -1437832031, -1437832030, -1437832029, -1437832028,\n               -1437832027, -1437832026, -1437832025, -1437832024, -1437832023,\n               -1437832022, -1437832021, -1437832020, -1437832019, -1437832018,\n               -1437832017, -1437832016, -1437832015, -1437832014, -1437832013,\n               -1437832012, -1437832011, -1437832010, -1437832009, -1437832008,\n               -1437832007])])\n\n        self.assertEqual(\n            testbin((1973, 9, 14), (2010, 9, 8)),\n            [\n                ('50 years',\n                 ['1950', '2000', '2050'],\n                 [-631152000, 946684800, 2524608000]),\n                ('25 years',\n                 ['1950', '1975', '2000', '2025'],\n                 [-631152000, 157766400, 946684800, 1735689600]),\n                ('10 years',\n                 ['1970', '1980', '1990', '2000', '2010', '2020'],\n                 [0, 315532800, 631152000, 946684800, 1262304000, 1577836800]),\n                ('5 years',\n                 ['1970', '1975', '1980', '1985', '1990', '1995', '2000',\n                  '2005', '2010', '2015'],\n                 [0, 157766400, 315532800, 473385600, 631152000, 788918400,\n                  946684800, 1104537600, 1262304000, 1420070400]),\n                ('2 years',\n                 ['1972', '1974', '1976', '1978', '1980', '1982', '1984',\n                  '1986', '1988', '1990', '1992', '1994', '1996', '1998',\n                  '2000', '2002', '2004', '2006', '2008', '2010', '2012'],\n                 [63072000, 126230400, 189302400, 252460800, 315532800,\n                  378691200, 441763200, 504921600, 567993600, 631152000,\n                  694224000, 757382400, 820454400, 883612800, 946684800,\n                  1009843200, 1072915200, 1136073600, 1199145600, 1262304000,\n                  1325376000]),\n                ('1 year',\n                 ['1973', '1974', '1975', '1976', '1977', '1978', '1979',\n                  '1980', '1981', '1982', '1983', '1984', '1985', '1986',\n                  '1987', '1988', '1989', '1990', '1991', '1992', '1993',\n                  '1994', '1995', '1996', '1997', '1998', '1999', '2000',\n                  '2001', '2002', '2003', '2004', '2005', '2006', '2007',\n                  '2008', '2009', '2010', '2011'],\n                 [94694400, 126230400, 157766400, 189302400, 220924800,\n                  252460800, 283996800, 315532800, 347155200, 378691200,\n                  410227200, 441763200, 473385600, 504921600, 536457600,\n                  567993600, 599616000, 631152000, 662688000, 694224000,\n                  725846400, 757382400, 788918400, 820454400, 852076800,\n                  883612800, 915148800, 946684800, 978307200, 1009843200,\n                  1041379200, 1072915200, 1104537600, 1136073600, 1167609600,\n                  1199145600, 1230768000, 1262304000, 1293840000])\n            ]\n        )\n\n    def test_min_unique(self):\n        bins = time_binnings(self.dates, min_unique=7)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_add_unique(self):\n        bins = time_binnings(self.dates, add_unique=7)\n        self.assertNotEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_limits(self):\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=17)},\n            {9, 17})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=16)},\n            {9})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=10, max_bins=17)},\n            {17})\n\n    def test_single_value(self):\n        dates = np.array([42])\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_multiple_identical(self):\n        dates = np.array([42] * 5)\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_no_values(self):\n        dates = np.array([])\n        self.assertRaises(ValueError, time_binnings, dates)\n\n        dates = np.array([np.nan, np.nan])\n        self.assertRaises(ValueError, time_binnings, dates)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 704,
                            "end_lineno": 708,
                            "parent": {
                                "file_name": "Orange/preprocess/tests/test_discretize.py",
                                "type": "class",
                                "name": "TestTimeBinning",
                                "content": "class TestTimeBinning(unittest.TestCase):\n    def setUp(self):\n        self.dates = [mktime(x) for x in\n            [(1975, 6, 9, 10, 0, 0, 0, 161, 0),\n             (1975, 6, 9, 10, 50, 0, 0, 161, 0),\n             (1975, 6, 9, 11, 40, 0, 0, 161, 0),\n             (1975, 6, 9, 12, 30, 0, 0, 161, 0),\n             (1975, 6, 9, 13, 20, 0, 0, 161, 0),\n             (1975, 6, 9, 14, 10, 0, 0, 161, 0)]]\n\n    def test_binning(self):\n        def testbin(start, end):\n            bins = _time_binnings(create(*start), create(*end), 3, 51)\n            return [(bin.width_label, bin.short_labels, bin.thresholds)\n                    for bin in reversed(bins)]\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1989, 3, 1)),\n            [('10 years',\n              ['1970', '1980', '1990'],\n              [0, 315532800, 631152000]),\n             ('5 years',\n              ['1975', '1980', '1985', '1990'],\n              [157766400, 315532800, 473385600, 631152000]),\n             ('2 years',\n              ['1974', '1976', '1978', '1980', '1982', '1984', '1986', '1988',\n               '1990'],\n              [126230400, 189302400, 252460800, 315532800, 378691200, 441763200,\n               504921600, 567993600, 631152000]),\n             ('1 year',\n              ['1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982',\n               '1983', '1984', '1985', '1986', '1987', '1988', '1989', '1990'],\n              [157766400, 189302400, 220924800, 252460800, 283996800, 315532800,\n               347155200, 378691200, 410227200, 441763200, 473385600, 504921600,\n               536457600, 567993600, 599616000, 631152000]),\n             ('6 months',\n              ['75 Jan', 'Jul', '76 Jan', 'Jul', '77 Jan', 'Jul', '78 Jan',\n               'Jul', '79 Jan', 'Jul', '80 Jan', 'Jul', '81 Jan', 'Jul',\n               '82 Jan', 'Jul', '83 Jan', 'Jul', '84 Jan', 'Jul', '85 Jan',\n               'Jul', '86 Jan', 'Jul', '87 Jan', 'Jul', '88 Jan', 'Jul',\n               '89 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200, 283996800, 299635200, 315532800, 331257600,\n               347155200, 362793600, 378691200, 394329600, 410227200, 425865600,\n               441763200, 457488000, 473385600, 489024000, 504921600, 520560000,\n               536457600, 552096000, 567993600, 583718400, 599616000,\n               615254400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1978, 3, 1)),\n            [('2 years',\n              ['1974', '1976', '1978', '1980'],\n              [126230400, 189302400, 252460800, 315532800]),\n             ('1 year',\n              ['1975', '1976', '1977', '1978', '1979'],\n              [157766400, 189302400, 220924800, 252460800, 283996800]),\n             ('6 months',\n              ['75 Jan', 'Jul',\n               '76 Jan', 'Jul',\n               '77 Jan', 'Jul',\n               '78 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200]),\n             ('3 months',\n              ['75 Apr', 'Jul', 'Oct',\n               '76 Jan', 'Apr', 'Jul', 'Oct',\n               '77 Jan', 'Apr', 'Jul', 'Oct',\n               '78 Jan', 'Apr'],\n              [165542400, 173404800, 181353600, 189302400, 197164800, 205027200,\n               212976000, 220924800, 228700800, 236563200, 244512000, 252460800,\n               260236800]),\n             ('2 months',\n              ['75 Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '76 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '77 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '78 Jan', 'Mar', 'May'],\n              [162864000, 168134400, 173404800, 178761600, 184032000, 189302400,\n               194486400, 199756800, 205027200, 210384000, 215654400, 220924800,\n               226022400, 231292800, 236563200, 241920000, 247190400, 252460800,\n               257558400, 262828800]),\n             ('1 month',\n              ['75 Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '76 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '77 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '78 Jan', 'Feb', 'Mar', 'Apr'],\n              [165542400, 168134400, 170812800, 173404800, 176083200, 178761600,\n               181353600, 184032000, 186624000, 189302400, 191980800, 194486400,\n               197164800, 199756800, 202435200, 205027200, 207705600, 210384000,\n               212976000, 215654400, 218246400, 220924800, 223603200, 226022400,\n               228700800, 231292800, 233971200, 236563200, 239241600, 241920000,\n               244512000, 247190400, 249782400, 252460800, 255139200, 257558400,\n               260236800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 2), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('2 weeks',\n              ['75 Dec 03', '17', '31', '76 Jan 14'],\n              [186796800, 188006400, 189216000, 190425600]),\n             ('1 week',\n              ['75 Dec 03', '10', '17', '24', '31',\n               '76 Jan 07'],\n              [186796800, 187401600, 188006400, 188611200, 189216000,\n               189820800]),\n             ('1 day',\n              ['75 Dec 02', '03', '04', '05', '06', '07', '08', '09', '10',\n               '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21',\n               '22', '23', '24', '25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [186710400, 186796800, 186883200, 186969600, 187056000, 187142400,\n               187228800, 187315200, 187401600, 187488000, 187574400, 187660800,\n               187747200, 187833600, 187920000, 188006400, 188092800, 188179200,\n               188265600, 188352000, 188438400, 188524800, 188611200, 188697600,\n               188784000, 188870400, 188956800, 189043200, 189129600, 189216000,\n               189302400, 189388800, 189475200, 189561600])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 25), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [188697600, 188784000, 188870400, 188956800, 189043200, 189129600,\n               189216000, 189302400, 189388800, 189475200, 189561600]),\n             ('12 hours',\n              ['75 Dec 25 00:00', '12:00',\n               '26 00:00', '12:00',\n               '27 00:00', '12:00',\n               '28 00:00', '12:00',\n               '29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [188697600, 188740800, 188784000, 188827200, 188870400, 188913600,\n               188956800, 189000000, 189043200, 189086400, 189129600, 189172800,\n               189216000, 189259200, 189302400, 189345600, 189388800, 189432000,\n               189475200, 189518400]),\n             ('6 hours',\n              ['75 Dec 25 00:00', '06:00', '12:00', '18:00',\n               '26 00:00', '06:00', '12:00', '18:00',\n               '27 00:00', '06:00', '12:00', '18:00',\n               '28 00:00', '06:00', '12:00', '18:00',\n               '29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [188697600, 188719200, 188740800, 188762400, 188784000, 188805600,\n               188827200, 188848800, 188870400, 188892000, 188913600, 188935200,\n               188956800, 188978400, 189000000, 189021600, 189043200, 189064800,\n               189086400, 189108000, 189129600, 189151200, 189172800, 189194400,\n               189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200, 189388800, 189410400, 189432000, 189453600,\n               189475200, 189496800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 29), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [189043200, 189129600, 189216000, 189302400, 189388800, 189475200,\n               189561600]),\n             ('12 hours',\n              ['75 Dec 29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [189043200, 189086400, 189129600, 189172800, 189216000, 189259200,\n               189302400, 189345600, 189388800, 189432000, 189475200,\n               189518400]),\n             ('6 hours',\n              ['75 Dec 29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [189043200, 189064800, 189086400, 189108000, 189129600, 189151200,\n               189172800, 189194400, 189216000, 189237600, 189259200, 189280800,\n               189302400, 189324000, 189345600, 189367200, 189388800, 189410400,\n               189432000, 189453600, 189475200, 189496800]),\n             ('3 hours',\n              ['75 Dec 29 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '30 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '02 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '03 00:00', '03:00'],\n              [189043200, 189054000, 189064800, 189075600, 189086400, 189097200,\n               189108000, 189118800, 189129600, 189140400, 189151200, 189162000,\n               189172800, 189183600, 189194400, 189205200, 189216000, 189226800,\n               189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200, 189324000, 189334800, 189345600, 189356400,\n               189367200, 189378000, 189388800, 189399600, 189410400, 189421200,\n               189432000, 189442800, 189453600, 189464400, 189475200,\n               189486000])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 0, 0, 0), (1976, 1, 1, 14, 30)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00'],\n              [189216000, 189259200, 189302400, 189345600, 189388800]),\n             ('6 hours',\n              ['75 Dec 31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00'],\n              [189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200]),\n             ('3 hours',\n              ['75 Dec 31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00'],\n              [189216000, 189226800, 189237600, 189248400, 189259200, 189270000,\n               189280800, 189291600, 189302400, 189313200, 189324000, 189334800,\n               189345600, 189356400]),\n             ('2 hours',\n              ['75 Dec 31 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00'],\n              [189216000, 189223200, 189230400, 189237600, 189244800, 189252000,\n               189259200, 189266400, 189273600, 189280800, 189288000, 189295200,\n               189302400, 189309600, 189316800, 189324000, 189331200, 189338400,\n               189345600, 189352800, 189360000]),\n             ('1 hour',\n              ['75 Dec 31 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00',\n               '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00'],\n              [189216000, 189219600, 189223200, 189226800, 189230400, 189234000,\n               189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000, 189309600, 189313200, 189316800, 189320400,\n               189324000, 189327600, 189331200, 189334800, 189338400, 189342000,\n               189345600, 189349200, 189352800, 189356400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 6), (1976, 1, 1)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00'],\n              [189216000, 189259200, 189302400, 189345600]),\n             ('6 hours',\n              ['75 Dec 31 06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00'],\n              [189237600, 189259200, 189280800, 189302400, 189324000]),\n             ('3 hours',\n              ['75 Dec 31 06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00'],\n              [189237600, 189244800, 189252000, 189259200, 189266400, 189273600,\n               189280800, 189288000, 189295200, 189302400, 189309600]),\n             ('1 hour',\n              ['75 Dec 31 06:00', '07:00', '08:00', '09:00', '10:00', '11:00',\n               '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00',\n               '19:00', '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00'],\n              [189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000]),\n             ('30 minutes',\n              ['Dec 31 06:00', '06:30', '07:00', '07:30', '08:00', '08:30',\n               '09:00', '09:30', '10:00', '10:30', '11:00', '11:30', '12:00',\n               '12:30', '13:00', '13:30', '14:00', '14:30', '15:00', '15:30',\n               '16:00', '16:30', '17:00', '17:30', '18:00', '18:30', '19:00',\n               '19:30', '20:00', '20:30', '21:00', '21:30', '22:00', '22:30',\n               '23:00', '23:30',\n               'Jan 01 00:00', '00:30'],\n              [189237600, 189239400, 189241200, 189243000, 189244800, 189246600,\n               189248400, 189250200, 189252000, 189253800, 189255600, 189257400,\n               189259200, 189261000, 189262800, 189264600, 189266400, 189268200,\n               189270000, 189271800, 189273600, 189275400, 189277200, 189279000,\n               189280800, 189282600, 189284400, 189286200, 189288000, 189289800,\n               189291600, 189293400, 189295200, 189297000, 189298800, 189300600,\n               189302400, 189304200])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 23), (1976, 1, 1, 2)),\n            [('3 hours',\n              ['75 Dec 31 21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189291600, 189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 22:00',\n               '76 Jan 01 00:00', '02:00', '04:00'],\n              [189295200, 189302400, 189309600, 189316800]),\n             ('1 hour',\n              ['75 Dec 31 23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00'],\n              [189298800, 189302400, 189306000, 189309600, 189313200]),\n             ('30 minutes',\n              ['Dec 31 23:00', '23:30',\n               'Jan 01 00:00', '00:30', '01:00', '01:30', '02:00', '02:30'],\n              [189298800, 189300600, 189302400, 189304200, 189306000, 189307800,\n               189309600, 189311400]),\n             ('15 minutes',\n              ['Dec 31 23:00', '23:15', '23:30', '23:45',\n               'Jan 01 00:00', '00:15', '00:30', '00:45', '01:00', '01:15',\n               '01:30', '01:45', '02:00', '02:15'],\n              [189298800, 189299700, 189300600, 189301500, 189302400, 189303300,\n               189304200, 189305100, 189306000, 189306900, 189307800, 189308700,\n               189309600, 189310500]),\n             ('10 minutes',\n              ['Dec 31 23:00', '23:10', '23:20', '23:30', '23:40', '23:50',\n               'Jan 01 00:00', '00:10', '00:20', '00:30', '00:40', '00:50',\n               '01:00', '01:10', '01:20', '01:30', '01:40', '01:50', '02:00',\n               '02:10'],\n              [189298800, 189299400, 189300000, 189300600, 189301200, 189301800,\n               189302400, 189303000, 189303600, 189304200, 189304800, 189305400,\n               189306000, 189306600, 189307200, 189307800, 189308400, 189309000,\n               189309600, 189310200]),\n             ('5 minutes',\n              ['Dec 31 23:00', '23:05', '23:10', '23:15', '23:20', '23:25',\n               '23:30', '23:35', '23:40', '23:45', '23:50', '23:55',\n               'Jan 01 00:00', '00:05', '00:10', '00:15', '00:20', '00:25',\n               '00:30', '00:35', '00:40', '00:45', '00:50', '00:55', '01:00',\n               '01:05', '01:10', '01:15', '01:20', '01:25', '01:30', '01:35',\n               '01:40', '01:45', '01:50', '01:55', '02:00', '02:05'],\n              [189298800, 189299100, 189299400, 189299700, 189300000, 189300300,\n               189300600, 189300900, 189301200, 189301500, 189301800, 189302100,\n               189302400, 189302700, 189303000, 189303300, 189303600, 189303900,\n               189304200, 189304500, 189304800, 189305100, 189305400, 189305700,\n               189306000, 189306300, 189306600, 189306900, 189307200, 189307500,\n               189307800, 189308100, 189308400, 189308700, 189309000, 189309300,\n               189309600, 189309900])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 23, 18)),\n            [('12 hours',\n              ['Jun 09 00:00', '12:00', '10 00:00'],\n              [-1437868800, -1437825600, -1437782400]),\n             ('6 hours',\n              ['Jun 09 06:00', '12:00', '18:00', '10 00:00'],\n              [-1437847200, -1437825600, -1437804000, -1437782400]),\n             ('3 hours',\n              ['Jun 09 09:00', '12:00', '15:00', '18:00', '21:00', '10 00:00'],\n              [-1437836400, -1437825600, -1437814800, -1437804000, -1437793200,\n               -1437782400]),\n             ('2 hours',\n              ['Jun 09 10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00', '10 00:00'],\n              [-1437832800, -1437825600, -1437818400, -1437811200, -1437804000,\n               -1437796800, -1437789600, -1437782400]),\n             ('1 hour',\n              ['Jun 09 10:00', '11:00', '12:00', '13:00', '14:00', '15:00',\n               '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00',\n               '23:00',\n               '10 00:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000, -1437818400,\n               -1437814800, -1437811200, -1437807600, -1437804000, -1437800400,\n               -1437796800, -1437793200, -1437789600, -1437786000,\n               -1437782400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30', '14:00', '14:30', '15:00', '15:30', '16:00', '16:30',\n               '17:00', '17:30', '18:00', '18:30', '19:00', '19:30', '20:00',\n               '20:30', '21:00', '21:30', '22:00', '22:30', '23:00', '23:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200, -1437818400, -1437816600,\n               -1437814800, -1437813000, -1437811200, -1437809400, -1437807600,\n               -1437805800, -1437804000, -1437802200, -1437800400, -1437798600,\n               -1437796800, -1437795000, -1437793200, -1437791400, -1437789600,\n               -1437787800, -1437786000, -1437784200])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 13, 18)),\n            [('2 hours',\n              ['10:00', '12:00', '14:00'],\n              [-1437832800, -1437825600, -1437818400]),\n             ('1 hour',\n              ['10:00', '11:00', '12:00', '13:00', '14:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000,\n               -1437818400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00', '11:15', '11:30',\n               '11:45', '12:00', '12:15', '12:30', '12:45', '13:00', '13:15',\n               '13:30'],\n              [-1437832800, -1437831900, -1437831000, -1437830100, -1437829200,\n               -1437828300, -1437827400, -1437826500, -1437825600, -1437824700,\n               -1437823800, -1437822900, -1437822000, -1437821100,\n               -1437820200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50', '11:00',\n               '11:10', '11:20', '11:30', '11:40', '11:50', '12:00', '12:10',\n               '12:20', '12:30', '12:40', '12:50', '13:00', '13:10', '13:20'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800, -1437829200, -1437828600, -1437828000, -1437827400,\n               -1437826800, -1437826200, -1437825600, -1437825000, -1437824400,\n               -1437823800, -1437823200, -1437822600, -1437822000, -1437821400,\n               -1437820800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50', '10:55', '11:00', '11:05',\n               '11:10', '11:15', '11:20', '11:25', '11:30', '11:35', '11:40',\n               '11:45', '11:50', '11:55', '12:00', '12:05', '12:10', '12:15',\n               '12:20', '12:25', '12:30', '12:35', '12:40', '12:45', '12:50',\n               '12:55', '13:00', '13:05', '13:10', '13:15', '13:20'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800, -1437829500, -1437829200, -1437828900, -1437828600,\n               -1437828300, -1437828000, -1437827700, -1437827400, -1437827100,\n               -1437826800, -1437826500, -1437826200, -1437825900, -1437825600,\n               -1437825300, -1437825000, -1437824700, -1437824400, -1437824100,\n               -1437823800, -1437823500, -1437823200, -1437822900, -1437822600,\n               -1437822300, -1437822000, -1437821700, -1437821400, -1437821100,\n               -1437820800])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 48)),\n            [('30 minutes',\n              ['10:00', '10:30', '11:00'],\n              [-1437832800, -1437831000, -1437829200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00'],\n              [-1437832800, -1437831900, -1437831000, -1437830100,\n               -1437829200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21', '10:22', '10:23', '10:24', '10:25', '10:26', '10:27',\n               '10:28', '10:29', '10:30', '10:31', '10:32', '10:33', '10:34',\n               '10:35', '10:36', '10:37', '10:38', '10:39', '10:40', '10:41',\n               '10:42', '10:43', '10:44', '10:45', '10:46', '10:47', '10:48',\n               '10:49'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540, -1437831480, -1437831420, -1437831360,\n               -1437831300, -1437831240, -1437831180, -1437831120, -1437831060,\n               -1437831000, -1437830940, -1437830880, -1437830820, -1437830760,\n               -1437830700, -1437830640, -1437830580, -1437830520, -1437830460,\n               -1437830400, -1437830340, -1437830280, -1437830220, -1437830160,\n               -1437830100, -1437830040, -1437829980, -1437829920, -1437829860]\n              )]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 20)),\n            [('15 minutes',\n              ['10:00', '10:15', '10:30'],\n              [-1437832800, -1437831900, -1437831000]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30'],\n              [-1437832800, -1437832200, -1437831600, -1437831000]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540]),\n             ('30 seconds',\n              ['10:00:00', '10:00:30', '10:01:00', '10:01:30', '10:02:00',\n               '10:02:30', '10:03:00', '10:03:30', '10:04:00', '10:04:30',\n               '10:05:00', '10:05:30', '10:06:00', '10:06:30', '10:07:00',\n               '10:07:30', '10:08:00', '10:08:30', '10:09:00', '10:09:30',\n               '10:10:00', '10:10:30', '10:11:00', '10:11:30', '10:12:00',\n               '10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30', '10:19:00', '10:19:30',\n               '10:20:00', '10:20:30'],\n              [-1437832800, -1437832770, -1437832740, -1437832710, -1437832680,\n               -1437832650, -1437832620, -1437832590, -1437832560, -1437832530,\n               -1437832500, -1437832470, -1437832440, -1437832410, -1437832380,\n               -1437832350, -1437832320, -1437832290, -1437832260, -1437832230,\n               -1437832200, -1437832170, -1437832140, -1437832110, -1437832080,\n               -1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690, -1437831660, -1437831630,\n               -1437831600, -1437831570])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 18, 12)),\n            [('5 minutes',\n              ['10:10', '10:15', '10:20'],\n              [-1437832200, -1437831900, -1437831600]),\n             ('1 minute',\n              ['10:12', '10:13', '10:14', '10:15', '10:16', '10:17', '10:18',\n               '10:19'],\n              [-1437832080, -1437832020, -1437831960, -1437831900, -1437831840,\n               -1437831780, -1437831720, -1437831660]),\n             ('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30'],\n              [-1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15', '10:13:30',\n               '10:13:45', '10:14:00', '10:14:15', '10:14:30', '10:14:45',\n               '10:15:00', '10:15:15', '10:15:30', '10:15:45', '10:16:00',\n               '10:16:15', '10:16:30', '10:16:45', '10:17:00', '10:17:15',\n               '10:17:30', '10:17:45', '10:18:00', '10:18:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005, -1437831990,\n               -1437831975, -1437831960, -1437831945, -1437831930, -1437831915,\n               -1437831900, -1437831885, -1437831870, -1437831855, -1437831840,\n               -1437831825, -1437831810, -1437831795, -1437831780, -1437831765,\n               -1437831750, -1437831735, -1437831720, -1437831705]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20', '10:13:30', '10:13:40', '10:13:50', '10:14:00',\n               '10:14:10', '10:14:20', '10:14:30', '10:14:40', '10:14:50',\n               '10:15:00', '10:15:10', '10:15:20', '10:15:30', '10:15:40',\n               '10:15:50', '10:16:00', '10:16:10', '10:16:20', '10:16:30',\n               '10:16:40', '10:16:50', '10:17:00', '10:17:10', '10:17:20',\n               '10:17:30', '10:17:40', '10:17:50', '10:18:00', '10:18:10',\n               '10:18:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000, -1437831990, -1437831980, -1437831970, -1437831960,\n               -1437831950, -1437831940, -1437831930, -1437831920, -1437831910,\n               -1437831900, -1437831890, -1437831880, -1437831870, -1437831860,\n               -1437831850, -1437831840, -1437831830, -1437831820, -1437831810,\n               -1437831800, -1437831790, -1437831780, -1437831770, -1437831760,\n               -1437831750, -1437831740, -1437831730, -1437831720, -1437831710,\n               -1437831700])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 13, 12)),\n            [('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30'],\n              [-1437832050, -1437832020, -1437831990]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000]),\n             ('5 seconds',\n              ['10:12:30', '10:12:35', '10:12:40', '10:12:45', '10:12:50',\n               '10:12:55', '10:13:00', '10:13:05', '10:13:10', '10:13:15'],\n              [-1437832050, -1437832045, -1437832040, -1437832035, -1437832030,\n               -1437832025, -1437832020, -1437832015, -1437832010,\n               -1437832005]),\n             ('1 second',\n              ['10:12:33', '10:12:34', '10:12:35', '10:12:36', '10:12:37',\n               '10:12:38', '10:12:39', '10:12:40', '10:12:41', '10:12:42',\n               '10:12:43', '10:12:44', '10:12:45', '10:12:46', '10:12:47',\n               '10:12:48', '10:12:49', '10:12:50', '10:12:51', '10:12:52',\n               '10:12:53', '10:12:54', '10:12:55', '10:12:56', '10:12:57',\n               '10:12:58', '10:12:59', '10:13:00', '10:13:01', '10:13:02',\n               '10:13:03', '10:13:04', '10:13:05', '10:13:06', '10:13:07',\n               '10:13:08', '10:13:09', '10:13:10', '10:13:11', '10:13:12',\n               '10:13:13'],\n              [-1437832047, -1437832046, -1437832045, -1437832044, -1437832043,\n               -1437832042, -1437832041, -1437832040, -1437832039, -1437832038,\n               -1437832037, -1437832036, -1437832035, -1437832034, -1437832033,\n               -1437832032, -1437832031, -1437832030, -1437832029, -1437832028,\n               -1437832027, -1437832026, -1437832025, -1437832024, -1437832023,\n               -1437832022, -1437832021, -1437832020, -1437832019, -1437832018,\n               -1437832017, -1437832016, -1437832015, -1437832014, -1437832013,\n               -1437832012, -1437832011, -1437832010, -1437832009, -1437832008,\n               -1437832007])])\n\n        self.assertEqual(\n            testbin((1973, 9, 14), (2010, 9, 8)),\n            [\n                ('50 years',\n                 ['1950', '2000', '2050'],\n                 [-631152000, 946684800, 2524608000]),\n                ('25 years',\n                 ['1950', '1975', '2000', '2025'],\n                 [-631152000, 157766400, 946684800, 1735689600]),\n                ('10 years',\n                 ['1970', '1980', '1990', '2000', '2010', '2020'],\n                 [0, 315532800, 631152000, 946684800, 1262304000, 1577836800]),\n                ('5 years',\n                 ['1970', '1975', '1980', '1985', '1990', '1995', '2000',\n                  '2005', '2010', '2015'],\n                 [0, 157766400, 315532800, 473385600, 631152000, 788918400,\n                  946684800, 1104537600, 1262304000, 1420070400]),\n                ('2 years',\n                 ['1972', '1974', '1976', '1978', '1980', '1982', '1984',\n                  '1986', '1988', '1990', '1992', '1994', '1996', '1998',\n                  '2000', '2002', '2004', '2006', '2008', '2010', '2012'],\n                 [63072000, 126230400, 189302400, 252460800, 315532800,\n                  378691200, 441763200, 504921600, 567993600, 631152000,\n                  694224000, 757382400, 820454400, 883612800, 946684800,\n                  1009843200, 1072915200, 1136073600, 1199145600, 1262304000,\n                  1325376000]),\n                ('1 year',\n                 ['1973', '1974', '1975', '1976', '1977', '1978', '1979',\n                  '1980', '1981', '1982', '1983', '1984', '1985', '1986',\n                  '1987', '1988', '1989', '1990', '1991', '1992', '1993',\n                  '1994', '1995', '1996', '1997', '1998', '1999', '2000',\n                  '2001', '2002', '2003', '2004', '2005', '2006', '2007',\n                  '2008', '2009', '2010', '2011'],\n                 [94694400, 126230400, 157766400, 189302400, 220924800,\n                  252460800, 283996800, 315532800, 347155200, 378691200,\n                  410227200, 441763200, 473385600, 504921600, 536457600,\n                  567993600, 599616000, 631152000, 662688000, 694224000,\n                  725846400, 757382400, 788918400, 820454400, 852076800,\n                  883612800, 915148800, 946684800, 978307200, 1009843200,\n                  1041379200, 1072915200, 1104537600, 1136073600, 1167609600,\n                  1199145600, 1230768000, 1262304000, 1293840000])\n            ]\n        )\n\n    def test_min_unique(self):\n        bins = time_binnings(self.dates, min_unique=7)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_add_unique(self):\n        bins = time_binnings(self.dates, add_unique=7)\n        self.assertNotEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_limits(self):\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=17)},\n            {9, 17})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=16)},\n            {9})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=10, max_bins=17)},\n            {17})\n\n    def test_single_value(self):\n        dates = np.array([42])\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_multiple_identical(self):\n        dates = np.array([42] * 5)\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_no_values(self):\n        dates = np.array([])\n        self.assertRaises(ValueError, time_binnings, dates)\n\n        dates = np.array([np.nan, np.nan])\n        self.assertRaises(ValueError, time_binnings, dates)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 16,
                                "end_lineno": 715,
                                "parent": null
                            }
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "f5b986b11e518191441420df8f8b84154c92e81c^",
    "new_commit_hash": "f5b986b11e518191441420df8f8b84154c92e81c",
    "commit_message": "_time_binnings: fix fail on longer date difference",
    "commit_date": "2020-03-06T22:32:01+01:00",
    "metadata": {}
}
{
    "repo_name": "orange3",
    "new_commit_hash": "f5b986b11e518191441420df8f8b84154c92e81c",
    "test_file_codes": [
        "# File contains some long lines; breaking them would decrease readability\n# pylint: disable=line-too-long\nimport unittest\nfrom time import struct_time, mktime\n\nimport numpy as np\nfrom Orange.preprocess.discretize import \\\n    _time_binnings, time_binnings, BinDefinition\n\n\n# pylint: disable=redefined-builtin\ndef create(year=1970, month=1, day=1, hour=0, min=0, sec=0):\n    return struct_time((year, month, day, hour, min, sec, 0, 0, 0))\n\n\nclass TestTimeBinning(unittest.TestCase):\n    def setUp(self):\n        self.dates = [mktime(x) for x in\n            [(1975, 6, 9, 10, 0, 0, 0, 161, 0),\n             (1975, 6, 9, 10, 50, 0, 0, 161, 0),\n             (1975, 6, 9, 11, 40, 0, 0, 161, 0),\n             (1975, 6, 9, 12, 30, 0, 0, 161, 0),\n             (1975, 6, 9, 13, 20, 0, 0, 161, 0),\n             (1975, 6, 9, 14, 10, 0, 0, 161, 0)]]\n\n    def test_binning(self):\n        def testbin(start, end):\n            bins = _time_binnings(create(*start), create(*end), 3, 51)\n            return [(bin.width_label, bin.short_labels, bin.thresholds)\n                    for bin in reversed(bins)]\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1989, 3, 1)),\n            [('10 years',\n              ['1970', '1980', '1990'],\n              [0, 315532800, 631152000]),\n             ('5 years',\n              ['1975', '1980', '1985', '1990'],\n              [157766400, 315532800, 473385600, 631152000]),\n             ('2 years',\n              ['1974', '1976', '1978', '1980', '1982', '1984', '1986', '1988',\n               '1990'],\n              [126230400, 189302400, 252460800, 315532800, 378691200, 441763200,\n               504921600, 567993600, 631152000]),\n             ('1 year',\n              ['1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982',\n               '1983', '1984', '1985', '1986', '1987', '1988', '1989', '1990'],\n              [157766400, 189302400, 220924800, 252460800, 283996800, 315532800,\n               347155200, 378691200, 410227200, 441763200, 473385600, 504921600,\n               536457600, 567993600, 599616000, 631152000]),\n             ('6 months',\n              ['75 Jan', 'Jul', '76 Jan', 'Jul', '77 Jan', 'Jul', '78 Jan',\n               'Jul', '79 Jan', 'Jul', '80 Jan', 'Jul', '81 Jan', 'Jul',\n               '82 Jan', 'Jul', '83 Jan', 'Jul', '84 Jan', 'Jul', '85 Jan',\n               'Jul', '86 Jan', 'Jul', '87 Jan', 'Jul', '88 Jan', 'Jul',\n               '89 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200, 283996800, 299635200, 315532800, 331257600,\n               347155200, 362793600, 378691200, 394329600, 410227200, 425865600,\n               441763200, 457488000, 473385600, 489024000, 504921600, 520560000,\n               536457600, 552096000, 567993600, 583718400, 599616000,\n               615254400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 4, 2), (1978, 3, 1)),\n            [('2 years',\n              ['1974', '1976', '1978', '1980'],\n              [126230400, 189302400, 252460800, 315532800]),\n             ('1 year',\n              ['1975', '1976', '1977', '1978', '1979'],\n              [157766400, 189302400, 220924800, 252460800, 283996800]),\n             ('6 months',\n              ['75 Jan', 'Jul',\n               '76 Jan', 'Jul',\n               '77 Jan', 'Jul',\n               '78 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200]),\n             ('3 months',\n              ['75 Apr', 'Jul', 'Oct',\n               '76 Jan', 'Apr', 'Jul', 'Oct',\n               '77 Jan', 'Apr', 'Jul', 'Oct',\n               '78 Jan', 'Apr'],\n              [165542400, 173404800, 181353600, 189302400, 197164800, 205027200,\n               212976000, 220924800, 228700800, 236563200, 244512000, 252460800,\n               260236800]),\n             ('2 months',\n              ['75 Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '76 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '77 Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov',\n               '78 Jan', 'Mar', 'May'],\n              [162864000, 168134400, 173404800, 178761600, 184032000, 189302400,\n               194486400, 199756800, 205027200, 210384000, 215654400, 220924800,\n               226022400, 231292800, 236563200, 241920000, 247190400, 252460800,\n               257558400, 262828800]),\n             ('1 month',\n              ['75 Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '76 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '77 Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n               '78 Jan', 'Feb', 'Mar', 'Apr'],\n              [165542400, 168134400, 170812800, 173404800, 176083200, 178761600,\n               181353600, 184032000, 186624000, 189302400, 191980800, 194486400,\n               197164800, 199756800, 202435200, 205027200, 207705600, 210384000,\n               212976000, 215654400, 218246400, 220924800, 223603200, 226022400,\n               228700800, 231292800, 233971200, 236563200, 239241600, 241920000,\n               244512000, 247190400, 249782400, 252460800, 255139200, 257558400,\n               260236800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 2), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('2 weeks',\n              ['75 Dec 03', '17', '31', '76 Jan 14'],\n              [186796800, 188006400, 189216000, 190425600]),\n             ('1 week',\n              ['75 Dec 03', '10', '17', '24', '31',\n               '76 Jan 07'],\n              [186796800, 187401600, 188006400, 188611200, 189216000,\n               189820800]),\n             ('1 day',\n              ['75 Dec 02', '03', '04', '05', '06', '07', '08', '09', '10',\n               '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21',\n               '22', '23', '24', '25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [186710400, 186796800, 186883200, 186969600, 187056000, 187142400,\n               187228800, 187315200, 187401600, 187488000, 187574400, 187660800,\n               187747200, 187833600, 187920000, 188006400, 188092800, 188179200,\n               188265600, 188352000, 188438400, 188524800, 188611200, 188697600,\n               188784000, 188870400, 188956800, 189043200, 189129600, 189216000,\n               189302400, 189388800, 189475200, 189561600])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 25), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 25', '26', '27', '28', '29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [188697600, 188784000, 188870400, 188956800, 189043200, 189129600,\n               189216000, 189302400, 189388800, 189475200, 189561600]),\n             ('12 hours',\n              ['75 Dec 25 00:00', '12:00',\n               '26 00:00', '12:00',\n               '27 00:00', '12:00',\n               '28 00:00', '12:00',\n               '29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [188697600, 188740800, 188784000, 188827200, 188870400, 188913600,\n               188956800, 189000000, 189043200, 189086400, 189129600, 189172800,\n               189216000, 189259200, 189302400, 189345600, 189388800, 189432000,\n               189475200, 189518400]),\n             ('6 hours',\n              ['75 Dec 25 00:00', '06:00', '12:00', '18:00',\n               '26 00:00', '06:00', '12:00', '18:00',\n               '27 00:00', '06:00', '12:00', '18:00',\n               '28 00:00', '06:00', '12:00', '18:00',\n               '29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [188697600, 188719200, 188740800, 188762400, 188784000, 188805600,\n               188827200, 188848800, 188870400, 188892000, 188913600, 188935200,\n               188956800, 188978400, 189000000, 189021600, 189043200, 189064800,\n               189086400, 189108000, 189129600, 189151200, 189172800, 189194400,\n               189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200, 189388800, 189410400, 189432000, 189453600,\n               189475200, 189496800])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 29), (1976, 1, 3)),\n            [('1 month',\n              ['75 Dec', '76 Jan', 'Feb'],\n              [186624000, 189302400, 191980800]),\n             ('1 day',\n              ['75 Dec 29', '30', '31',\n               '76 Jan 01', '02', '03', '04'],\n              [189043200, 189129600, 189216000, 189302400, 189388800, 189475200,\n               189561600]),\n             ('12 hours',\n              ['75 Dec 29 00:00', '12:00',\n               '30 00:00', '12:00',\n               '31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00', '12:00',\n               '03 00:00', '12:00'],\n              [189043200, 189086400, 189129600, 189172800, 189216000, 189259200,\n               189302400, 189345600, 189388800, 189432000, 189475200,\n               189518400]),\n             ('6 hours',\n              ['75 Dec 29 00:00', '06:00', '12:00', '18:00',\n               '30 00:00', '06:00', '12:00', '18:00',\n               '31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00',\n               '02 00:00', '06:00', '12:00', '18:00',\n               '03 00:00', '06:00'],\n              [189043200, 189064800, 189086400, 189108000, 189129600, 189151200,\n               189172800, 189194400, 189216000, 189237600, 189259200, 189280800,\n               189302400, 189324000, 189345600, 189367200, 189388800, 189410400,\n               189432000, 189453600, 189475200, 189496800]),\n             ('3 hours',\n              ['75 Dec 29 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '30 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '02 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '03 00:00', '03:00'],\n              [189043200, 189054000, 189064800, 189075600, 189086400, 189097200,\n               189108000, 189118800, 189129600, 189140400, 189151200, 189162000,\n               189172800, 189183600, 189194400, 189205200, 189216000, 189226800,\n               189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200, 189324000, 189334800, 189345600, 189356400,\n               189367200, 189378000, 189388800, 189399600, 189410400, 189421200,\n               189432000, 189442800, 189453600, 189464400, 189475200,\n               189486000])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 0, 0, 0), (1976, 1, 1, 14, 30)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00',\n               '02 00:00'],\n              [189216000, 189259200, 189302400, 189345600, 189388800]),\n             ('6 hours',\n              ['75 Dec 31 00:00', '06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00', '12:00', '18:00'],\n              [189216000, 189237600, 189259200, 189280800, 189302400, 189324000,\n               189345600, 189367200]),\n             ('3 hours',\n              ['75 Dec 31 00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00', '06:00', '09:00', '12:00', '15:00'],\n              [189216000, 189226800, 189237600, 189248400, 189259200, 189270000,\n               189280800, 189291600, 189302400, 189313200, 189324000, 189334800,\n               189345600, 189356400]),\n             ('2 hours',\n              ['75 Dec 31 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00'],\n              [189216000, 189223200, 189230400, 189237600, 189244800, 189252000,\n               189259200, 189266400, 189273600, 189280800, 189288000, 189295200,\n               189302400, 189309600, 189316800, 189324000, 189331200, 189338400,\n               189345600, 189352800, 189360000]),\n             ('1 hour',\n              ['75 Dec 31 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00',\n               '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00', '04:00', '05:00',\n               '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00',\n               '13:00', '14:00', '15:00'],\n              [189216000, 189219600, 189223200, 189226800, 189230400, 189234000,\n               189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000, 189309600, 189313200, 189316800, 189320400,\n               189324000, 189327600, 189331200, 189334800, 189338400, 189342000,\n               189345600, 189349200, 189352800, 189356400])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 6), (1976, 1, 1)),\n            [('1 day',\n              ['75 Dec 31', '76 Jan 01', '02'],\n              [189216000, 189302400, 189388800]),\n             ('12 hours',\n              ['75 Dec 31 00:00', '12:00',\n               '76 Jan 01 00:00', '12:00'],\n              [189216000, 189259200, 189302400, 189345600]),\n             ('6 hours',\n              ['75 Dec 31 06:00', '12:00', '18:00',\n               '76 Jan 01 00:00', '06:00'],\n              [189237600, 189259200, 189280800, 189302400, 189324000]),\n             ('3 hours',\n              ['75 Dec 31 06:00', '09:00', '12:00', '15:00', '18:00', '21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189237600, 189248400, 189259200, 189270000, 189280800, 189291600,\n               189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00',\n               '76 Jan 01 00:00', '02:00'],\n              [189237600, 189244800, 189252000, 189259200, 189266400, 189273600,\n               189280800, 189288000, 189295200, 189302400, 189309600]),\n             ('1 hour',\n              ['75 Dec 31 06:00', '07:00', '08:00', '09:00', '10:00', '11:00',\n               '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00',\n               '19:00', '20:00', '21:00', '22:00', '23:00',\n               '76 Jan 01 00:00', '01:00'],\n              [189237600, 189241200, 189244800, 189248400, 189252000, 189255600,\n               189259200, 189262800, 189266400, 189270000, 189273600, 189277200,\n               189280800, 189284400, 189288000, 189291600, 189295200, 189298800,\n               189302400, 189306000]),\n             ('30 minutes',\n              ['Dec 31 06:00', '06:30', '07:00', '07:30', '08:00', '08:30',\n               '09:00', '09:30', '10:00', '10:30', '11:00', '11:30', '12:00',\n               '12:30', '13:00', '13:30', '14:00', '14:30', '15:00', '15:30',\n               '16:00', '16:30', '17:00', '17:30', '18:00', '18:30', '19:00',\n               '19:30', '20:00', '20:30', '21:00', '21:30', '22:00', '22:30',\n               '23:00', '23:30',\n               'Jan 01 00:00', '00:30'],\n              [189237600, 189239400, 189241200, 189243000, 189244800, 189246600,\n               189248400, 189250200, 189252000, 189253800, 189255600, 189257400,\n               189259200, 189261000, 189262800, 189264600, 189266400, 189268200,\n               189270000, 189271800, 189273600, 189275400, 189277200, 189279000,\n               189280800, 189282600, 189284400, 189286200, 189288000, 189289800,\n               189291600, 189293400, 189295200, 189297000, 189298800, 189300600,\n               189302400, 189304200])]\n        )\n\n        self.assertEqual(\n            testbin((1975, 12, 31, 23), (1976, 1, 1, 2)),\n            [('3 hours',\n              ['75 Dec 31 21:00',\n               '76 Jan 01 00:00', '03:00'],\n              [189291600, 189302400, 189313200]),\n             ('2 hours',\n              ['75 Dec 31 22:00',\n               '76 Jan 01 00:00', '02:00', '04:00'],\n              [189295200, 189302400, 189309600, 189316800]),\n             ('1 hour',\n              ['75 Dec 31 23:00',\n               '76 Jan 01 00:00', '01:00', '02:00', '03:00'],\n              [189298800, 189302400, 189306000, 189309600, 189313200]),\n             ('30 minutes',\n              ['Dec 31 23:00', '23:30',\n               'Jan 01 00:00', '00:30', '01:00', '01:30', '02:00', '02:30'],\n              [189298800, 189300600, 189302400, 189304200, 189306000, 189307800,\n               189309600, 189311400]),\n             ('15 minutes',\n              ['Dec 31 23:00', '23:15', '23:30', '23:45',\n               'Jan 01 00:00', '00:15', '00:30', '00:45', '01:00', '01:15',\n               '01:30', '01:45', '02:00', '02:15'],\n              [189298800, 189299700, 189300600, 189301500, 189302400, 189303300,\n               189304200, 189305100, 189306000, 189306900, 189307800, 189308700,\n               189309600, 189310500]),\n             ('10 minutes',\n              ['Dec 31 23:00', '23:10', '23:20', '23:30', '23:40', '23:50',\n               'Jan 01 00:00', '00:10', '00:20', '00:30', '00:40', '00:50',\n               '01:00', '01:10', '01:20', '01:30', '01:40', '01:50', '02:00',\n               '02:10'],\n              [189298800, 189299400, 189300000, 189300600, 189301200, 189301800,\n               189302400, 189303000, 189303600, 189304200, 189304800, 189305400,\n               189306000, 189306600, 189307200, 189307800, 189308400, 189309000,\n               189309600, 189310200]),\n             ('5 minutes',\n              ['Dec 31 23:00', '23:05', '23:10', '23:15', '23:20', '23:25',\n               '23:30', '23:35', '23:40', '23:45', '23:50', '23:55',\n               'Jan 01 00:00', '00:05', '00:10', '00:15', '00:20', '00:25',\n               '00:30', '00:35', '00:40', '00:45', '00:50', '00:55', '01:00',\n               '01:05', '01:10', '01:15', '01:20', '01:25', '01:30', '01:35',\n               '01:40', '01:45', '01:50', '01:55', '02:00', '02:05'],\n              [189298800, 189299100, 189299400, 189299700, 189300000, 189300300,\n               189300600, 189300900, 189301200, 189301500, 189301800, 189302100,\n               189302400, 189302700, 189303000, 189303300, 189303600, 189303900,\n               189304200, 189304500, 189304800, 189305100, 189305400, 189305700,\n               189306000, 189306300, 189306600, 189306900, 189307200, 189307500,\n               189307800, 189308100, 189308400, 189308700, 189309000, 189309300,\n               189309600, 189309900])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 23, 18)),\n            [('12 hours',\n              ['Jun 09 00:00', '12:00', '10 00:00'],\n              [-1437868800, -1437825600, -1437782400]),\n             ('6 hours',\n              ['Jun 09 06:00', '12:00', '18:00', '10 00:00'],\n              [-1437847200, -1437825600, -1437804000, -1437782400]),\n             ('3 hours',\n              ['Jun 09 09:00', '12:00', '15:00', '18:00', '21:00', '10 00:00'],\n              [-1437836400, -1437825600, -1437814800, -1437804000, -1437793200,\n               -1437782400]),\n             ('2 hours',\n              ['Jun 09 10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00', '10 00:00'],\n              [-1437832800, -1437825600, -1437818400, -1437811200, -1437804000,\n               -1437796800, -1437789600, -1437782400]),\n             ('1 hour',\n              ['Jun 09 10:00', '11:00', '12:00', '13:00', '14:00', '15:00',\n               '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00',\n               '23:00',\n               '10 00:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000, -1437818400,\n               -1437814800, -1437811200, -1437807600, -1437804000, -1437800400,\n               -1437796800, -1437793200, -1437789600, -1437786000,\n               -1437782400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30', '14:00', '14:30', '15:00', '15:30', '16:00', '16:30',\n               '17:00', '17:30', '18:00', '18:30', '19:00', '19:30', '20:00',\n               '20:30', '21:00', '21:30', '22:00', '22:30', '23:00', '23:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200, -1437818400, -1437816600,\n               -1437814800, -1437813000, -1437811200, -1437809400, -1437807600,\n               -1437805800, -1437804000, -1437802200, -1437800400, -1437798600,\n               -1437796800, -1437795000, -1437793200, -1437791400, -1437789600,\n               -1437787800, -1437786000, -1437784200])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 13, 18)),\n            [('2 hours',\n              ['10:00', '12:00', '14:00'],\n              [-1437832800, -1437825600, -1437818400]),\n             ('1 hour',\n              ['10:00', '11:00', '12:00', '13:00', '14:00'],\n              [-1437832800, -1437829200, -1437825600, -1437822000,\n               -1437818400]),\n             ('30 minutes',\n              ['10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00',\n               '13:30'],\n              [-1437832800, -1437831000, -1437829200, -1437827400, -1437825600,\n               -1437823800, -1437822000, -1437820200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00', '11:15', '11:30',\n               '11:45', '12:00', '12:15', '12:30', '12:45', '13:00', '13:15',\n               '13:30'],\n              [-1437832800, -1437831900, -1437831000, -1437830100, -1437829200,\n               -1437828300, -1437827400, -1437826500, -1437825600, -1437824700,\n               -1437823800, -1437822900, -1437822000, -1437821100,\n               -1437820200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50', '11:00',\n               '11:10', '11:20', '11:30', '11:40', '11:50', '12:00', '12:10',\n               '12:20', '12:30', '12:40', '12:50', '13:00', '13:10', '13:20'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800, -1437829200, -1437828600, -1437828000, -1437827400,\n               -1437826800, -1437826200, -1437825600, -1437825000, -1437824400,\n               -1437823800, -1437823200, -1437822600, -1437822000, -1437821400,\n               -1437820800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50', '10:55', '11:00', '11:05',\n               '11:10', '11:15', '11:20', '11:25', '11:30', '11:35', '11:40',\n               '11:45', '11:50', '11:55', '12:00', '12:05', '12:10', '12:15',\n               '12:20', '12:25', '12:30', '12:35', '12:40', '12:45', '12:50',\n               '12:55', '13:00', '13:05', '13:10', '13:15', '13:20'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800, -1437829500, -1437829200, -1437828900, -1437828600,\n               -1437828300, -1437828000, -1437827700, -1437827400, -1437827100,\n               -1437826800, -1437826500, -1437826200, -1437825900, -1437825600,\n               -1437825300, -1437825000, -1437824700, -1437824400, -1437824100,\n               -1437823800, -1437823500, -1437823200, -1437822900, -1437822600,\n               -1437822300, -1437822000, -1437821700, -1437821400, -1437821100,\n               -1437820800])]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 48)),\n            [('30 minutes',\n              ['10:00', '10:30', '11:00'],\n              [-1437832800, -1437831000, -1437829200]),\n             ('15 minutes',\n              ['10:00', '10:15', '10:30', '10:45', '11:00'],\n              [-1437832800, -1437831900, -1437831000, -1437830100,\n               -1437829200]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30', '10:40', '10:50'],\n              [-1437832800, -1437832200, -1437831600, -1437831000, -1437830400,\n               -1437829800]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25', '10:30',\n               '10:35', '10:40', '10:45', '10:50'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300, -1437831000, -1437830700, -1437830400, -1437830100,\n               -1437829800]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21', '10:22', '10:23', '10:24', '10:25', '10:26', '10:27',\n               '10:28', '10:29', '10:30', '10:31', '10:32', '10:33', '10:34',\n               '10:35', '10:36', '10:37', '10:38', '10:39', '10:40', '10:41',\n               '10:42', '10:43', '10:44', '10:45', '10:46', '10:47', '10:48',\n               '10:49'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540, -1437831480, -1437831420, -1437831360,\n               -1437831300, -1437831240, -1437831180, -1437831120, -1437831060,\n               -1437831000, -1437830940, -1437830880, -1437830820, -1437830760,\n               -1437830700, -1437830640, -1437830580, -1437830520, -1437830460,\n               -1437830400, -1437830340, -1437830280, -1437830220, -1437830160,\n               -1437830100, -1437830040, -1437829980, -1437829920, -1437829860]\n              )]\n        )\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10), (1924, 6, 9, 10, 20)),\n            [('15 minutes',\n              ['10:00', '10:15', '10:30'],\n              [-1437832800, -1437831900, -1437831000]),\n             ('10 minutes',\n              ['10:00', '10:10', '10:20', '10:30'],\n              [-1437832800, -1437832200, -1437831600, -1437831000]),\n             ('5 minutes',\n              ['10:00', '10:05', '10:10', '10:15', '10:20', '10:25'],\n              [-1437832800, -1437832500, -1437832200, -1437831900, -1437831600,\n               -1437831300]),\n             ('1 minute',\n              ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06',\n               '10:07', '10:08', '10:09', '10:10', '10:11', '10:12', '10:13',\n               '10:14', '10:15', '10:16', '10:17', '10:18', '10:19', '10:20',\n               '10:21'],\n              [-1437832800, -1437832740, -1437832680, -1437832620, -1437832560,\n               -1437832500, -1437832440, -1437832380, -1437832320, -1437832260,\n               -1437832200, -1437832140, -1437832080, -1437832020, -1437831960,\n               -1437831900, -1437831840, -1437831780, -1437831720, -1437831660,\n               -1437831600, -1437831540]),\n             ('30 seconds',\n              ['10:00:00', '10:00:30', '10:01:00', '10:01:30', '10:02:00',\n               '10:02:30', '10:03:00', '10:03:30', '10:04:00', '10:04:30',\n               '10:05:00', '10:05:30', '10:06:00', '10:06:30', '10:07:00',\n               '10:07:30', '10:08:00', '10:08:30', '10:09:00', '10:09:30',\n               '10:10:00', '10:10:30', '10:11:00', '10:11:30', '10:12:00',\n               '10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30', '10:19:00', '10:19:30',\n               '10:20:00', '10:20:30'],\n              [-1437832800, -1437832770, -1437832740, -1437832710, -1437832680,\n               -1437832650, -1437832620, -1437832590, -1437832560, -1437832530,\n               -1437832500, -1437832470, -1437832440, -1437832410, -1437832380,\n               -1437832350, -1437832320, -1437832290, -1437832260, -1437832230,\n               -1437832200, -1437832170, -1437832140, -1437832110, -1437832080,\n               -1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690, -1437831660, -1437831630,\n               -1437831600, -1437831570])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 18, 12)),\n            [('5 minutes',\n              ['10:10', '10:15', '10:20'],\n              [-1437832200, -1437831900, -1437831600]),\n             ('1 minute',\n              ['10:12', '10:13', '10:14', '10:15', '10:16', '10:17', '10:18',\n               '10:19'],\n              [-1437832080, -1437832020, -1437831960, -1437831900, -1437831840,\n               -1437831780, -1437831720, -1437831660]),\n             ('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30', '10:14:00', '10:14:30',\n               '10:15:00', '10:15:30', '10:16:00', '10:16:30', '10:17:00',\n               '10:17:30', '10:18:00', '10:18:30'],\n              [-1437832050, -1437832020, -1437831990, -1437831960, -1437831930,\n               -1437831900, -1437831870, -1437831840, -1437831810, -1437831780,\n               -1437831750, -1437831720, -1437831690]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15', '10:13:30',\n               '10:13:45', '10:14:00', '10:14:15', '10:14:30', '10:14:45',\n               '10:15:00', '10:15:15', '10:15:30', '10:15:45', '10:16:00',\n               '10:16:15', '10:16:30', '10:16:45', '10:17:00', '10:17:15',\n               '10:17:30', '10:17:45', '10:18:00', '10:18:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005, -1437831990,\n               -1437831975, -1437831960, -1437831945, -1437831930, -1437831915,\n               -1437831900, -1437831885, -1437831870, -1437831855, -1437831840,\n               -1437831825, -1437831810, -1437831795, -1437831780, -1437831765,\n               -1437831750, -1437831735, -1437831720, -1437831705]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20', '10:13:30', '10:13:40', '10:13:50', '10:14:00',\n               '10:14:10', '10:14:20', '10:14:30', '10:14:40', '10:14:50',\n               '10:15:00', '10:15:10', '10:15:20', '10:15:30', '10:15:40',\n               '10:15:50', '10:16:00', '10:16:10', '10:16:20', '10:16:30',\n               '10:16:40', '10:16:50', '10:17:00', '10:17:10', '10:17:20',\n               '10:17:30', '10:17:40', '10:17:50', '10:18:00', '10:18:10',\n               '10:18:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000, -1437831990, -1437831980, -1437831970, -1437831960,\n               -1437831950, -1437831940, -1437831930, -1437831920, -1437831910,\n               -1437831900, -1437831890, -1437831880, -1437831870, -1437831860,\n               -1437831850, -1437831840, -1437831830, -1437831820, -1437831810,\n               -1437831800, -1437831790, -1437831780, -1437831770, -1437831760,\n               -1437831750, -1437831740, -1437831730, -1437831720, -1437831710,\n               -1437831700])])\n\n        self.assertEqual(\n            testbin((1924, 6, 9, 10, 12, 33), (1924, 6, 9, 10, 13, 12)),\n            [('30 seconds',\n              ['10:12:30', '10:13:00', '10:13:30'],\n              [-1437832050, -1437832020, -1437831990]),\n             ('15 seconds',\n              ['10:12:30', '10:12:45', '10:13:00', '10:13:15'],\n              [-1437832050, -1437832035, -1437832020, -1437832005]),\n             ('10 seconds',\n              ['10:12:30', '10:12:40', '10:12:50', '10:13:00', '10:13:10',\n               '10:13:20'],\n              [-1437832050, -1437832040, -1437832030, -1437832020, -1437832010,\n               -1437832000]),\n             ('5 seconds',\n              ['10:12:30', '10:12:35', '10:12:40', '10:12:45', '10:12:50',\n               '10:12:55', '10:13:00', '10:13:05', '10:13:10', '10:13:15'],\n              [-1437832050, -1437832045, -1437832040, -1437832035, -1437832030,\n               -1437832025, -1437832020, -1437832015, -1437832010,\n               -1437832005]),\n             ('1 second',\n              ['10:12:33', '10:12:34', '10:12:35', '10:12:36', '10:12:37',\n               '10:12:38', '10:12:39', '10:12:40', '10:12:41', '10:12:42',\n               '10:12:43', '10:12:44', '10:12:45', '10:12:46', '10:12:47',\n               '10:12:48', '10:12:49', '10:12:50', '10:12:51', '10:12:52',\n               '10:12:53', '10:12:54', '10:12:55', '10:12:56', '10:12:57',\n               '10:12:58', '10:12:59', '10:13:00', '10:13:01', '10:13:02',\n               '10:13:03', '10:13:04', '10:13:05', '10:13:06', '10:13:07',\n               '10:13:08', '10:13:09', '10:13:10', '10:13:11', '10:13:12',\n               '10:13:13'],\n              [-1437832047, -1437832046, -1437832045, -1437832044, -1437832043,\n               -1437832042, -1437832041, -1437832040, -1437832039, -1437832038,\n               -1437832037, -1437832036, -1437832035, -1437832034, -1437832033,\n               -1437832032, -1437832031, -1437832030, -1437832029, -1437832028,\n               -1437832027, -1437832026, -1437832025, -1437832024, -1437832023,\n               -1437832022, -1437832021, -1437832020, -1437832019, -1437832018,\n               -1437832017, -1437832016, -1437832015, -1437832014, -1437832013,\n               -1437832012, -1437832011, -1437832010, -1437832009, -1437832008,\n               -1437832007])])\n\n        self.assertEqual(\n            testbin((1973, 9, 14), (2010, 9, 8)),\n            [\n                ('50 years',\n                 ['1950', '2000', '2050'],\n                 [-631152000, 946684800, 2524608000]),\n                ('25 years',\n                 ['1950', '1975', '2000', '2025'],\n                 [-631152000, 157766400, 946684800, 1735689600]),\n                ('10 years',\n                 ['1970', '1980', '1990', '2000', '2010', '2020'],\n                 [0, 315532800, 631152000, 946684800, 1262304000, 1577836800]),\n                ('5 years',\n                 ['1970', '1975', '1980', '1985', '1990', '1995', '2000',\n                  '2005', '2010', '2015'],\n                 [0, 157766400, 315532800, 473385600, 631152000, 788918400,\n                  946684800, 1104537600, 1262304000, 1420070400]),\n                ('2 years',\n                 ['1972', '1974', '1976', '1978', '1980', '1982', '1984',\n                  '1986', '1988', '1990', '1992', '1994', '1996', '1998',\n                  '2000', '2002', '2004', '2006', '2008', '2010', '2012'],\n                 [63072000, 126230400, 189302400, 252460800, 315532800,\n                  378691200, 441763200, 504921600, 567993600, 631152000,\n                  694224000, 757382400, 820454400, 883612800, 946684800,\n                  1009843200, 1072915200, 1136073600, 1199145600, 1262304000,\n                  1325376000]),\n                ('1 year',\n                 ['1973', '1974', '1975', '1976', '1977', '1978', '1979',\n                  '1980', '1981', '1982', '1983', '1984', '1985', '1986',\n                  '1987', '1988', '1989', '1990', '1991', '1992', '1993',\n                  '1994', '1995', '1996', '1997', '1998', '1999', '2000',\n                  '2001', '2002', '2003', '2004', '2005', '2006', '2007',\n                  '2008', '2009', '2010', '2011'],\n                 [94694400, 126230400, 157766400, 189302400, 220924800,\n                  252460800, 283996800, 315532800, 347155200, 378691200,\n                  410227200, 441763200, 473385600, 504921600, 536457600,\n                  567993600, 599616000, 631152000, 662688000, 694224000,\n                  725846400, 757382400, 788918400, 820454400, 852076800,\n                  883612800, 915148800, 946684800, 978307200, 1009843200,\n                  1041379200, 1072915200, 1104537600, 1136073600, 1167609600,\n                  1199145600, 1230768000, 1262304000, 1293840000])\n            ]\n        )\n\n    def test_min_unique(self):\n        bins = time_binnings(self.dates, min_unique=7)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_add_unique(self):\n        bins = time_binnings(self.dates, add_unique=7)\n        self.assertNotEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds[:-1], self.dates)\n\n    def test_limits(self):\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=17)},\n            {9, 17})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=9, max_bins=16)},\n            {9})\n        self.assertEqual(\n            {b.nbins\n             for b in time_binnings(self.dates, min_bins=10, max_bins=17)},\n            {17})\n\n    def test_single_value(self):\n        dates = np.array([42])\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_multiple_identical(self):\n        dates = np.array([42] * 5)\n        bins = time_binnings(dates)\n        self.assertEqual(len(bins), 1)\n        np.testing.assert_equal(bins[0].thresholds, [42, 43])\n\n    def test_no_values(self):\n        dates = np.array([])\n        self.assertRaises(ValueError, time_binnings, dates)\n\n        dates = np.array([np.nan, np.nan])\n        self.assertRaises(ValueError, time_binnings, dates)\n\n\nclass TestBinDefinition(unittest.TestCase):\n    def test_labels(self):\n        thresholds = np.array([1, 2, 3.14])\n        self.assertEqual(BinDefinition(thresholds).labels,\n                         [\"1\", \"2\", \"3.14\"])\n        self.assertEqual(BinDefinition(thresholds, \"%.3f\").labels,\n                         [\"1.000\", \"2.000\", \"3.140\"])\n        self.assertEqual(BinDefinition(thresholds, lambda x: f\"b{x:g}\").labels,\n                         [\"b1\", \"b2\", \"b3.14\"])\n        self.assertEqual(BinDefinition(thresholds, list(\"abc\")).labels,\n                         list(\"abc\"))\n\n    def test_width_label(self):\n        thresholds = np.array([1, 2, 3.14])\n        self.assertEqual(BinDefinition(thresholds).width_label, \"\")\n        self.assertEqual(BinDefinition(thresholds, width=3).width_label, \"3\")\n        self.assertEqual(BinDefinition(thresholds, width=3.14).width_label, \"3.14\")\n\n    def test_thresholds(self):\n        thresholds = np.array([1, 2, 3.14])\n        bindef = BinDefinition(thresholds)\n        np.testing.assert_equal(bindef.thresholds, thresholds)\n        self.assertEqual(bindef.start, 1)\n        self.assertEqual(bindef.nbins, 2)\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
    ],
    "test_file_names": [
        "test_1.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "Starting Orange installation attempts...\nAttempting installation with Python 3.7...\nrunning build_ext\nrunning build_src\nbuild_src\nbuilding extension \"Orange.classification._simple_tree\" sources\nbuilding extension \"Orange.classification._tree_scorers\" sources\nbuilding extension \"Orange.data._valuecount\" sources\nbuilding extension \"Orange.data._contingency\" sources\nbuilding extension \"Orange.data._io\" sources\nbuilding extension \"Orange.data._variable\" sources\nbuilding extension \"Orange.distance._distance\" sources\nbuilding extension \"Orange.preprocess._discretize\" sources\nbuilding extension \"Orange.preprocess._relieff\" sources\nbuilding extension \"Orange.projection._som\" sources\nbuilding extension \"Orange.widgets.utils._grid_density\" sources\nbuild_src: building npy-pkg config files\ncustomize UnixCCompiler\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating /tmp/tmp_grgav16/tmp\ncreating /tmp/tmp_grgav16/tmp/tmp_grgav16\ncompile options: '-MMD -MF /tmp/tmp_grgav16/file.c.d -c'\ncc: /tmp/tmp_grgav16/file.c\ncustomize UnixCCompiler using build_ext\ncustomize UnixCCompiler\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating /tmp/tmptmyfvp0l/tmp\ncreating /tmp/tmptmyfvp0l/tmp/tmptmyfvp0l\ncompile options: '-MMD -MF /tmp/tmptmyfvp0l/file.c.d -c'\ncc: /tmp/tmptmyfvp0l/file.c\ncustomize UnixCCompiler using build_ext\nbuilding 'Orange.classification._simple_tree' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating build/temp.linux-x86_64-3.7/Orange\ncreating build/temp.linux-x86_64-3.7/Orange/classification\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/classification/_simple_tree.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/classification/_simple_tree.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/classification/_simple_tree.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.classification._tree_scorers' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/classification/_tree_scorers.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/classification/_tree_scorers.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/classification/_tree_scorers.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.data._valuecount' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating build/temp.linux-x86_64-3.7/Orange/data\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/data/_valuecount.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/data/_valuecount.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/data/_valuecount.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.data._contingency' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/data/_contingency.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/data/_contingency.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/data/_contingency.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.data._io' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/data/_io.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/data/_io.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/data/_io.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.data._variable' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/data/_variable.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/data/_variable.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/data/_variable.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.distance._distance' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating build/temp.linux-x86_64-3.7/Orange/distance\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/distance/_distance.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/distance/_distance.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/distance/_distance.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.preprocess._discretize' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating build/temp.linux-x86_64-3.7/Orange/preprocess\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/preprocess/_discretize.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/preprocess/_discretize.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/preprocess/_discretize.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.preprocess._relieff' extension\ncompiling C++ sources\nC compiler: c++ -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\nc++: Orange/preprocess/_relieff.cpp\nc++ -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/preprocess/_relieff.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/preprocess/_relieff.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.projection._som' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating build/temp.linux-x86_64-3.7/Orange/projection\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/projection/_som.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/projection/_som.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/projection/_som.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.widgets.utils._grid_density' extension\ncompiling C++ sources\nC compiler: c++ -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating build/temp.linux-x86_64-3.7/Orange/widgets\ncreating build/temp.linux-x86_64-3.7/Orange/widgets/utils\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\nc++: Orange/widgets/utils/_grid_density.cpp\nc++ -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/widgets/utils/_grid_density.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/widgets/utils/_grid_density.cpython-37m-x86_64-linux-gnu.so\nrunning develop\nrunning build_scripts\nrunning egg_info\nrunning build_src\nbuild_src\nbuilding extension \"Orange.classification._simple_tree\" sources\nbuilding extension \"Orange.classification._tree_scorers\" sources\nbuilding extension \"Orange.data._valuecount\" sources\nbuilding extension \"Orange.data._contingency\" sources\nbuilding extension \"Orange.data._io\" sources\nbuilding extension \"Orange.data._variable\" sources\nbuilding extension \"Orange.distance._distance\" sources\nbuilding extension \"Orange.preprocess._discretize\" sources\nbuilding extension \"Orange.preprocess._relieff\" sources\nbuilding extension \"Orange.projection._som\" sources\nbuilding extension \"Orange.widgets.utils._grid_density\" sources\nbuild_src: building npy-pkg config files\ncreating Orange3.egg-info\nwriting Orange3.egg-info/PKG-INFO\nwriting dependency_links to Orange3.egg-info/dependency_links.txt\nwriting entry points to Orange3.egg-info/entry_points.txt\nwriting requirements to Orange3.egg-info/requires.txt\nwriting top-level names to Orange3.egg-info/top_level.txt\nwriting manifest file 'Orange3.egg-info/SOURCES.txt'\nreading manifest file 'Orange3.egg-info/SOURCES.txt'\nreading manifest template 'MANIFEST.in'\nwarning: no files found matching 'README*' under directory 'Orange'\nwarning: no files found matching 'LICENSE' under directory 'Orange'\nwarning: no files found matching '*.basket' under directory 'Orange/datasets'\nwarning: no files found matching '*.js' under directory 'Orange/widgets'\nwarning: no files found matching '*.css' under directory 'Orange/widgets'\nwarning: no files found matching '*.html' under directory 'Orange/widgets'\nwarning: no files found matching 'COPYING'\nadding license file 'LICENSE'\nwriting manifest file 'Orange3.egg-info/SOURCES.txt'\nrunning build_ext\ncustomize UnixCCompiler\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating /tmp/tmpsz5adw5b/tmp\ncreating /tmp/tmpsz5adw5b/tmp/tmpsz5adw5b\ncompile options: '-MMD -MF /tmp/tmpsz5adw5b/file.c.d -c'\ncc: /tmp/tmpsz5adw5b/file.c\ncustomize UnixCCompiler using build_ext\ncustomize UnixCCompiler\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating /tmp/tmplq8zuf5h/tmp\ncreating /tmp/tmplq8zuf5h/tmp/tmplq8zuf5h\ncompile options: '-MMD -MF /tmp/tmplq8zuf5h/file.c.d -c'\ncc: /tmp/tmplq8zuf5h/file.c\ncustomize UnixCCompiler using build_ext\nCreating /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/Orange3.egg-link (link to .)\nAdding Orange3 3.25.0.dev0+f5b986b to easy-install.pth file\nInstalling orange-canvas script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/bin\n\nInstalled /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c\nProcessing dependencies for Orange3==3.25.0.dev0+f5b986b\nSearching for XlsxWriter==3.2.0\nBest match: XlsxWriter 3.2.0\nAdding XlsxWriter 3.2.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for xlrd==2.0.1\nBest match: xlrd 2.0.1\nAdding xlrd 2.0.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for setuptools==59.8.0\nBest match: setuptools 59.8.0\nAdding setuptools 59.8.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for serverfiles==0.3.1\nBest match: serverfiles 0.3.1\nAdding serverfiles 0.3.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for scipy==1.7.3\nBest match: scipy 1.7.3\nAdding scipy 1.7.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for scikit-learn==1.0.2\nBest match: scikit-learn 1.0.2\nAdding scikit-learn 1.0.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for requests==2.31.0\nBest match: requests 2.31.0\nAdding requests 2.31.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for PyYAML==6.0.1\nBest match: PyYAML 6.0.1\nAdding PyYAML 6.0.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for python-louvain==0.16\nBest match: python-louvain 0.16\nAdding python-louvain 0.16 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for pyqtgraph==0.10.0\nBest match: pyqtgraph 0.10.0\nAdding pyqtgraph 0.10.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for pip==24.0\nBest match: pip 24.0\nAdding pip 24.0 to easy-install.pth file\nInstalling pip script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/bin\nInstalling pip3 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/bin\nInstalling pip3.10 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for pandas==1.3.5\nBest match: pandas 1.3.5\nAdding pandas 1.3.5 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for orange-widget-base==4.22.0\nBest match: orange-widget-base 4.22.0\nAdding orange-widget-base 4.22.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for orange-canvas-core==0.1.35\nBest match: orange-canvas-core 0.1.35\nAdding orange-canvas-core 0.1.35 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for openpyxl==3.1.3\nBest match: openpyxl 3.1.3\nAdding openpyxl 3.1.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for openTSNE==1.0.1\nBest match: openTSNE 1.0.1\nAdding openTSNE 1.0.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for numpy==1.17.5\nBest match: numpy 1.17.5\nAdding numpy 1.17.5 to easy-install.pth file\nInstalling f2py script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/bin\nInstalling f2py3 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/bin\nInstalling f2py3.7 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for networkx==2.6.3\nBest match: networkx 2.6.3\nAdding networkx 2.6.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for matplotlib==3.5.3\nBest match: matplotlib 3.5.3\nAdding matplotlib 3.5.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for keyrings.alt==4.2.0\nBest match: keyrings.alt 4.2.0\nAdding keyrings.alt 4.2.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for keyring==24.1.1\nBest match: keyring 24.1.1\nAdding keyring 24.1.1 to easy-install.pth file\nInstalling keyring script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for joblib==1.3.2\nBest match: joblib 1.3.2\nAdding joblib 1.3.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for docutils==0.20.1\nBest match: docutils 0.20.1\nAdding docutils 0.20.1 to easy-install.pth file\nInstalling docutils script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for chardet==5.2.0\nBest match: chardet 5.2.0\nAdding chardet 5.2.0 to easy-install.pth file\nInstalling chardetect script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for Bottleneck==1.4.0\nBest match: Bottleneck 1.4.0\nAdding Bottleneck 1.4.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for baycomp==1.0.3\nBest match: baycomp 1.0.3\nAdding baycomp 1.0.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for AnyQt==0.2.0\nBest match: AnyQt 0.2.0\nAdding AnyQt 0.2.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for threadpoolctl==3.1.0\nBest match: threadpoolctl 3.1.0\nAdding threadpoolctl 3.1.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for urllib3==2.0.7\nBest match: urllib3 2.0.7\nAdding urllib3 2.0.7 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for idna==3.10\nBest match: idna 3.10\nAdding idna 3.10 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for certifi==2024.12.14\nBest match: certifi 2024.12.14\nAdding certifi 2024.12.14 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for charset-normalizer==3.4.1\nBest match: charset-normalizer 3.4.1\nAdding charset-normalizer 3.4.1 to easy-install.pth file\nInstalling normalizer script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for python-dateutil==2.9.0.post0\nBest match: python-dateutil 2.9.0.post0\nAdding python-dateutil 2.9.0.post0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for pytz==2024.2\nBest match: pytz 2024.2\nAdding pytz 2024.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for typing-extensions==4.7.1\nBest match: typing-extensions 4.7.1\nAdding typing-extensions 4.7.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for commonmark==0.9.1\nBest match: commonmark 0.9.1\nAdding commonmark 0.9.1 to easy-install.pth file\nInstalling cmark script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for qasync==0.25.0\nBest match: qasync 0.25.0\nAdding qasync 0.25.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for importlib-metadata==6.7.0\nBest match: importlib-metadata 6.7.0\nAdding importlib-metadata 6.7.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for packaging==24.0\nBest match: packaging 24.0\nAdding packaging 24.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for dictdiffer==0.9.0\nBest match: dictdiffer 0.9.0\nAdding dictdiffer 0.9.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for requests-cache==1.1.1\nBest match: requests-cache 1.1.1\nAdding requests-cache 1.1.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for et-xmlfile==1.1.0\nBest match: et-xmlfile 1.1.0\nAdding et-xmlfile 1.1.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for fonttools==4.38.0\nBest match: fonttools 4.38.0\nAdding fonttools 4.38.0 to easy-install.pth file\nInstalling fonttools script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/bin\nInstalling pyftmerge script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/bin\nInstalling pyftsubset script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/bin\nInstalling ttx script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for kiwisolver==1.4.5\nBest match: kiwisolver 1.4.5\nAdding kiwisolver 1.4.5 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for cycler==0.11.0\nBest match: cycler 0.11.0\nAdding cycler 0.11.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for Pillow==9.5.0\nBest match: Pillow 9.5.0\nAdding Pillow 9.5.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for pyparsing==3.1.4\nBest match: pyparsing 3.1.4\nAdding pyparsing 3.1.4 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for jaraco.classes==3.2.3\nBest match: jaraco.classes 3.2.3\nAdding jaraco.classes 3.2.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for SecretStorage==3.3.3\nBest match: SecretStorage 3.3.3\nAdding SecretStorage 3.3.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for jeepney==0.8.0\nBest match: jeepney 0.8.0\nAdding jeepney 0.8.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for importlib-resources==5.12.0\nBest match: importlib-resources 5.12.0\nAdding importlib-resources 5.12.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for six==1.17.0\nBest match: six 1.17.0\nAdding six 1.17.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for zipp==3.15.0\nBest match: zipp 3.15.0\nAdding zipp 3.15.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for platformdirs==4.0.0\nBest match: platformdirs 4.0.0\nAdding platformdirs 4.0.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for cattrs==23.1.2\nBest match: cattrs 23.1.2\nAdding cattrs 23.1.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for attrs==24.2.0\nBest match: attrs 24.2.0\nAdding attrs 24.2.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for url-normalize==1.4.3\nBest match: url-normalize 1.4.3\nAdding url-normalize 1.4.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for more-itertools==9.1.0\nBest match: more-itertools 9.1.0\nAdding more-itertools 9.1.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for cryptography==44.0.0\nBest match: cryptography 44.0.0\nAdding cryptography 44.0.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for exceptiongroup==1.2.2\nBest match: exceptiongroup 1.2.2\nAdding exceptiongroup 1.2.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for cffi==1.15.1\nBest match: cffi 1.15.1\nAdding cffi 1.15.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nSearching for pycparser==2.21\nBest match: pycparser 2.21\nAdding pycparser 2.21 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages\nFinished processing dependencies for Orange3==3.25.0.dev0+f5b986b\nVerifying Orange installation...\n✅ Orange installation successful!\nSuccessfully installed orange using Python 3.7\n",
    "setup_res_stderr": "Using CPython 3.7.9\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 18 packages in 182ms\nPrepared 18 packages in 1ms\nInstalled 18 packages in 231ms\n + cython==0.29.37\n + exceptiongroup==1.2.2\n + importlib-metadata==6.7.0\n + iniconfig==2.0.0\n + numpy==1.17.5\n + packaging==24.0\n + pluggy==1.2.0\n + pyqt5==5.15.10\n + pyqt5-qt5==5.15.16\n + pyqt5-sip==12.13.0\n + pyqtwebengine==5.15.6\n + pyqtwebengine-qt5==5.15.16\n + pytest==7.4.4\n + setuptools==59.8.0\n + tomli==2.0.1\n + typing-extensions==4.7.1\n + wheel==0.42.0\n + zipp==3.15.0\nResolved 48 packages in 231ms\nInstalled 42 packages in 462ms\n + baycomp==1.0.3\n + bottleneck==1.4.0\n + certifi==2024.12.14\n + cffi==1.15.1\n + chardet==5.2.0\n + charset-normalizer==3.4.1\n + cryptography==44.0.0\n + cycler==0.11.0\n + et-xmlfile==1.1.0\n + fonttools==4.38.0\n + idna==3.10\n + importlib-resources==5.12.0\n + jaraco-classes==3.2.3\n + jeepney==0.8.0\n + joblib==1.3.2\n + keyring==24.1.1\n + keyrings-alt==4.2.0\n + kiwisolver==1.4.5\n + matplotlib==3.5.3\n + more-itertools==9.1.0\n + networkx==2.6.3\n + openpyxl==3.1.3\n + opentsne==1.0.1\n + pandas==1.3.5\n + pillow==9.5.0\n + pip==24.0\n + pycparser==2.21\n + pyparsing==3.1.4\n + python-dateutil==2.9.0.post0\n + python-louvain==0.16\n + pytz==2024.2\n + pyyaml==6.0.1\n + requests==2.31.0\n + scikit-learn==1.0.2\n + scipy==1.7.3\n + secretstorage==3.3.3\n + serverfiles==0.3.1\n + six==1.17.0\n + threadpoolctl==3.1.0\n + urllib3==2.0.7\n + xlrd==2.0.1\n + xlsxwriter==3.2.0\nResolved 34 packages in 129ms\nInstalled 13 packages in 348ms\n + anyqt==0.2.0\n + attrs==24.2.0\n + cattrs==23.1.2\n + commonmark==0.9.1\n + dictdiffer==0.9.0\n + docutils==0.20.1\n + orange-canvas-core==0.1.35\n + orange-widget-base==4.22.0\n + platformdirs==4.0.0\n + pyqtgraph==0.10.0\n + qasync==0.25.0\n + requests-cache==1.1.1\n + url-normalize==1.4.3\nResolved 2 packages in 3ms\nInstalled 2 packages in 132ms\n + psycopg2==2.9.9\n + pymssql==2.3.2\nAudited 1 package in 3ms\nAudited 2 packages in 20ms\nOrange/classification/_simple_tree.c: In function ‘gain_ratio_c’:\nOrange/classification/_simple_tree.c:63:9: warning: implicit declaration of function ‘qsort_r’; did you mean ‘qsort’? [-Wimplicit-function-declaration]\n   63 |         qsort_r(base, nel, size, compar, thunk)\n      |         ^~~~~~~\nOrange/classification/_simple_tree.c:147:9: note: in expansion of macro ‘QSORT_R_FUNC’\n  147 |         QSORT_R_FUNC(examples, size, sizeof(struct Example), (void*) &compar_attr, compar_examples);\n      |         ^~~~~~~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/classification/_tree_scorers.c:567:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_2find_threshold_entropy’:\nOrange/classification/_tree_scorers.c:3115:27: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 3115 |   __pyx_t_7 = ((__pyx_v_N <= __pyx_v_min_leaf) != 0);\n      |                           ^~\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_6find_threshold_MSE’:\nOrange/classification/_tree_scorers.c:4619:27: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 4619 |   __pyx_t_1 = ((__pyx_v_N <= __pyx_v_min_leaf) != 0);\n      |                           ^~\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_8find_binarization_MSE’:\nOrange/classification/_tree_scorers.c:5396:43: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 5396 |           for (__pyx_t_22 = 0; __pyx_t_22 < __pyx_t_21; __pyx_t_22+=1) {\n      |                                           ^\nOrange/classification/_tree_scorers.c:5517:39: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 5517 |           __pyx_t_27 = ((__pyx_v_left >= __pyx_v_min_leaf) != 0);\n      |                                       ^~\nOrange/classification/_tree_scorers.c:5523:53: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 5523 |           __pyx_t_27 = (((__pyx_v_N - __pyx_v_left) >= __pyx_v_min_leaf) != 0);\n      |                                                     ^~\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_14compute_predictions_csr’:\nOrange/classification/_tree_scorers.c:7051:41: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 7051 |         for (__pyx_t_11 = 0; __pyx_t_11 < __pyx_t_10; __pyx_t_11+=1) {\n      |                                         ^\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_16compute_predictions_csc’:\nOrange/classification/_tree_scorers.c:7741:41: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 7741 |         for (__pyx_t_11 = 0; __pyx_t_11 < __pyx_t_10; __pyx_t_11+=1) {\n      |                                         ^\nOrange/classification/_tree_scorers.c:7801:143: warning: comparison of integer expressions of different signedness: ‘__pyx_t_5numpy_int32_t’ {aka ‘int’} and ‘unsigned int’ [-Wsign-compare]\n 7801 |               __pyx_t_17 = (((*((__pyx_t_5numpy_int32_t *) ( /* dim=0 */ (__pyx_v_indices.data + __pyx_t_18 * __pyx_v_indices.strides[0]) ))) != __pyx_v_i) != 0);\n      |                                                                                                                                               ^~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/data/_valuecount.c:567:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/data/_contingency.c:598:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nOrange/data/_io.c: In function ‘__pyx_pf_6Orange_4data_3_io_sparse_read_float.constprop’:\nOrange/data/_io.c:3881:24: warning: ‘__pyx_v_decs’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3881 |           __pyx_v_decs = (__pyx_v_decs / 10.0);\n      |           ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~\nOrange/data/_io.c:4070:24: warning: ‘__pyx_v_value’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4070 |           __pyx_t_10 = PyFloat_FromDouble(__pyx_v_value); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 221, __pyx_L5_error)\n      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nOrange/data/_io.c:480:40: warning: ‘__pyx_v_attr_index’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n  480 |   #define PyInt_FromLong               PyLong_FromLong\n      |                                        ^~~~~~~~~~~~~~~\nOrange/data/_io.c:1301:7: note: ‘__pyx_v_attr_index’ was declared here\n 1301 |   int __pyx_v_attr_index;\n      |       ^~~~~~~~~~~~~~~~~~\nOrange/data/_io.c:2935:25: warning: ‘__pyx_v_atomp’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 2935 |           __pyx_v_atomp = (__pyx_v_atomp + 1);\n      |           ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/distance/_distance.c:598:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/preprocess/_discretize.c:567:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/preprocess/_relieff.cpp:581:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/projection/_som.c:598:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pw_6Orange_10projection_4_som_5update_hex’:\nOrange/projection/_som.c:3655:7: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3655 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:3654:7: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3654 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pw_6Orange_10projection_4_som_7get_winners_sparse’:\nOrange/projection/_som.c:4547:223: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4547 |           *__Pyx_BufPtrStrided2d(__pyx_t_5numpy_int16_t *, __pyx_pybuffernd_winners.rcbuffer->pybuffer.buf, __pyx_t_38, __pyx_pybuffernd_winners.diminfo[0].strides, __pyx_t_39, __pyx_pybuffernd_winners.diminfo[1].strides) = __pyx_v_win_y;\n      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/projection/_som.c:4114:7: note: ‘__pyx_v_win_y’ was declared here\n 4114 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:4536:223: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4536 |           *__Pyx_BufPtrStrided2d(__pyx_t_5numpy_int16_t *, __pyx_pybuffernd_winners.rcbuffer->pybuffer.buf, __pyx_t_36, __pyx_pybuffernd_winners.diminfo[0].strides, __pyx_t_37, __pyx_pybuffernd_winners.diminfo[1].strides) = __pyx_v_win_x;\n      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/projection/_som.c:4113:7: note: ‘__pyx_v_win_x’ was declared here\n 4113 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pf_6Orange_10projection_4_som_8update_sparse.constprop’:\nOrange/projection/_som.c:4746:7: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4746 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:4745:7: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4745 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pw_6Orange_10projection_4_som_3update’:\nOrange/projection/_som.c:3141:7: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3141 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pw_6Orange_10projection_4_som_1get_winners’:\nOrange/projection/_som.c:2964:223: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 2964 |           *__Pyx_BufPtrStrided2d(__pyx_t_5numpy_int16_t *, __pyx_pybuffernd_winners.rcbuffer->pybuffer.buf, __pyx_t_27, __pyx_pybuffernd_winners.diminfo[0].strides, __pyx_t_28, __pyx_pybuffernd_winners.diminfo[1].strides) = __pyx_v_win_y;\n      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/projection/_som.c:2665:7: note: ‘__pyx_v_win_y’ was declared here\n 2665 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:2953:223: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 2953 |           *__Pyx_BufPtrStrided2d(__pyx_t_5numpy_int16_t *, __pyx_pybuffernd_winners.rcbuffer->pybuffer.buf, __pyx_t_25, __pyx_pybuffernd_winners.diminfo[0].strides, __pyx_t_26, __pyx_pybuffernd_winners.diminfo[1].strides) = __pyx_v_win_x;\n      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/projection/_som.c:2664:7: note: ‘__pyx_v_win_x’ was declared here\n 2664 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pf_6Orange_10projection_4_som_10update_sparse_hex.constprop’:\nOrange/projection/_som.c:5515:7: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 5515 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:5514:7: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 5514 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/setuptools/command/install.py:37: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n  setuptools.SetuptoolsDeprecationWarning,\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/setuptools/command/easy_install.py:159: EasyInstallDeprecationWarning: easy_install command is deprecated. Use build and pip and other standards-based tools.\n  EasyInstallDeprecationWarning,\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/setuptools/command/install.py:37: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n  setuptools.SetuptoolsDeprecationWarning,\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c/.venv/lib/python3.7/site-packages/setuptools/command/egg_info.py:628: SetuptoolsDeprecationWarning: Custom 'build_py' does not implement 'get_data_files_without_manifest'.\nPlease extend command classes from setuptools instead of distutils.\n  SetuptoolsDeprecationWarning\n",
    "new_commit_res_code": 0,
    "new_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.7.9, pytest-7.4.4, pluggy-1.2.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c\ncollected 10 items\n\nr2e_tests/test_1.py ..........                                           [100%]\n\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::TestTimeBinning::test_add_unique\nPASSED r2e_tests/test_1.py::TestTimeBinning::test_binning\nPASSED r2e_tests/test_1.py::TestTimeBinning::test_limits\nPASSED r2e_tests/test_1.py::TestTimeBinning::test_min_unique\nPASSED r2e_tests/test_1.py::TestTimeBinning::test_multiple_identical\nPASSED r2e_tests/test_1.py::TestTimeBinning::test_no_values\nPASSED r2e_tests/test_1.py::TestTimeBinning::test_single_value\nPASSED r2e_tests/test_1.py::TestBinDefinition::test_labels\nPASSED r2e_tests/test_1.py::TestBinDefinition::test_thresholds\nPASSED r2e_tests/test_1.py::TestBinDefinition::test_width_label\n============================== 10 passed in 1.76s ==============================\n",
    "new_commit_res_stderr": "",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.7.9, pytest-7.4.4, pluggy-1.2.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_f5b986b11e518191441420df8f8b84154c92e81c\ncollected 10 items\n\nr2e_tests/test_1.py .F........                                           [100%]\n\n=================================== FAILURES ===================================\n_________________________ TestTimeBinning.test_binning _________________________\n\nself = <r2e_tests.test_1.TestTimeBinning testMethod=test_binning>\n\n    def test_binning(self):\n        def testbin(start, end):\n            bins = _time_binnings(create(*start), create(*end), 3, 51)\n            return [(bin.width_label, bin.short_labels, bin.thresholds)\n                    for bin in reversed(bins)]\n    \n        self.assertEqual(\n            testbin((1975, 4, 2), (1989, 3, 1)),\n            [('10 years',\n              ['1970', '1980', '1990'],\n              [0, 315532800, 631152000]),\n             ('5 years',\n              ['1975', '1980', '1985', '1990'],\n              [157766400, 315532800, 473385600, 631152000]),\n             ('2 years',\n              ['1974', '1976', '1978', '1980', '1982', '1984', '1986', '1988',\n               '1990'],\n              [126230400, 189302400, 252460800, 315532800, 378691200, 441763200,\n               504921600, 567993600, 631152000]),\n             ('1 year',\n              ['1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982',\n               '1983', '1984', '1985', '1986', '1987', '1988', '1989', '1990'],\n              [157766400, 189302400, 220924800, 252460800, 283996800, 315532800,\n               347155200, 378691200, 410227200, 441763200, 473385600, 504921600,\n               536457600, 567993600, 599616000, 631152000]),\n             ('6 months',\n              ['75 Jan', 'Jul', '76 Jan', 'Jul', '77 Jan', 'Jul', '78 Jan',\n               'Jul', '79 Jan', 'Jul', '80 Jan', 'Jul', '81 Jan', 'Jul',\n               '82 Jan', 'Jul', '83 Jan', 'Jul', '84 Jan', 'Jul', '85 Jan',\n               'Jul', '86 Jan', 'Jul', '87 Jan', 'Jul', '88 Jan', 'Jul',\n               '89 Jan', 'Jul'],\n              [157766400, 173404800, 189302400, 205027200, 220924800, 236563200,\n               252460800, 268099200, 283996800, 299635200, 315532800, 331257600,\n               347155200, 362793600, 378691200, 394329600, 410227200, 425865600,\n               441763200, 457488000, 473385600, 489024000, 504921600, 520560000,\n               536457600, 552096000, 567993600, 583718400, 599616000,\n>              615254400])]\n        )\nE       AssertionError: Lists differ: [('10 years', ['70', '80', '90'], [0, 315532800, 63115200[1145 chars]00])] != [('10 years', ['1970', '1980', '1990'], [0, 315532800, 63[1209 chars]00])]\nE       \nE       First differing element 0:\nE       ('10 years', ['70', '80', '90'], [0, 315532800, 631152000])\nE       ('10 years', ['1970', '1980', '1990'], [0, 315532800, 631152000])\nE       \nE       Diff is 2435 characters long. Set self.maxDiff to None to see it.\n\nr2e_tests/test_1.py:62: AssertionError\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::TestTimeBinning::test_add_unique\nPASSED r2e_tests/test_1.py::TestTimeBinning::test_limits\nPASSED r2e_tests/test_1.py::TestTimeBinning::test_min_unique\nPASSED r2e_tests/test_1.py::TestTimeBinning::test_multiple_identical\nPASSED r2e_tests/test_1.py::TestTimeBinning::test_no_values\nPASSED r2e_tests/test_1.py::TestTimeBinning::test_single_value\nPASSED r2e_tests/test_1.py::TestBinDefinition::test_labels\nPASSED r2e_tests/test_1.py::TestBinDefinition::test_thresholds\nPASSED r2e_tests/test_1.py::TestBinDefinition::test_width_label\nFAILED r2e_tests/test_1.py::TestTimeBinning::test_binning - AssertionError: L...\n========================= 1 failed, 9 passed in 1.39s ==========================\n",
    "old_commit_res_stderr": ""
}
Orange/preprocess/discretize.py Orange/preprocess/tests/test_discretize.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Incorrect Year Labels in Time Binnings for Extended Date Ranges

**Description:**
When using the `time_binnings` function with longer date ranges, the year labels are displayed in a two-digit format instead of the expected four-digit format. This inconsistency causes related tests to fail.

**Example:**
```python
bins = time_binnings(start=(1975, 4, 2), end=(1989, 3, 1), min_bins=2, max_bins=50)
for bin in bins:
    print(bin.width_label, bin.short_labels)
```

**Expected Behavior:**
For a "10 years" bin, the labels should be:
```
10 years ['1970', '1980', '1990'] [0, 315532800, 631152000]
```

**Actual Behavior:**
The labels are incorrectly displayed as:
```
10 years ['70', '80', '90'] [0, 315532800, 631152000]
```

This mismatch between the expected and actual labels leads to failing tests and confusion for developers relying on accurate time binning.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### Orange/preprocess/discretize.py
import calendar
import re
import time
from typing import NamedTuple, List, Union, Callable
import datetime
from itertools import count

import numpy as np
import scipy.sparse as sp

from Orange.data import DiscreteVariable, Domain
from Orange.data.sql.table import SqlTable
from Orange.statistics import distribution, contingency, util as ut
from Orange.statistics.basic_stats import BasicStats
from Orange.util import Reprable
from .transformation import Transformation
from . import _discretize

__all__ = ["EqualFreq", "EqualWidth", "EntropyMDL", "DomainDiscretizer",
           "decimal_binnings", "time_binnings", "short_time_units",
           "BinDefinition"]


class Discretizer(Transformation):
    """Value transformer that returns an index of the bin for the given value.
    """
    def __init__(self, variable, points):
        super().__init__(variable)
        self.points = points

    @staticmethod
    def digitize(x, bins):
        if sp.issparse(x):
            if len(bins):
                x.data = np.digitize(x.data, bins)
            else:
                x = sp.csr_matrix(x.shape)
            return x
        else:
            return np.digitize(x, bins) if len(bins) else [0]*len(x)

    def transform(self, c):
        if sp.issparse(c):
            return self.digitize(c, self.points)
        elif c.size:
            return np.where(np.isnan(c), np.NaN, self.digitize(c, self.points))
        else:
            return np.array([], dtype=int)

    @staticmethod
    def _fmt_interval(low, high, formatter):
        assert low is not None or high is not None
        assert low is None or high is None or low < high
        if low is None or np.isinf(low):
            return f"< {formatter(high)}"
        if high is None or np.isinf(high):
            return f"≥ {formatter(low)}"
        return f"{formatter(low)} - {formatter(high)}"

    @classmethod
    def create_discretized_var(cls, var, points):
        def fmt(val):
            sval = var.str_val(val)
            # For decimal numbers, remove trailing 0's and . if no decimals left
            if re.match(r"^\d+\.\d+", sval):
                return sval.rstrip("0").rstrip(".")
            return sval

        lpoints = list(points)
        if lpoints:
            values = [
                cls._fmt_interval(low, high, fmt)
                for low, high in zip([-np.inf] + lpoints, lpoints + [np.inf])]
            to_sql = BinSql(var, lpoints)
        else:
            values = ["single_value"]
            to_sql = SingleValueSql(values[0])

        dvar = DiscreteVariable(name=var.name, values=values,
                                compute_value=cls(var, points),
                                sparse=var.sparse)
        dvar.source_variable = var
        dvar.to_sql = to_sql
        return dvar


class BinSql:
    def __init__(self, var, points):
        self.var = var
        self.points = points

    def __call__(self):
        return 'width_bucket(%s, ARRAY%s::double precision[])' % (
            self.var.to_sql(), str(self.points))


class SingleValueSql:
    def __init__(self, value):
        self.value = value

    def __call__(self):
        return "'%s'" % self.value


class Discretization(Reprable):
    """Abstract base class for discretization classes."""
    def __call__(self, data, variable):
        """
        Compute discretization of the given variable on the given data.
        Return a new variable with the appropriate domain
        (:obj:`Orange.data.DiscreteVariable.values`) and transformer
        (:obj:`Orange.data.Variable.compute_value`).
        """
        raise NotImplementedError(
            "Subclasses of 'Discretization' need to implement "
            "the call operator")


class EqualFreq(Discretization):
    """Discretization into bins with approximately equal number of data
    instances.

    .. attribute:: n

        Number of bins (default: 4). The actual number may be lower if the
        variable has less than n distinct values.
    """
    def __init__(self, n=4):
        self.n = n

    # noinspection PyProtectedMember
    def __call__(self, data, attribute):
        if type(data) == SqlTable:
            att = attribute.to_sql()
            quantiles = [(i + 1) / self.n for i in range(self.n - 1)]
            query = data._sql_query(
                ['quantile(%s, ARRAY%s)' % (att, str(quantiles))],
                use_time_sample=1000)
            with data._execute_sql_query(query) as cur:
                points = sorted(set(cur.fetchone()[0]))
        else:
            d = distribution.get_distribution(data, attribute)
            points = _discretize.split_eq_freq(d, self.n)
        return Discretizer.create_discretized_var(
            data.domain[attribute], points)

class EqualWidth(Discretization):
    """Discretization into a fixed number of bins with equal widths.

    .. attribute:: n

        Number of bins (default: 4).
    """
    def __init__(self, n=4):
        self.n = n

    # noinspection PyProtectedMember
    def __call__(self, data, attribute, fixed=None):
        if fixed:
            min, max = fixed[attribute.name]
            points = self._split_eq_width(min, max)
        else:
            if type(data) == SqlTable:
                stats = BasicStats(data, attribute)
                points = self._split_eq_width(stats.min, stats.max)
            else:
                values = data[:, attribute]
                values = values.X if values.X.size else values.Y
                min, max = ut.nanmin(values), ut.nanmax(values)
                points = self._split_eq_width(min, max)
        return Discretizer.create_discretized_var(
            data.domain[attribute], points)

    def _split_eq_width(self, min, max):
        if np.isnan(min) or np.isnan(max) or min == max:
            return []
        dif = (max - min) / self.n
        return [min + (i + 1) * dif for i in range(self.n - 1)]


class BinDefinition(NamedTuple):
    thresholds: np.ndarray  # thresholds, including the top
    labels: List[str]  # friendly-formatted thresholds
    short_labels: List[str]  # shorter labels (e.g. simplified dates)
    width: Union[float, None]  # widths, if uniform; otherwise None
    width_label: str  # friendly-formatted width (e.g. '50' or '2 weeks')


# NamedTupleMeta doesn't allow to define __new__ so we need a subclass
# Name of the class has to be the same to match the namedtuple name
# pylint: disable=function-redefined
class BinDefinition(BinDefinition):
    def __new__(cls, thresholds, labels="%g",
                short_labels=None, width=None, width_label=""):

        def get_labels(fmt, default=None):
            if fmt is None:
                return default
            if isinstance(fmt, str):
                return [fmt % x for x in thresholds]
            elif isinstance(fmt, Callable):
                return [fmt(x) for x in thresholds]
            else:
                return fmt

        labels = get_labels(labels)
        short_labels = get_labels(short_labels, labels)
        if not width_label and width is not None:
            width_label = f"{width:g}"
        return super().__new__(
            cls, thresholds, labels, short_labels, width, width_label)

    @property
    def start(self) -> float:
        return self.thresholds[0]

    @property
    def nbins(self) -> int:
        return len(self.thresholds) - 1


def decimal_binnings(
        data, *, min_width=0, min_bins=2, max_bins=50,
        min_unique=5, add_unique=0,
        factors=(0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20),
        label_fmt="%g"):
    """
    Find a set of nice splits of data into bins

    The function first computes the scaling factor that is, the power of 10
    that brings the interval of values within [0, 1]. For instances, if the
    numbers come from interaval 10004001 and 10007005, the width of the
    interval is 3004, so the scaling factor is 1000.

    The function next considers bin widths that are products of scaling and
    different factors from 20 to 0.01 that make sense in decimal scale
    (see default value for argument `factors`). For each width, it rounds the
    minimal value down to this width and the maximal value up, and it computes
    the number of bins of that width that fit between these two values.
    If the number of bins is between `min_bins` and `max_bins`, and the width
    is at least `min_width`, this is a valid interval.

    If the data has no more than `min_unique` unique values, the function will
    add a set of bins that put each value into its own bin.

    If the data has no more than `add_unique` values, that last bins will put
    each value into its own bin.

    Args:
        data (np.ndarray):
            vector of data points; values may repeat, and nans and infs are
            filtered out.
        min_width (float): minimal bin width
        min_bins (int): minimal number of bins
        max_bins (int):
            maximal number of bins; the number of bins will never exceed the
            number of unique values
        min_unique (int):
            if the number of unique values are less or equal to `min_unique`,
            the function returns a single binning that matches that values in
            the data
        add_unique (int):
            similar to `min_unique` except that such bins are added to the list;
            set to 0 to disable
        factors (list of float):
            The factors with which the scaling is multiplied. Default is
            `(0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20)`,
            so if scaling is 1000, considered bin widths are 20000, 10000,
            5000, 2000, 1000, 500, 250, 200, 100, 50, 25, 20 and 10.
        label_fmt (str or Callable):
            A format string (default: "%g") used for threshold labels,
            or a function for formatting thresholds (e.g. var.str_val)

    Returns:
        bin_boundaries (list of np.ndarray): a list of bin boundaries,
            including the top boundary of the last interval, hence the list
            size equals the number bins + 1. These array match the `bin`
            argument of `numpy.histogram`.

            This is returned if `return_defs` is left `True`.

        bin_definition (list of BinDefinition):
            `BinDefinition` is a named tuple containing the beginning of the
            first bin (`start`), number of bins (`nbins`) and their widths
            (`width`). The last value can also be a `nd.array` with `nbins + 1`
            elements, which describes bins of unequal width and is used for
            binnings that match the unique values in the data (see `min_unique`
            and `add_unique`).

            This is returned if `return_defs` is `False`.
    """
    bins = []

    mn, mx, unique = _min_max_unique(data)
    if len(unique) <= max(min_unique, add_unique):
        bins.append(BinDefinition(_unique_thresholds(unique), label_fmt))
        if len(unique) <= min_unique:
            return bins

    diff = mx - mn
    f10 = 10 ** -np.floor(np.log10(diff))
    max_bins = min(max_bins, len(unique))
    for f in factors:
        width = f / f10
        if width < min_width:
            continue
        mn_ = np.floor(mn / width) * width
        mx_ = np.ceil(mx / width) * width
        nbins = np.round((mx_ - mn_) / width)
        if min_bins <= nbins <= max_bins \
                and (not bins or bins[-1].nbins != nbins):
            bin_def = BinDefinition(mn_ + width * np.arange(nbins + 1),
                                    label_fmt, None, width)
            bins.append(bin_def)
    return bins


def time_binnings(data, *, min_bins=2, max_bins=50, min_unique=5, add_unique=0):
    """
    Find a set of nice splits of time variable data into bins

    The function considers bin widths of

    - 1, 5, 10, 15, 30 seconds.
    - 1, 5, 10, 15, 30 minutes,
    - 1, 2, 3, 6, 12 hours,
    - 1 day,
    - 1, 2 weeks,
    - 1, 2, 3, 6 months,
    - 1, 2, 5, 10, 25, 50, 100 years,

    and returns those that yield between `min_bins` and `max_bins` intervals.

    Args:
        data (np.ndarray):
            vector of data points; values may repeat, and nans and infs are
            filtered out.
        min_bins (int): minimal number of bins
        max_bins (int):
            maximal number of bins; the number of bins will never exceed the
            number of unique values

    Returns:
        bin_boundaries (list): a list of possible binning.
            Each element of `bin_boundaries` is a tuple consisting of a label
            describing the bin size (e.g. `2 weeks`) and a list of thresholds.
            Thresholds are given as pairs
            (number_of_seconds_since_epoch, label).
    """
    mn, mx, unique = _min_max_unique(data)
    mn, mx = time.gmtime(mn), time.gmtime(mx)
    bins = []
    if len(unique) <= max(min_unique, add_unique):
        bins.append(_unique_time_bins(unique))
    if len(unique) > min_unique:
        bins += _time_binnings(mn, mx, min_bins + 1, max_bins + 1)
    return bins


def _time_binnings(mn, mx, min_pts, max_pts):
    yfmt = "%y " if mn.tm_year >= 1950 else "%Y "
    bins = []
    for place, step, fmt, unit in (
            [(5, x, "%H:%M:%S", "second") for x in (1, 5, 10, 15, 30)] +
            [(4, x, "%b %d %H:%M", "minute") for x in (1, 5, 10, 15, 30)] +
            [(3, x, yfmt + "%b %d %H:%M", "hour") for x in (1, 2, 3, 6, 12)] +
            [(2, 1, yfmt + "%b %d", "day")] +
            [(2, x, yfmt + "%b %d", "week") for x in (7, 14)] +
            [(1, x, yfmt + "%b", "month") for x in (1, 2, 3, 6)] +
            [(0, x, yfmt.strip(), "year") for x in (1, 2, 5, 10, 25, 50, 100)]):
        times = _time_range(mn, mx, place, step, min_pts, max_pts)
        if not times:
            continue
        times = [time.struct_time(t + (0, 0, 0)) for t in times]
        thresholds = [calendar.timegm(t) for t in times]
        labels = [time.strftime(fmt, t) for t in times]
        short_labels = _simplified_labels(labels)
        if place == 2 and step >= 7:
            unit_label = f"{step // 7} week{'s' * (step > 7)}"
        else:
            unit_label = f"{step} {unit}{'s' * (step > 1)}"
        new_bins = BinDefinition(
            thresholds, labels, short_labels, None, unit_label)
        if not bins or new_bins.nbins != bins[-1].nbins:
            bins.append(new_bins)
    return bins


# datetime + deltatime is not very useful here because deltatime is
# given a number of days, not years or months, so it doesn't allow
# for specifying a step of 1 month
def _time_range(start, end, place, step, min_pts, max_pts,
                _zeros=(0, 1, 1, 0, 0, 0)):
    if place == 2 and step % 7 == 0:
        startd = datetime.date(*start[:3])
        startd -= datetime.timedelta(days=-startd.weekday())
        start = [startd.year, startd.month, startd.day, 0, 0, 0]
    else:
        start = list(
            start[:place]
            + ((start[place] - _zeros[place]) // step * step + _zeros[place], )
            + _zeros[place + 1:])
    end = list(end[:place + 1] + _zeros[place + 1:])
    s = [tuple(start)]
    for _ in range(max_pts - 1):
        start[place] += step
        if place >= 3:  # hours, minutes, seconds
            for pos, maxval in enumerate((60, 60, 24), start=1):
                if start[-pos] >= maxval:
                    start[-pos - 1] += 1
                    start[-pos] %= maxval
        if place >= 2:
            md = _month_days(*start[:2])
            if start[2] > md:
                start[1] += 1
                start[2] %= md
        if start[1] > 12:
            start[0] += 1
            start[1] %= 12
        s.append(tuple(start))
        if start > end:
            return s if len(s) >= min_pts else None
    return None


def _month_days(year, month,
                _md=(None, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)):
    return _md[month] + (
        month == 2 and (year % 400 == 0 or year % 4 == 0 and year % 100 != 0))


def _simplified_labels(labels):
    labels = labels[:]
    to_remove = "42"
    while True:
        firsts = {f for f, *_ in (lab.split() for lab in labels)}
        if len(firsts) > 1:
            break
        to_remove = firsts.pop()
        flen = len(to_remove) + 1
        if any(len(lab) == flen for lab in labels):
            break
        labels = [lab[flen:] for lab in labels]
    for i in range(len(labels) - 1, 0, -1):
        for k, c, d in zip(count(), labels[i].split(), labels[i - 1].split()):
            if c != d:
                labels[i] = " ".join(labels[i].split()[k:])
                break
    # If the last thing removed were month names and the labels continues with
    # hours, keep month name in the first label; "08 12:29" looks awkward.
    if not to_remove[0].isdigit() and ":" in labels[0]:
        labels[0] = f"{to_remove} {labels[0]}"
    return labels


def _unique_time_bins(unique):
    times = [time.gmtime(x) for x in unique]
    fmt = f'{"%y " if times[0][0] >= 1950 else "%Y "} %b %d'
    fmt += " %H:%M" * (len({t[2:] for t in times}) > 1)
    fmt += ":%S" * bool(np.all(unique % 60 == 0))
    labels = [time.strftime(fmt, x) for x in times]
    short_labels = _simplified_labels(labels)
    return BinDefinition(_unique_thresholds(unique), labels, short_labels)


def _unique_thresholds(unique):
    if len(unique) >= 2:
        # make the last bin the same width as the one before
        last_boundary = 2 * unique[-1] - unique[-2]
    else:
        last_boundary = unique[0] + 1
    return np.hstack((unique, [last_boundary]))


def _min_max_unique(data):
    unique = np.unique(data)
    unique = unique[np.isfinite(unique)]
    if not unique.size:
        raise ValueError("no valid (non-nan) data")
    return unique[0], unique[-1], unique


short_time_units = dict(seconds="sec", minutes="min", hours="hrs",
                        weeks="wks", months="mon", years="yrs",
                        second="sec", minute="min", month="mon")


# noinspection PyPep8Naming
class EntropyMDL(Discretization):
    """
    Discretization into bins inferred by recursively splitting the values to
    minimize the class-entropy. The procedure stops when further splits would
    decrease the entropy for less than the corresponding increase of minimal
    description length (MDL). [FayyadIrani93].

    If there are no suitable cut-off points, the procedure returns a single bin,
    which means that the new feature is constant and can be removed.

    .. attribute:: force

        Induce at least one cut-off point, even when its information
        gain is lower than MDL (default: False).

    """
    def __init__(self, force=False):
        self.force = force

    def __call__(self, data, attribute):
        cont = contingency.get_contingency(data, attribute)
        values, I = cont.values, cont.counts.T
        cut_ind = np.array(self._entropy_discretize_sorted(I, self.force))
        if len(cut_ind) > 0:
            # "the midpoint between each successive pair of examples" (FI p.1)
            points = (values[cut_ind] + values[cut_ind - 1]) / 2.
        else:
            points = []
        return Discretizer.create_discretized_var(
            data.domain[attribute], points)

    @classmethod
    def _normalize(cls, X, axis=None, out=None):
        """
        Normalize `X` array so it sums to 1.0 over the `axis`.

        Parameters
        ----------
        X : array
            Array to normalize.
        axis : optional int
            Axis over which the resulting array sums to 1.
        out : optional array
            Output array of the same shape as X.
        """
        X = np.asarray(X, dtype=float)
        scale = np.sum(X, axis=axis, keepdims=True)
        if out is None:
            return X / scale
        else:
            if out is not X:
                assert out.shape == X.shape
                out[:] = X
            out /= scale
            return out

    @classmethod
    def _entropy_normalized(cls, D, axis=None):
        """
        Compute the entropy of distribution array `D`.

        `D` must be a distribution (i.e. sum to 1.0 over `axis`)

        Parameters
        ----------
        D : array
            Distribution.
        axis : optional int
            Axis of `D` along which to compute the entropy.

        """
        # req: (np.sum(D, axis=axis) >= 0).all()
        # req: (np.sum(D, axis=axis) <= 1).all()
        # req: np.all(np.abs(np.sum(D, axis=axis) - 1) < 1e-9)

        D = np.asarray(D)
        Dc = np.clip(D, np.finfo(D.dtype).eps, 1.0)
        return - np.sum(D * np.log2(Dc), axis=axis)

    @classmethod
    def _entropy(cls, D, axis=None):
        """
        Compute the entropy of distribution `D`.

        Parameters
        ----------
        D : array
            Distribution.
        axis : optional int
            Axis of `D` along which to compute the entropy.

        """
        D = cls._normalize(D, axis=axis)
        return cls._entropy_normalized(D, axis=axis)

    @classmethod
    def _entropy1(cls, D):
        """
        Compute the entropy of distributions in `D`
        (one per each row).
        """
        D = cls._normalize(D)
        return _discretize.entropy_normalized1(D)

    @classmethod
    def _entropy2(cls, D):
        """
        Compute the entropy of distributions in `D`
        (one per each row).
        """
        D = cls._normalize(D, axis=1)
        return _discretize.entropy_normalized2(D)

    @classmethod
    def _entropy_cuts_sorted(cls, CS):
        """
        Return the class information entropy induced by partitioning
        the `CS` distribution at all N-1 candidate cut points.

        Parameters
        ----------
        CS : (N, K) array of class distributions.
        """
        CS = np.asarray(CS)
        # |--|-------|--------|
        #  S1    ^       S2
        # S1 contains all points which are <= to cut point
        # Cumulative distributions for S1 and S2 (left right set)
        # i.e. a cut at index i separates the CS into S1Dist[i] and S2Dist[i]
        S1Dist = np.cumsum(CS, axis=0)[:-1]
        S2Dist = np.cumsum(CS[::-1], axis=0)[-2::-1]

        # Entropy of S1[i] and S2[i] sets
        ES1 = cls._entropy2(S1Dist)
        ES2 = cls._entropy2(S2Dist)

        # Number of cases in S1[i] and S2[i] sets
        S1_count = np.sum(S1Dist, axis=1)
        S2_count = np.sum(S2Dist, axis=1)

        # Number of all cases
        S_count = np.sum(CS)

        ES1w = ES1 * S1_count / S_count
        ES2w = ES2 * S2_count / S_count

        # E(A, T; S) Class information entropy of the partition S
        E = ES1w + ES2w

        return E, ES1, ES2

    @classmethod
    def _entropy_discretize_sorted(cls, C, force=False):
        """
        Entropy discretization on a sorted C.

        :param C: (N, K) array of class distributions.

        """
        E, ES1, ES2 = cls._entropy_cuts_sorted(C)
        # TODO: Also get the left right distribution counts from
        # entropy_cuts_sorted,

        # Note the + 1
        if len(E) == 0:
            return []
        cut_index = np.argmin(E) + 1

        # Distribution of classed in S1, S2 and S
        S1_c = np.sum(C[:cut_index], axis=0)
        S2_c = np.sum(C[cut_index:], axis=0)
        S_c = S1_c + S2_c

        ES = cls._entropy1(np.sum(C, axis=0))
        ES1, ES2 = ES1[cut_index - 1], ES2[cut_index - 1]

        # Information gain of the best split
        Gain = ES - E[cut_index - 1]
        # Number of different classes in S, S1 and S2
        k = float(np.sum(S_c > 0))
        k1 = float(np.sum(S1_c > 0))
        k2 = float(np.sum(S2_c > 0))

        assert k > 0
        delta = np.log2(3 ** k - 2) - (k * ES - k1 * ES1 - k2 * ES2)
        N = float(np.sum(S_c))

        if Gain > np.log2(N - 1) / N + delta / N:
            # Accept the cut point and recursively split the subsets.
            left, right = [], []
            if k1 > 1 and cut_index > 1:
                left = cls._entropy_discretize_sorted(C[:cut_index, :])
            if k2 > 1 and cut_index < len(C) - 1:
                right = cls._entropy_discretize_sorted(C[cut_index:, :])
            return left + [cut_index] + [i + cut_index for i in right]
        elif force:
            return [cut_index]
        else:
            return []


class DomainDiscretizer(Reprable):
    """Discretizes all continuous features in the data.

    .. attribute:: method

        Feature discretization method (instance of
        :obj:`Orange.preprocess.Discretization`). If `None` (default),
        :class:`Orange.preprocess.EqualFreq` with 4 intervals is
        used.

    .. attribute:: clean

        If `True`, features discretized into a single interval constant are
        removed. This is useful for discretization methods that infer the
        number of intervals from the data, such as
        :class:`Orange.preprocess.EntropyMDL` (default: `True`).

    .. attribute:: discretize_class

        Determines whether a target is also discretized if it is continuous.
        (default: `False`)
    """
    def __init__(self, discretize_class=False, method=None, clean=True,
                 fixed=None):
        self.discretize_class = discretize_class
        self.method = method
        self.clean = clean
        self.fixed = fixed

    def __call__(self, data, fixed=None):
        """
        Compute and return discretized domain.

        :param data: Data to discretize.
        """

        def transform_list(s, fixed=None):
            new_vars = []
            for var in s:
                if var.is_continuous:
                    if fixed and var.name in fixed.keys():
                        nv = method(data, var, fixed)
                    else:
                        nv = method(data, var)
                    if not self.clean or len(nv.values) > 1:
                        new_vars.append(nv)
                else:
                    new_vars.append(var)
            return new_vars
        if self.method is None:
            method = EqualFreq(n=4)
        else:
            method = self.method
        domain = data.domain
        new_attrs = transform_list(domain.attributes, fixed or self.fixed)
        if self.discretize_class:
            new_classes = transform_list(domain.class_vars)
        else:
            new_classes = domain.class_vars
        return Domain(new_attrs, new_classes)

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
[ISSUE]
**Title:** Incorrect Year Labels in Time Binnings for Extended Date Ranges

**Description:**
When using the `time_binnings` function with longer date ranges, the year labels are displayed in a two-digit format instead of the expected four-digit format. This inconsistency causes related tests to fail.

**Example:**
```python
bins = time_binnings(start=(1975, 4, 2), end=(1989, 3, 1), min_bins=2, max_bins=50)
for bin in bins:
    print(bin.width_label, bin.short_labels)
```

**Expected Behavior:**
For a "10 years" bin, the labels should be:
```
10 years ['1970', '1980', '1990'] [0, 315532800, 631152000]
```

**Actual Behavior:**
The labels are incorrectly displayed as:
```
10 years ['70', '80', '90'] [0, 315532800, 631152000]
```

This mismatch between the expected and actual labels leads to failing tests and confusion for developers relying on accurate time binning.

[/ISSUE]
{
    "TestTimeBinning.test_add_unique": "PASSED",
    "TestTimeBinning.test_binning": "PASSED",
    "TestTimeBinning.test_limits": "PASSED",
    "TestTimeBinning.test_min_unique": "PASSED",
    "TestTimeBinning.test_multiple_identical": "PASSED",
    "TestTimeBinning.test_no_values": "PASSED",
    "TestTimeBinning.test_single_value": "PASSED",
    "TestBinDefinition.test_labels": "PASSED",
    "TestBinDefinition.test_thresholds": "PASSED",
    "TestBinDefinition.test_width_label": "PASSED"
}
diff --git a/Orange/preprocess/discretize.py b/Orange/preprocess/discretize.py
index 7b0e9e224..8b02bab1d 100644
--- a/Orange/preprocess/discretize.py
+++ b/Orange/preprocess/discretize.py
@@ -358,16 +358,15 @@ def time_binnings(data, *, min_bins=2, max_bins=50, min_unique=5, add_unique=0):
 
 
 def _time_binnings(mn, mx, min_pts, max_pts):
-    yfmt = "%y " if mn.tm_year >= 1950 else "%Y "
     bins = []
     for place, step, fmt, unit in (
             [(5, x, "%H:%M:%S", "second") for x in (1, 5, 10, 15, 30)] +
             [(4, x, "%b %d %H:%M", "minute") for x in (1, 5, 10, 15, 30)] +
-            [(3, x, yfmt + "%b %d %H:%M", "hour") for x in (1, 2, 3, 6, 12)] +
-            [(2, 1, yfmt + "%b %d", "day")] +
-            [(2, x, yfmt + "%b %d", "week") for x in (7, 14)] +
-            [(1, x, yfmt + "%b", "month") for x in (1, 2, 3, 6)] +
-            [(0, x, yfmt.strip(), "year") for x in (1, 2, 5, 10, 25, 50, 100)]):
+            [(3, x, "%y %b %d %H:%M", "hour") for x in (1, 2, 3, 6, 12)] +
+            [(2, 1, "%y %b %d", "day")] +
+            [(2, x, "%y %b %d", "week") for x in (7, 14)] +
+            [(1, x, "%y %b", "month") for x in (1, 2, 3, 6)] +
+            [(0, x, "%Y", "year") for x in (1, 2, 5, 10, 25, 50, 100)]):
         times = _time_range(mn, mx, place, step, min_pts, max_pts)
         if not times:
             continue
@@ -437,10 +436,10 @@ def _simplified_labels(labels):
         if len(firsts) > 1:
             break
         to_remove = firsts.pop()
-        flen = len(to_remove) + 1
+        flen = len(to_remove)
         if any(len(lab) == flen for lab in labels):
             break
-        labels = [lab[flen:] for lab in labels]
+        labels = [lab[flen+1:] for lab in labels]
     for i in range(len(labels) - 1, 0, -1):
         for k, c, d in zip(count(), labels[i].split(), labels[i - 1].split()):
             if c != d:
@@ -455,7 +454,7 @@ def _simplified_labels(labels):
 
 def _unique_time_bins(unique):
     times = [time.gmtime(x) for x in unique]
-    fmt = f'{"%y " if times[0][0] >= 1950 else "%Y "} %b %d'
+    fmt = f'%y %b %d'
     fmt += " %H:%M" * (len({t[2:] for t in times}) > 1)
     fmt += ":%S" * bool(np.all(unique % 60 == 0))
     labels = [time.strftime(fmt, x) for x in times]

{"Orange/preprocess/discretize.py": "import calendar\nimport re\nimport time\nfrom typing import NamedTuple, List, Union, Callable\nimport datetime\nfrom itertools import count\n\nimport numpy as np\nimport scipy.sparse as sp\n\nfrom Orange.data import DiscreteVariable, Domain\nfrom Orange.data.sql.table import SqlTable\nfrom Orange.statistics import distribution, contingency, util as ut\nfrom Orange.statistics.basic_stats import BasicStats\nfrom Orange.util import Reprable\nfrom .transformation import Transformation\nfrom . import _discretize\n\n__all__ = [\"EqualFreq\", \"EqualWidth\", \"EntropyMDL\", \"DomainDiscretizer\",\n           \"decimal_binnings\", \"time_binnings\", \"short_time_units\",\n           \"BinDefinition\"]\n\n\nclass Discretizer(Transformation):\n    \"\"\"Value transformer that returns an index of the bin for the given value.\n    \"\"\"\n    def __init__(self, variable, points):\n        super().__init__(variable)\n        self.points = points\n\n    @staticmethod\n    def digitize(x, bins):\n        if sp.issparse(x):\n            if len(bins):\n                x.data = np.digitize(x.data, bins)\n            else:\n                x = sp.csr_matrix(x.shape)\n            return x\n        else:\n            return np.digitize(x, bins) if len(bins) else [0]*len(x)\n\n    def transform(self, c):\n        if sp.issparse(c):\n            return self.digitize(c, self.points)\n        elif c.size:\n            return np.where(np.isnan(c), np.NaN, self.digitize(c, self.points))\n        else:\n            return np.array([], dtype=int)\n\n    @staticmethod\n    def _fmt_interval(low, high, formatter):\n        assert low is not None or high is not None\n        assert low is None or high is None or low < high\n        if low is None or np.isinf(low):\n            return f\"< {formatter(high)}\"\n        if high is None or np.isinf(high):\n            return f\"\u2265 {formatter(low)}\"\n        return f\"{formatter(low)} - {formatter(high)}\"\n\n    @classmethod\n    def create_discretized_var(cls, var, points):\n        def fmt(val):\n            sval = var.str_val(val)\n            # For decimal numbers, remove trailing 0's and . if no decimals left\n            if re.match(r\"^\\d+\\.\\d+\", sval):\n                return sval.rstrip(\"0\").rstrip(\".\")\n            return sval\n\n        lpoints = list(points)\n        if lpoints:\n            values = [\n                cls._fmt_interval(low, high, fmt)\n                for low, high in zip([-np.inf] + lpoints, lpoints + [np.inf])]\n            to_sql = BinSql(var, lpoints)\n        else:\n            values = [\"single_value\"]\n            to_sql = SingleValueSql(values[0])\n\n        dvar = DiscreteVariable(name=var.name, values=values,\n                                compute_value=cls(var, points),\n                                sparse=var.sparse)\n        dvar.source_variable = var\n        dvar.to_sql = to_sql\n        return dvar\n\n\nclass BinSql:\n    def __init__(self, var, points):\n        self.var = var\n        self.points = points\n\n    def __call__(self):\n        return 'width_bucket(%s, ARRAY%s::double precision[])' % (\n            self.var.to_sql(), str(self.points))\n\n\nclass SingleValueSql:\n    def __init__(self, value):\n        self.value = value\n\n    def __call__(self):\n        return \"'%s'\" % self.value\n\n\nclass Discretization(Reprable):\n    \"\"\"Abstract base class for discretization classes.\"\"\"\n    def __call__(self, data, variable):\n        \"\"\"\n        Compute discretization of the given variable on the given data.\n        Return a new variable with the appropriate domain\n        (:obj:`Orange.data.DiscreteVariable.values`) and transformer\n        (:obj:`Orange.data.Variable.compute_value`).\n        \"\"\"\n        raise NotImplementedError(\n            \"Subclasses of 'Discretization' need to implement \"\n            \"the call operator\")\n\n\nclass EqualFreq(Discretization):\n    \"\"\"Discretization into bins with approximately equal number of data\n    instances.\n\n    .. attribute:: n\n\n        Number of bins (default: 4). The actual number may be lower if the\n        variable has less than n distinct values.\n    \"\"\"\n    def __init__(self, n=4):\n        self.n = n\n\n    # noinspection PyProtectedMember\n    def __call__(self, data, attribute):\n        if type(data) == SqlTable:\n            att = attribute.to_sql()\n            quantiles = [(i + 1) / self.n for i in range(self.n - 1)]\n            query = data._sql_query(\n                ['quantile(%s, ARRAY%s)' % (att, str(quantiles))],\n                use_time_sample=1000)\n            with data._execute_sql_query(query) as cur:\n                points = sorted(set(cur.fetchone()[0]))\n        else:\n            d = distribution.get_distribution(data, attribute)\n            points = _discretize.split_eq_freq(d, self.n)\n        return Discretizer.create_discretized_var(\n            data.domain[attribute], points)\n\nclass EqualWidth(Discretization):\n    \"\"\"Discretization into a fixed number of bins with equal widths.\n\n    .. attribute:: n\n\n        Number of bins (default: 4).\n    \"\"\"\n    def __init__(self, n=4):\n        self.n = n\n\n    # noinspection PyProtectedMember\n    def __call__(self, data, attribute, fixed=None):\n        if fixed:\n            min, max = fixed[attribute.name]\n            points = self._split_eq_width(min, max)\n        else:\n            if type(data) == SqlTable:\n                stats = BasicStats(data, attribute)\n                points = self._split_eq_width(stats.min, stats.max)\n            else:\n                values = data[:, attribute]\n                values = values.X if values.X.size else values.Y\n                min, max = ut.nanmin(values), ut.nanmax(values)\n                points = self._split_eq_width(min, max)\n        return Discretizer.create_discretized_var(\n            data.domain[attribute], points)\n\n    def _split_eq_width(self, min, max):\n        if np.isnan(min) or np.isnan(max) or min == max:\n            return []\n        dif = (max - min) / self.n\n        return [min + (i + 1) * dif for i in range(self.n - 1)]\n\n\nclass BinDefinition(NamedTuple):\n    thresholds: np.ndarray  # thresholds, including the top\n    labels: List[str]  # friendly-formatted thresholds\n    short_labels: List[str]  # shorter labels (e.g. simplified dates)\n    width: Union[float, None]  # widths, if uniform; otherwise None\n    width_label: str  # friendly-formatted width (e.g. '50' or '2 weeks')\n\n\n# NamedTupleMeta doesn't allow to define __new__ so we need a subclass\n# Name of the class has to be the same to match the namedtuple name\n# pylint: disable=function-redefined\nclass BinDefinition(BinDefinition):\n    def __new__(cls, thresholds, labels=\"%g\",\n                short_labels=None, width=None, width_label=\"\"):\n\n        def get_labels(fmt, default=None):\n            if fmt is None:\n                return default\n            if isinstance(fmt, str):\n                return [fmt % x for x in thresholds]\n            elif isinstance(fmt, Callable):\n                return [fmt(x) for x in thresholds]\n            else:\n                return fmt\n\n        labels = get_labels(labels)\n        short_labels = get_labels(short_labels, labels)\n        if not width_label and width is not None:\n            width_label = f\"{width:g}\"\n        return super().__new__(\n            cls, thresholds, labels, short_labels, width, width_label)\n\n    @property\n    def start(self) -> float:\n        return self.thresholds[0]\n\n    @property\n    def nbins(self) -> int:\n        return len(self.thresholds) - 1\n\n\ndef decimal_binnings(\n        data, *, min_width=0, min_bins=2, max_bins=50,\n        min_unique=5, add_unique=0,\n        factors=(0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20),\n        label_fmt=\"%g\"):\n    \"\"\"\n    Find a set of nice splits of data into bins\n\n    The function first computes the scaling factor that is, the power of 10\n    that brings the interval of values within [0, 1]. For instances, if the\n    numbers come from interaval 10004001 and 10007005, the width of the\n    interval is 3004, so the scaling factor is 1000.\n\n    The function next considers bin widths that are products of scaling and\n    different factors from 20 to 0.01 that make sense in decimal scale\n    (see default value for argument `factors`). For each width, it rounds the\n    minimal value down to this width and the maximal value up, and it computes\n    the number of bins of that width that fit between these two values.\n    If the number of bins is between `min_bins` and `max_bins`, and the width\n    is at least `min_width`, this is a valid interval.\n\n    If the data has no more than `min_unique` unique values, the function will\n    add a set of bins that put each value into its own bin.\n\n    If the data has no more than `add_unique` values, that last bins will put\n    each value into its own bin.\n\n    Args:\n        data (np.ndarray):\n            vector of data points; values may repeat, and nans and infs are\n            filtered out.\n        min_width (float): minimal bin width\n        min_bins (int): minimal number of bins\n        max_bins (int):\n            maximal number of bins; the number of bins will never exceed the\n            number of unique values\n        min_unique (int):\n            if the number of unique values are less or equal to `min_unique`,\n            the function returns a single binning that matches that values in\n            the data\n        add_unique (int):\n            similar to `min_unique` except that such bins are added to the list;\n            set to 0 to disable\n        factors (list of float):\n            The factors with which the scaling is multiplied. Default is\n            `(0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20)`,\n            so if scaling is 1000, considered bin widths are 20000, 10000,\n            5000, 2000, 1000, 500, 250, 200, 100, 50, 25, 20 and 10.\n        label_fmt (str or Callable):\n            A format string (default: \"%g\") used for threshold labels,\n            or a function for formatting thresholds (e.g. var.str_val)\n\n    Returns:\n        bin_boundaries (list of np.ndarray): a list of bin boundaries,\n            including the top boundary of the last interval, hence the list\n            size equals the number bins + 1. These array match the `bin`\n            argument of `numpy.histogram`.\n\n            This is returned if `return_defs` is left `True`.\n\n        bin_definition (list of BinDefinition):\n            `BinDefinition` is a named tuple containing the beginning of the\n            first bin (`start`), number of bins (`nbins`) and their widths\n            (`width`). The last value can also be a `nd.array` with `nbins + 1`\n            elements, which describes bins of unequal width and is used for\n            binnings that match the unique values in the data (see `min_unique`\n            and `add_unique`).\n\n            This is returned if `return_defs` is `False`.\n    \"\"\"\n    bins = []\n\n    mn, mx, unique = _min_max_unique(data)\n    if len(unique) <= max(min_unique, add_unique):\n        bins.append(BinDefinition(_unique_thresholds(unique), label_fmt))\n        if len(unique) <= min_unique:\n            return bins\n\n    diff = mx - mn\n    f10 = 10 ** -np.floor(np.log10(diff))\n    max_bins = min(max_bins, len(unique))\n    for f in factors:\n        width = f / f10\n        if width < min_width:\n            continue\n        mn_ = np.floor(mn / width) * width\n        mx_ = np.ceil(mx / width) * width\n        nbins = np.round((mx_ - mn_) / width)\n        if min_bins <= nbins <= max_bins \\\n                and (not bins or bins[-1].nbins != nbins):\n            bin_def = BinDefinition(mn_ + width * np.arange(nbins + 1),\n                                    label_fmt, None, width)\n            bins.append(bin_def)\n    return bins\n\n\ndef time_binnings(data, *, min_bins=2, max_bins=50, min_unique=5, add_unique=0):\n    \"\"\"\n    Find a set of nice splits of time variable data into bins\n\n    The function considers bin widths of\n\n    - 1, 5, 10, 15, 30 seconds.\n    - 1, 5, 10, 15, 30 minutes,\n    - 1, 2, 3, 6, 12 hours,\n    - 1 day,\n    - 1, 2 weeks,\n    - 1, 2, 3, 6 months,\n    - 1, 2, 5, 10, 25, 50, 100 years,\n\n    and returns those that yield between `min_bins` and `max_bins` intervals.\n\n    Args:\n        data (np.ndarray):\n            vector of data points; values may repeat, and nans and infs are\n            filtered out.\n        min_bins (int): minimal number of bins\n        max_bins (int):\n            maximal number of bins; the number of bins will never exceed the\n            number of unique values\n\n    Returns:\n        bin_boundaries (list): a list of possible binning.\n            Each element of `bin_boundaries` is a tuple consisting of a label\n            describing the bin size (e.g. `2 weeks`) and a list of thresholds.\n            Thresholds are given as pairs\n            (number_of_seconds_since_epoch, label).\n    \"\"\"\n    mn, mx, unique = _min_max_unique(data)\n    mn, mx = time.gmtime(mn), time.gmtime(mx)\n    bins = []\n    if len(unique) <= max(min_unique, add_unique):\n        bins.append(_unique_time_bins(unique))\n    if len(unique) > min_unique:\n        bins += _time_binnings(mn, mx, min_bins + 1, max_bins + 1)\n    return bins\n\n\ndef _time_binnings(mn, mx, min_pts, max_pts):\n    yfmt = \"%y \" if mn.tm_year >= 1950 else \"%Y \"\n    bins = []\n    for place, step, fmt, unit in (\n            [(5, x, \"%H:%M:%S\", \"second\") for x in (1, 5, 10, 15, 30)] +\n            [(4, x, \"%b %d %H:%M\", \"minute\") for x in (1, 5, 10, 15, 30)] +\n            [(3, x, yfmt + \"%b %d %H:%M\", \"hour\") for x in (1, 2, 3, 6, 12)] +\n            [(2, 1, yfmt + \"%b %d\", \"day\")] +\n            [(2, x, yfmt + \"%b %d\", \"week\") for x in (7, 14)] +\n            [(1, x, yfmt + \"%b\", \"month\") for x in (1, 2, 3, 6)] +\n            [(0, x, yfmt.strip(), \"year\") for x in (1, 2, 5, 10, 25, 50, 100)]):\n        times = _time_range(mn, mx, place, step, min_pts, max_pts)\n        if not times:\n            continue\n        times = [time.struct_time(t + (0, 0, 0)) for t in times]\n        thresholds = [calendar.timegm(t) for t in times]\n        labels = [time.strftime(fmt, t) for t in times]\n        short_labels = _simplified_labels(labels)\n        if place == 2 and step >= 7:\n            unit_label = f\"{step // 7} week{'s' * (step > 7)}\"\n        else:\n            unit_label = f\"{step} {unit}{'s' * (step > 1)}\"\n        new_bins = BinDefinition(\n            thresholds, labels, short_labels, None, unit_label)\n        if not bins or new_bins.nbins != bins[-1].nbins:\n            bins.append(new_bins)\n    return bins\n\n\n# datetime + deltatime is not very useful here because deltatime is\n# given a number of days, not years or months, so it doesn't allow\n# for specifying a step of 1 month\ndef _time_range(start, end, place, step, min_pts, max_pts,\n                _zeros=(0, 1, 1, 0, 0, 0)):\n    if place == 2 and step % 7 == 0:\n        startd = datetime.date(*start[:3])\n        startd -= datetime.timedelta(days=-startd.weekday())\n        start = [startd.year, startd.month, startd.day, 0, 0, 0]\n    else:\n        start = list(\n            start[:place]\n            + ((start[place] - _zeros[place]) // step * step + _zeros[place], )\n            + _zeros[place + 1:])\n    end = list(end[:place + 1] + _zeros[place + 1:])\n    s = [tuple(start)]\n    for _ in range(max_pts - 1):\n        start[place] += step\n        if place >= 3:  # hours, minutes, seconds\n            for pos, maxval in enumerate((60, 60, 24), start=1):\n                if start[-pos] >= maxval:\n                    start[-pos - 1] += 1\n                    start[-pos] %= maxval\n        if place >= 2:\n            md = _month_days(*start[:2])\n            if start[2] > md:\n                start[1] += 1\n                start[2] %= md\n        if start[1] > 12:\n            start[0] += 1\n            start[1] %= 12\n        s.append(tuple(start))\n        if start > end:\n            return s if len(s) >= min_pts else None\n    return None\n\n\ndef _month_days(year, month,\n                _md=(None, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)):\n    return _md[month] + (\n        month == 2 and (year % 400 == 0 or year % 4 == 0 and year % 100 != 0))\n\n\ndef _simplified_labels(labels):\n    labels = labels[:]\n    to_remove = \"42\"\n    while True:\n        firsts = {f for f, *_ in (lab.split() for lab in labels)}\n        if len(firsts) > 1:\n            break\n        to_remove = firsts.pop()\n        flen = len(to_remove) + 1\n        if any(len(lab) == flen for lab in labels):\n            break\n        labels = [lab[flen:] for lab in labels]\n    for i in range(len(labels) - 1, 0, -1):\n        for k, c, d in zip(count(), labels[i].split(), labels[i - 1].split()):\n            if c != d:\n                labels[i] = \" \".join(labels[i].split()[k:])\n                break\n    # If the last thing removed were month names and the labels continues with\n    # hours, keep month name in the first label; \"08 12:29\" looks awkward.\n    if not to_remove[0].isdigit() and \":\" in labels[0]:\n        labels[0] = f\"{to_remove} {labels[0]}\"\n    return labels\n\n\ndef _unique_time_bins(unique):\n    times = [time.gmtime(x) for x in unique]\n    fmt = f'{\"%y \" if times[0][0] >= 1950 else \"%Y \"} %b %d'\n    fmt += \" %H:%M\" * (len({t[2:] for t in times}) > 1)\n    fmt += \":%S\" * bool(np.all(unique % 60 == 0))\n    labels = [time.strftime(fmt, x) for x in times]\n    short_labels = _simplified_labels(labels)\n    return BinDefinition(_unique_thresholds(unique), labels, short_labels)\n\n\ndef _unique_thresholds(unique):\n    if len(unique) >= 2:\n        # make the last bin the same width as the one before\n        last_boundary = 2 * unique[-1] - unique[-2]\n    else:\n        last_boundary = unique[0] + 1\n    return np.hstack((unique, [last_boundary]))\n\n\ndef _min_max_unique(data):\n    unique = np.unique(data)\n    unique = unique[np.isfinite(unique)]\n    if not unique.size:\n        raise ValueError(\"no valid (non-nan) data\")\n    return unique[0], unique[-1], unique\n\n\nshort_time_units = dict(seconds=\"sec\", minutes=\"min\", hours=\"hrs\",\n                        weeks=\"wks\", months=\"mon\", years=\"yrs\",\n                        second=\"sec\", minute=\"min\", month=\"mon\")\n\n\n# noinspection PyPep8Naming\nclass EntropyMDL(Discretization):\n    \"\"\"\n    Discretization into bins inferred by recursively splitting the values to\n    minimize the class-entropy. The procedure stops when further splits would\n    decrease the entropy for less than the corresponding increase of minimal\n    description length (MDL). [FayyadIrani93].\n\n    If there are no suitable cut-off points, the procedure returns a single bin,\n    which means that the new feature is constant and can be removed.\n\n    .. attribute:: force\n\n        Induce at least one cut-off point, even when its information\n        gain is lower than MDL (default: False).\n\n    \"\"\"\n    def __init__(self, force=False):\n        self.force = force\n\n    def __call__(self, data, attribute):\n        cont = contingency.get_contingency(data, attribute)\n        values, I = cont.values, cont.counts.T\n        cut_ind = np.array(self._entropy_discretize_sorted(I, self.force))\n        if len(cut_ind) > 0:\n            # \"the midpoint between each successive pair of examples\" (FI p.1)\n            points = (values[cut_ind] + values[cut_ind - 1]) / 2.\n        else:\n            points = []\n        return Discretizer.create_discretized_var(\n            data.domain[attribute], points)\n\n    @classmethod\n    def _normalize(cls, X, axis=None, out=None):\n        \"\"\"\n        Normalize `X` array so it sums to 1.0 over the `axis`.\n\n        Parameters\n        ----------\n        X : array\n            Array to normalize.\n        axis : optional int\n            Axis over which the resulting array sums to 1.\n        out : optional array\n            Output array of the same shape as X.\n        \"\"\"\n        X = np.asarray(X, dtype=float)\n        scale = np.sum(X, axis=axis, keepdims=True)\n        if out is None:\n            return X / scale\n        else:\n            if out is not X:\n                assert out.shape == X.shape\n                out[:] = X\n            out /= scale\n            return out\n\n    @classmethod\n    def _entropy_normalized(cls, D, axis=None):\n        \"\"\"\n        Compute the entropy of distribution array `D`.\n\n        `D` must be a distribution (i.e. sum to 1.0 over `axis`)\n\n        Parameters\n        ----------\n        D : array\n            Distribution.\n        axis : optional int\n            Axis of `D` along which to compute the entropy.\n\n        \"\"\"\n        # req: (np.sum(D, axis=axis) >= 0).all()\n        # req: (np.sum(D, axis=axis) <= 1).all()\n        # req: np.all(np.abs(np.sum(D, axis=axis) - 1) < 1e-9)\n\n        D = np.asarray(D)\n        Dc = np.clip(D, np.finfo(D.dtype).eps, 1.0)\n        return - np.sum(D * np.log2(Dc), axis=axis)\n\n    @classmethod\n    def _entropy(cls, D, axis=None):\n        \"\"\"\n        Compute the entropy of distribution `D`.\n\n        Parameters\n        ----------\n        D : array\n            Distribution.\n        axis : optional int\n            Axis of `D` along which to compute the entropy.\n\n        \"\"\"\n        D = cls._normalize(D, axis=axis)\n        return cls._entropy_normalized(D, axis=axis)\n\n    @classmethod\n    def _entropy1(cls, D):\n        \"\"\"\n        Compute the entropy of distributions in `D`\n        (one per each row).\n        \"\"\"\n        D = cls._normalize(D)\n        return _discretize.entropy_normalized1(D)\n\n    @classmethod\n    def _entropy2(cls, D):\n        \"\"\"\n        Compute the entropy of distributions in `D`\n        (one per each row).\n        \"\"\"\n        D = cls._normalize(D, axis=1)\n        return _discretize.entropy_normalized2(D)\n\n    @classmethod\n    def _entropy_cuts_sorted(cls, CS):\n        \"\"\"\n        Return the class information entropy induced by partitioning\n        the `CS` distribution at all N-1 candidate cut points.\n\n        Parameters\n        ----------\n        CS : (N, K) array of class distributions.\n        \"\"\"\n        CS = np.asarray(CS)\n        # |--|-------|--------|\n        #  S1    ^       S2\n        # S1 contains all points which are <= to cut point\n        # Cumulative distributions for S1 and S2 (left right set)\n        # i.e. a cut at index i separates the CS into S1Dist[i] and S2Dist[i]\n        S1Dist = np.cumsum(CS, axis=0)[:-1]\n        S2Dist = np.cumsum(CS[::-1], axis=0)[-2::-1]\n\n        # Entropy of S1[i] and S2[i] sets\n        ES1 = cls._entropy2(S1Dist)\n        ES2 = cls._entropy2(S2Dist)\n\n        # Number of cases in S1[i] and S2[i] sets\n        S1_count = np.sum(S1Dist, axis=1)\n        S2_count = np.sum(S2Dist, axis=1)\n\n        # Number of all cases\n        S_count = np.sum(CS)\n\n        ES1w = ES1 * S1_count / S_count\n        ES2w = ES2 * S2_count / S_count\n\n        # E(A, T; S) Class information entropy of the partition S\n        E = ES1w + ES2w\n\n        return E, ES1, ES2\n\n    @classmethod\n    def _entropy_discretize_sorted(cls, C, force=False):\n        \"\"\"\n        Entropy discretization on a sorted C.\n\n        :param C: (N, K) array of class distributions.\n\n        \"\"\"\n        E, ES1, ES2 = cls._entropy_cuts_sorted(C)\n        # TODO: Also get the left right distribution counts from\n        # entropy_cuts_sorted,\n\n        # Note the + 1\n        if len(E) == 0:\n            return []\n        cut_index = np.argmin(E) + 1\n\n        # Distribution of classed in S1, S2 and S\n        S1_c = np.sum(C[:cut_index], axis=0)\n        S2_c = np.sum(C[cut_index:], axis=0)\n        S_c = S1_c + S2_c\n\n        ES = cls._entropy1(np.sum(C, axis=0))\n        ES1, ES2 = ES1[cut_index - 1], ES2[cut_index - 1]\n\n        # Information gain of the best split\n        Gain = ES - E[cut_index - 1]\n        # Number of different classes in S, S1 and S2\n        k = float(np.sum(S_c > 0))\n        k1 = float(np.sum(S1_c > 0))\n        k2 = float(np.sum(S2_c > 0))\n\n        assert k > 0\n        delta = np.log2(3 ** k - 2) - (k * ES - k1 * ES1 - k2 * ES2)\n        N = float(np.sum(S_c))\n\n        if Gain > np.log2(N - 1) / N + delta / N:\n            # Accept the cut point and recursively split the subsets.\n            left, right = [], []\n            if k1 > 1 and cut_index > 1:\n                left = cls._entropy_discretize_sorted(C[:cut_index, :])\n            if k2 > 1 and cut_index < len(C) - 1:\n                right = cls._entropy_discretize_sorted(C[cut_index:, :])\n            return left + [cut_index] + [i + cut_index for i in right]\n        elif force:\n            return [cut_index]\n        else:\n            return []\n\n\nclass DomainDiscretizer(Reprable):\n    \"\"\"Discretizes all continuous features in the data.\n\n    .. attribute:: method\n\n        Feature discretization method (instance of\n        :obj:`Orange.preprocess.Discretization`). If `None` (default),\n        :class:`Orange.preprocess.EqualFreq` with 4 intervals is\n        used.\n\n    .. attribute:: clean\n\n        If `True`, features discretized into a single interval constant are\n        removed. This is useful for discretization methods that infer the\n        number of intervals from the data, such as\n        :class:`Orange.preprocess.EntropyMDL` (default: `True`).\n\n    .. attribute:: discretize_class\n\n        Determines whether a target is also discretized if it is continuous.\n        (default: `False`)\n    \"\"\"\n    def __init__(self, discretize_class=False, method=None, clean=True,\n                 fixed=None):\n        self.discretize_class = discretize_class\n        self.method = method\n        self.clean = clean\n        self.fixed = fixed\n\n    def __call__(self, data, fixed=None):\n        \"\"\"\n        Compute and return discretized domain.\n\n        :param data: Data to discretize.\n        \"\"\"\n\n        def transform_list(s, fixed=None):\n            new_vars = []\n            for var in s:\n                if var.is_continuous:\n                    if fixed and var.name in fixed.keys():\n                        nv = method(data, var, fixed)\n                    else:\n                        nv = method(data, var)\n                    if not self.clean or len(nv.values) > 1:\n                        new_vars.append(nv)\n                else:\n                    new_vars.append(var)\n            return new_vars\n        if self.method is None:\n            method = EqualFreq(n=4)\n        else:\n            method = self.method\n        domain = data.domain\n        new_attrs = transform_list(domain.attributes, fixed or self.fixed)\n        if self.discretize_class:\n            new_classes = transform_list(domain.class_vars)\n        else:\n            new_classes = domain.class_vars\n        return Domain(new_attrs, new_classes)\n"}
A user will ask you to solve a task. You should first draft your thinking process (inner monologue). Then, generate the solution.

Your response format must follow the template below:
<think>
Your thoughts or/and draft, like working through an exercise on scratch paper. Be as casual and as long as you want until you are confident to generate a correct solution.
</think>
<solution>
Final solution presented to the user.
</solution>
system
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Incorrect Year Labels in Time Binnings for Extended Date Ranges

**Description:**
When using the `time_binnings` function with longer date ranges, the year labels are displayed in a two-digit format instead of the expected four-digit format. This inconsistency causes related tests to fail.

**Example:**
```python
bins = time_binnings(start=(1975, 4, 2), end=(1989, 3, 1), min_bins=2, max_bins=50)
for bin in bins:
    print(bin.width_label, bin.short_labels)
```

**Expected Behavior:**
For a "10 years" bin, the labels should be:
```
10 years ['1970', '1980', '1990'] [0, 315532800, 631152000]
```

**Actual Behavior:**
The labels are incorrectly displayed as:
```
10 years ['70', '80', '90'] [0, 315532800, 631152000]
```

This mismatch between the expected and actual labels leads to failing tests and confusion for developers relying on accurate time binning.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### Orange/preprocess/discretize.py
import calendar
import re
import time
from typing import NamedTuple, List, Union, Callable
import datetime
from itertools import count

import numpy as np
import scipy.sparse as sp

from Orange.data import DiscreteVariable, Domain
from Orange.data.sql.table import SqlTable
from Orange.statistics import distribution, contingency, util as ut
from Orange.statistics.basic_stats import BasicStats
from Orange.util import Reprable
from .transformation import Transformation
from . import _discretize

__all__ = ["EqualFreq", "EqualWidth", "EntropyMDL", "DomainDiscretizer",
           "decimal_binnings", "time_binnings", "short_time_units",
           "BinDefinition"]


class Discretizer(Transformation):
    """Value transformer that returns an index of the bin for the given value.
    """
    def __init__(self, variable, points):
        super().__init__(variable)
        self.points = points

    @staticmethod
    def digitize(x, bins):
        if sp.issparse(x):
            if len(bins):
                x.data = np.digitize(x.data, bins)
            else:
                x = sp.csr_matrix(x.shape)
            return x
        else:
            return np.digitize(x, bins) if len(bins) else [0]*len(x)

    def transform(self, c):
        if sp.issparse(c):
            return self.digitize(c, self.points)
        elif c.size:
            return np.where(np.isnan(c), np.NaN, self.digitize(c, self.points))
        else:
            return np.array([], dtype=int)

    @staticmethod
    def _fmt_interval(low, high, formatter):
        assert low is not None or high is not None
        assert low is None or high is None or low < high
        if low is None or np.isinf(low):
            return f"< {formatter(high)}"
        if high is None or np.isinf(high):
            return f"≥ {formatter(low)}"
        return f"{formatter(low)} - {formatter(high)}"

    @classmethod
    def create_discretized_var(cls, var, points):
        def fmt(val):
            sval = var.str_val(val)
            # For decimal numbers, remove trailing 0's and . if no decimals left
            if re.match(r"^\d+\.\d+", sval):
                return sval.rstrip("0").rstrip(".")
            return sval

        lpoints = list(points)
        if lpoints:
            values = [
                cls._fmt_interval(low, high, fmt)
                for low, high in zip([-np.inf] + lpoints, lpoints + [np.inf])]
            to_sql = BinSql(var, lpoints)
        else:
            values = ["single_value"]
            to_sql = SingleValueSql(values[0])

        dvar = DiscreteVariable(name=var.name, values=values,
                                compute_value=cls(var, points),
                                sparse=var.sparse)
        dvar.source_variable = var
        dvar.to_sql = to_sql
        return dvar


class BinSql:
    def __init__(self, var, points):
        self.var = var
        self.points = points

    def __call__(self):
        return 'width_bucket(%s, ARRAY%s::double precision[])' % (
            self.var.to_sql(), str(self.points))


class SingleValueSql:
    def __init__(self, value):
        self.value = value

    def __call__(self):
        return "'%s'" % self.value


class Discretization(Reprable):
    """Abstract base class for discretization classes."""
    def __call__(self, data, variable):
        """
        Compute discretization of the given variable on the given data.
        Return a new variable with the appropriate domain
        (:obj:`Orange.data.DiscreteVariable.values`) and transformer
        (:obj:`Orange.data.Variable.compute_value`).
        """
        raise NotImplementedError(
            "Subclasses of 'Discretization' need to implement "
            "the call operator")


class EqualFreq(Discretization):
    """Discretization into bins with approximately equal number of data
    instances.

    .. attribute:: n

        Number of bins (default: 4). The actual number may be lower if the
        variable has less than n distinct values.
    """
    def __init__(self, n=4):
        self.n = n

    # noinspection PyProtectedMember
    def __call__(self, data, attribute):
        if type(data) == SqlTable:
            att = attribute.to_sql()
            quantiles = [(i + 1) / self.n for i in range(self.n - 1)]
            query = data._sql_query(
                ['quantile(%s, ARRAY%s)' % (att, str(quantiles))],
                use_time_sample=1000)
            with data._execute_sql_query(query) as cur:
                points = sorted(set(cur.fetchone()[0]))
        else:
            d = distribution.get_distribution(data, attribute)
            points = _discretize.split_eq_freq(d, self.n)
        return Discretizer.create_discretized_var(
            data.domain[attribute], points)

class EqualWidth(Discretization):
    """Discretization into a fixed number of bins with equal widths.

    .. attribute:: n

        Number of bins (default: 4).
    """
    def __init__(self, n=4):
        self.n = n

    # noinspection PyProtectedMember
    def __call__(self, data, attribute, fixed=None):
        if fixed:
            min, max = fixed[attribute.name]
            points = self._split_eq_width(min, max)
        else:
            if type(data) == SqlTable:
                stats = BasicStats(data, attribute)
                points = self._split_eq_width(stats.min, stats.max)
            else:
                values = data[:, attribute]
                values = values.X if values.X.size else values.Y
                min, max = ut.nanmin(values), ut.nanmax(values)
                points = self._split_eq_width(min, max)
        return Discretizer.create_discretized_var(
            data.domain[attribute], points)

    def _split_eq_width(self, min, max):
        if np.isnan(min) or np.isnan(max) or min == max:
            return []
        dif = (max - min) / self.n
        return [min + (i + 1) * dif for i in range(self.n - 1)]


class BinDefinition(NamedTuple):
    thresholds: np.ndarray  # thresholds, including the top
    labels: List[str]  # friendly-formatted thresholds
    short_labels: List[str]  # shorter labels (e.g. simplified dates)
    width: Union[float, None]  # widths, if uniform; otherwise None
    width_label: str  # friendly-formatted width (e.g. '50' or '2 weeks')


# NamedTupleMeta doesn't allow to define __new__ so we need a subclass
# Name of the class has to be the same to match the namedtuple name
# pylint: disable=function-redefined
class BinDefinition(BinDefinition):
    def __new__(cls, thresholds, labels="%g",
                short_labels=None, width=None, width_label=""):

        def get_labels(fmt, default=None):
            if fmt is None:
                return default
            if isinstance(fmt, str):
                return [fmt % x for x in thresholds]
            elif isinstance(fmt, Callable):
                return [fmt(x) for x in thresholds]
            else:
                return fmt

        labels = get_labels(labels)
        short_labels = get_labels(short_labels, labels)
        if not width_label and width is not None:
            width_label = f"{width:g}"
        return super().__new__(
            cls, thresholds, labels, short_labels, width, width_label)

    @property
    def start(self) -> float:
        return self.thresholds[0]

    @property
    def nbins(self) -> int:
        return len(self.thresholds) - 1


def decimal_binnings(
        data, *, min_width=0, min_bins=2, max_bins=50,
        min_unique=5, add_unique=0,
        factors=(0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20),
        label_fmt="%g"):
    """
    Find a set of nice splits of data into bins

    The function first computes the scaling factor that is, the power of 10
    that brings the interval of values within [0, 1]. For instances, if the
    numbers come from interaval 10004001 and 10007005, the width of the
    interval is 3004, so the scaling factor is 1000.

    The function next considers bin widths that are products of scaling and
    different factors from 20 to 0.01 that make sense in decimal scale
    (see default value for argument `factors`). For each width, it rounds the
    minimal value down to this width and the maximal value up, and it computes
    the number of bins of that width that fit between these two values.
    If the number of bins is between `min_bins` and `max_bins`, and the width
    is at least `min_width`, this is a valid interval.

    If the data has no more than `min_unique` unique values, the function will
    add a set of bins that put each value into its own bin.

    If the data has no more than `add_unique` values, that last bins will put
    each value into its own bin.

    Args:
        data (np.ndarray):
            vector of data points; values may repeat, and nans and infs are
            filtered out.
        min_width (float): minimal bin width
        min_bins (int): minimal number of bins
        max_bins (int):
            maximal number of bins; the number of bins will never exceed the
            number of unique values
        min_unique (int):
            if the number of unique values are less or equal to `min_unique`,
            the function returns a single binning that matches that values in
            the data
        add_unique (int):
            similar to `min_unique` except that such bins are added to the list;
            set to 0 to disable
        factors (list of float):
            The factors with which the scaling is multiplied. Default is
            `(0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20)`,
            so if scaling is 1000, considered bin widths are 20000, 10000,
            5000, 2000, 1000, 500, 250, 200, 100, 50, 25, 20 and 10.
        label_fmt (str or Callable):
            A format string (default: "%g") used for threshold labels,
            or a function for formatting thresholds (e.g. var.str_val)

    Returns:
        bin_boundaries (list of np.ndarray): a list of bin boundaries,
            including the top boundary of the last interval, hence the list
            size equals the number bins + 1. These array match the `bin`
            argument of `numpy.histogram`.

            This is returned if `return_defs` is left `True`.

        bin_definition (list of BinDefinition):
            `BinDefinition` is a named tuple containing the beginning of the
            first bin (`start`), number of bins (`nbins`) and their widths
            (`width`). The last value can also be a `nd.array` with `nbins + 1`
            elements, which describes bins of unequal width and is used for
            binnings that match the unique values in the data (see `min_unique`
            and `add_unique`).

            This is returned if `return_defs` is `False`.
    """
    bins = []

    mn, mx, unique = _min_max_unique(data)
    if len(unique) <= max(min_unique, add_unique):
        bins.append(BinDefinition(_unique_thresholds(unique), label_fmt))
        if len(unique) <= min_unique:
            return bins

    diff = mx - mn
    f10 = 10 ** -np.floor(np.log10(diff))
    max_bins = min(max_bins, len(unique))
    for f in factors:
        width = f / f10
        if width < min_width:
            continue
        mn_ = np.floor(mn / width) * width
        mx_ = np.ceil(mx / width) * width
        nbins = np.round((mx_ - mn_) / width)
        if min_bins <= nbins <= max_bins \
                and (not bins or bins[-1].nbins != nbins):
            bin_def = BinDefinition(mn_ + width * np.arange(nbins + 1),
                                    label_fmt, None, width)
            bins.append(bin_def)
    return bins


def time_binnings(data, *, min_bins=2, max_bins=50, min_unique=5, add_unique=0):
    """
    Find a set of nice splits of time variable data into bins

    The function considers bin widths of

    - 1, 5, 10, 15, 30 seconds.
    - 1, 5, 10, 15, 30 minutes,
    - 1, 2, 3, 6, 12 hours,
    - 1 day,
    - 1, 2 weeks,
    - 1, 2, 3, 6 months,
    - 1, 2, 5, 10, 25, 50, 100 years,

    and returns those that yield between `min_bins` and `max_bins` intervals.

    Args:
        data (np.ndarray):
            vector of data points; values may repeat, and nans and infs are
            filtered out.
        min_bins (int): minimal number of bins
        max_bins (int):
            maximal number of bins; the number of bins will never exceed the
            number of unique values

    Returns:
        bin_boundaries (list): a list of possible binning.
            Each element of `bin_boundaries` is a tuple consisting of a label
            describing the bin size (e.g. `2 weeks`) and a list of thresholds.
            Thresholds are given as pairs
            (number_of_seconds_since_epoch, label).
    """
    mn, mx, unique = _min_max_unique(data)
    mn, mx = time.gmtime(mn), time.gmtime(mx)
    bins = []
    if len(unique) <= max(min_unique, add_unique):
        bins.append(_unique_time_bins(unique))
    if len(unique) > min_unique:
        bins += _time_binnings(mn, mx, min_bins + 1, max_bins + 1)
    return bins


def _time_binnings(mn, mx, min_pts, max_pts):
    yfmt = "%y " if mn.tm_year >= 1950 else "%Y "
    bins = []
    for place, step, fmt, unit in (
            [(5, x, "%H:%M:%S", "second") for x in (1, 5, 10, 15, 30)] +
            [(4, x, "%b %d %H:%M", "minute") for x in (1, 5, 10, 15, 30)] +
            [(3, x, yfmt + "%b %d %H:%M", "hour") for x in (1, 2, 3, 6, 12)] +
            [(2, 1, yfmt + "%b %d", "day")] +
            [(2, x, yfmt + "%b %d", "week") for x in (7, 14)] +
            [(1, x, yfmt + "%b", "month") for x in (1, 2, 3, 6)] +
            [(0, x, yfmt.strip(), "year") for x in (1, 2, 5, 10, 25, 50, 100)]):
        times = _time_range(mn, mx, place, step, min_pts, max_pts)
        if not times:
            continue
        times = [time.struct_time(t + (0, 0, 0)) for t in times]
        thresholds = [calendar.timegm(t) for t in times]
        labels = [time.strftime(fmt, t) for t in times]
        short_labels = _simplified_labels(labels)
        if place == 2 and step >= 7:
            unit_label = f"{step // 7} week{'s' * (step > 7)}"
        else:
            unit_label = f"{step} {unit}{'s' * (step > 1)}"
        new_bins = BinDefinition(
            thresholds, labels, short_labels, None, unit_label)
        if not bins or new_bins.nbins != bins[-1].nbins:
            bins.append(new_bins)
    return bins


# datetime + deltatime is not very useful here because deltatime is
# given a number of days, not years or months, so it doesn't allow
# for specifying a step of 1 month
def _time_range(start, end, place, step, min_pts, max_pts,
                _zeros=(0, 1, 1, 0, 0, 0)):
    if place == 2 and step % 7 == 0:
        startd = datetime.date(*start[:3])
        startd -= datetime.timedelta(days=-startd.weekday())
        start = [startd.year, startd.month, startd.day, 0, 0, 0]
    else:
        start = list(
            start[:place]
            + ((start[place] - _zeros[place]) // step * step + _zeros[place], )
            + _zeros[place + 1:])
    end = list(end[:place + 1] + _zeros[place + 1:])
    s = [tuple(start)]
    for _ in range(max_pts - 1):
        start[place] += step
        if place >= 3:  # hours, minutes, seconds
            for pos, maxval in enumerate((60, 60, 24), start=1):
                if start[-pos] >= maxval:
                    start[-pos - 1] += 1
                    start[-pos] %= maxval
        if place >= 2:
            md = _month_days(*start[:2])
            if start[2] > md:
                start[1] += 1
                start[2] %= md
        if start[1] > 12:
            start[0] += 1
            start[1] %= 12
        s.append(tuple(start))
        if start > end:
            return s if len(s) >= min_pts else None
    return None


def _month_days(year, month,
                _md=(None, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)):
    return _md[month] + (
        month == 2 and (year % 400 == 0 or year % 4 == 0 and year % 100 != 0))


def _simplified_labels(labels):
    labels = labels[:]
    to_remove = "42"
    while True:
        firsts = {f for f, *_ in (lab.split() for lab in labels)}
        if len(firsts) > 1:
            break
        to_remove = firsts.pop()
        flen = len(to_remove) + 1
        if any(len(lab) == flen for lab in labels):
            break
        labels = [lab[flen:] for lab in labels]
    for i in range(len(labels) - 1, 0, -1):
        for k, c, d in zip(count(), labels[i].split(), labels[i - 1].split()):
            if c != d:
                labels[i] = " ".join(labels[i].split()[k:])
                break
    # If the last thing removed were month names and the labels continues with
    # hours, keep month name in the first label; "08 12:29" looks awkward.
    if not to_remove[0].isdigit() and ":" in labels[0]:
        labels[0] = f"{to_remove} {labels[0]}"
    return labels


def _unique_time_bins(unique):
    times = [time.gmtime(x) for x in unique]
    fmt = f'{"%y " if times[0][0] >= 1950 else "%Y "} %b %d'
    fmt += " %H:%M" * (len({t[2:] for t in times}) > 1)
    fmt += ":%S" * bool(np.all(unique % 60 == 0))
    labels = [time.strftime(fmt, x) for x in times]
    short_labels = _simplified_labels(labels)
    return BinDefinition(_unique_thresholds(unique), labels, short_labels)


def _unique_thresholds(unique):
    if len(unique) >= 2:
        # make the last bin the same width as the one before
        last_boundary = 2 * unique[-1] - unique[-2]
    else:
        last_boundary = unique[0] + 1
    return np.hstack((unique, [last_boundary]))


def _min_max_unique(data):
    unique = np.unique(data)
    unique = unique[np.isfinite(unique)]
    if not unique.size:
        raise ValueError("no valid (non-nan) data")
    return unique[0], unique[-1], unique


short_time_units = dict(seconds="sec", minutes="min", hours="hrs",
                        weeks="wks", months="mon", years="yrs",
                        second="sec", minute="min", month="mon")


# noinspection PyPep8Naming
class EntropyMDL(Discretization):
    """
    Discretization into bins inferred by recursively splitting the values to
    minimize the class-entropy. The procedure stops when further splits would
    decrease the entropy for less than the corresponding increase of minimal
    description length (MDL). [FayyadIrani93].

    If there are no suitable cut-off points, the procedure returns a single bin,
    which means that the new feature is constant and can be removed.

    .. attribute:: force

        Induce at least one cut-off point, even when its information
        gain is lower than MDL (default: False).

    """
    def __init__(self, force=False):
        self.force = force

    def __call__(self, data, attribute):
        cont = contingency.get_contingency(data, attribute)
        values, I = cont.values, cont.counts.T
        cut_ind = np.array(self._entropy_discretize_sorted(I, self.force))
        if len(cut_ind) > 0:
            # "the midpoint between each successive pair of examples" (FI p.1)
            points = (values[cut_ind] + values[cut_ind - 1]) / 2.
        else:
            points = []
        return Discretizer.create_discretized_var(
            data.domain[attribute], points)

    @classmethod
    def _normalize(cls, X, axis=None, out=None):
        """
        Normalize `X` array so it sums to 1.0 over the `axis`.

        Parameters
        ----------
        X : array
            Array to normalize.
        axis : optional int
            Axis over which the resulting array sums to 1.
        out : optional array
            Output array of the same shape as X.
        """
        X = np.asarray(X, dtype=float)
        scale = np.sum(X, axis=axis, keepdims=True)
        if out is None:
            return X / scale
        else:
            if out is not X:
                assert out.shape == X.shape
                out[:] = X
            out /= scale
            return out

    @classmethod
    def _entropy_normalized(cls, D, axis=None):
        """
        Compute the entropy of distribution array `D`.

        `D` must be a distribution (i.e. sum to 1.0 over `axis`)

        Parameters
        ----------
        D : array
            Distribution.
        axis : optional int
            Axis of `D` along which to compute the entropy.

        """
        # req: (np.sum(D, axis=axis) >= 0).all()
        # req: (np.sum(D, axis=axis) <= 1).all()
        # req: np.all(np.abs(np.sum(D, axis=axis) - 1) < 1e-9)

        D = np.asarray(D)
        Dc = np.clip(D, np.finfo(D.dtype).eps, 1.0)
        return - np.sum(D * np.log2(Dc), axis=axis)

    @classmethod
    def _entropy(cls, D, axis=None):
        """
        Compute the entropy of distribution `D`.

        Parameters
        ----------
        D : array
            Distribution.
        axis : optional int
            Axis of `D` along which to compute the entropy.

        """
        D = cls._normalize(D, axis=axis)
        return cls._entropy_normalized(D, axis=axis)

    @classmethod
    def _entropy1(cls, D):
        """
        Compute the entropy of distributions in `D`
        (one per each row).
        """
        D = cls._normalize(D)
        return _discretize.entropy_normalized1(D)

    @classmethod
    def _entropy2(cls, D):
        """
        Compute the entropy of distributions in `D`
        (one per each row).
        """
        D = cls._normalize(D, axis=1)
        return _discretize.entropy_normalized2(D)

    @classmethod
    def _entropy_cuts_sorted(cls, CS):
        """
        Return the class information entropy induced by partitioning
        the `CS` distribution at all N-1 candidate cut points.

        Parameters
        ----------
        CS : (N, K) array of class distributions.
        """
        CS = np.asarray(CS)
        # |--|-------|--------|
        #  S1    ^       S2
        # S1 contains all points which are <= to cut point
        # Cumulative distributions for S1 and S2 (left right set)
        # i.e. a cut at index i separates the CS into S1Dist[i] and S2Dist[i]
        S1Dist = np.cumsum(CS, axis=0)[:-1]
        S2Dist = np.cumsum(CS[::-1], axis=0)[-2::-1]

        # Entropy of S1[i] and S2[i] sets
        ES1 = cls._entropy2(S1Dist)
        ES2 = cls._entropy2(S2Dist)

        # Number of cases in S1[i] and S2[i] sets
        S1_count = np.sum(S1Dist, axis=1)
        S2_count = np.sum(S2Dist, axis=1)

        # Number of all cases
        S_count = np.sum(CS)

        ES1w = ES1 * S1_count / S_count
        ES2w = ES2 * S2_count / S_count

        # E(A, T; S) Class information entropy of the partition S
        E = ES1w + ES2w

        return E, ES1, ES2

    @classmethod
    def _entropy_discretize_sorted(cls, C, force=False):
        """
        Entropy discretization on a sorted C.

        :param C: (N, K) array of class distributions.

        """
        E, ES1, ES2 = cls._entropy_cuts_sorted(C)
        # TODO: Also get the left right distribution counts from
        # entropy_cuts_sorted,

        # Note the + 1
        if len(E) == 0:
            return []
        cut_index = np.argmin(E) + 1

        # Distribution of classed in S1, S2 and S
        S1_c = np.sum(C[:cut_index], axis=0)
        S2_c = np.sum(C[cut_index:], axis=0)
        S_c = S1_c + S2_c

        ES = cls._entropy1(np.sum(C, axis=0))
        ES1, ES2 = ES1[cut_index - 1], ES2[cut_index - 1]

        # Information gain of the best split
        Gain = ES - E[cut_index - 1]
        # Number of different classes in S, S1 and S2
        k = float(np.sum(S_c > 0))
        k1 = float(np.sum(S1_c > 0))
        k2 = float(np.sum(S2_c > 0))

        assert k > 0
        delta = np.log2(3 ** k - 2) - (k * ES - k1 * ES1 - k2 * ES2)
        N = float(np.sum(S_c))

        if Gain > np.log2(N - 1) / N + delta / N:
            # Accept the cut point and recursively split the subsets.
            left, right = [], []
            if k1 > 1 and cut_index > 1:
                left = cls._entropy_discretize_sorted(C[:cut_index, :])
            if k2 > 1 and cut_index < len(C) - 1:
                right = cls._entropy_discretize_sorted(C[cut_index:, :])
            return left + [cut_index] + [i + cut_index for i in right]
        elif force:
            return [cut_index]
        else:
            return []


class DomainDiscretizer(Reprable):
    """Discretizes all continuous features in the data.

    .. attribute:: method

        Feature discretization method (instance of
        :obj:`Orange.preprocess.Discretization`). If `None` (default),
        :class:`Orange.preprocess.EqualFreq` with 4 intervals is
        used.

    .. attribute:: clean

        If `True`, features discretized into a single interval constant are
        removed. This is useful for discretization methods that infer the
        number of intervals from the data, such as
        :class:`Orange.preprocess.EntropyMDL` (default: `True`).

    .. attribute:: discretize_class

        Determines whether a target is also discretized if it is continuous.
        (default: `False`)
    """
    def __init__(self, discretize_class=False, method=None, clean=True,
                 fixed=None):
        self.discretize_class = discretize_class
        self.method = method
        self.clean = clean
        self.fixed = fixed

    def __call__(self, data, fixed=None):
        """
        Compute and return discretized domain.

        :param data: Data to discretize.
        """

        def transform_list(s, fixed=None):
            new_vars = []
            for var in s:
                if var.is_continuous:
                    if fixed and var.name in fixed.keys():
                        nv = method(data, var, fixed)
                    else:
                        nv = method(data, var)
                    if not self.clean or len(nv.values) > 1:
                        new_vars.append(nv)
                else:
                    new_vars.append(var)
            return new_vars
        if self.method is None:
            method = EqualFreq(n=4)
        else:
            method = self.method
        domain = data.domain
        new_attrs = transform_list(domain.attributes, fixed or self.fixed)
        if self.discretize_class:
            new_classes = transform_list(domain.class_vars)
        else:
            new_classes = domain.class_vars
        return Domain(new_attrs, new_classes)

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
user