예제 #1
0
def floor(t, res):
    """Round the given date down to the nearest smaller resolution step."""
    resName = res[-1]
    resFactor = float(res[:-1])

    d = Date(t * 1000)
    tup = (
        d.getFullYear(),
        d.getMonth(),
        d.getDate(),
        d.getHours(),
        d.getMinutes(),
        d.getSeconds(),
    )
    if resName == "s":
        tup[-1] = int(tup[-1] / resFactor) * resFactor
    elif resName == "m":
        tup = tup[:5]
        tup[-1] = int(tup[-1] / resFactor) * resFactor
    elif resName == "h":
        tup = tup[:4]
        tup[-1] = int(tup[-1] / resFactor) * resFactor
    elif resName == "D":
        tup = tup[:3]
        tup[-1] = int(
            (tup[-1] - 1) / resFactor) * resFactor + 1  # days are 1-based
    elif resName == "W":
        d.setHours(0, 0, 0, 0)
        daysoff = (d.getDay() + 6) % 7  # Align to a monday
        d = Date(d.getTime() - 86_400_000 * daysoff)
        tup = d.getFullYear(), d.getMonth(), d.getDate()
    elif resName == "M":
        tup = tup[:2]  # Note that it is zero-based (jan is zero)
        tup[-1] = int(tup[-1] / resFactor) * resFactor
        tup.extend([1])
    elif resName == "Y":
        tup = tup[:1]
        tup[-1] = int(tup[-1] / resFactor) * resFactor
        tup.extend([0, 1])
    else:
        raise RuntimeError("Invalid resolution: " + res)

    while len(tup) < 6:
        tup.append(0)
    return (Date(tup[0], tup[1], tup[2], tup[3], tup[4], tup[5]).getTime() /
            1000)  # cant do *tup
예제 #2
0
def add(t, delta):
    """Add a delta to the given date. Delta can be an int (number of seconds),
    or a delta string like '4h', "21s", "2M" or "2Y". Works correctly for months
    and keeps leap years into account.
    """

    if isinstance(delta, (float, int)):
        delta = str(delta) + "s"

    deltaName = delta[-1]
    deltaFactor = float(delta[:-1])
    if isNaN(deltaFactor):
        raise RuntimeError(f"Cannot create delta from {delta!r}")

    d = Date(t * 1000)
    tup = (
        d.getFullYear(),
        d.getMonth(),
        d.getDate(),
        d.getHours(),
        d.getMinutes(),
        d.getSeconds(),
    )
    if deltaName == "s":
        tup[5] += deltaFactor
    elif deltaName == "m":
        tup[4] += deltaFactor
    elif deltaName == "h":
        tup[3] += deltaFactor
    elif deltaName == "D":
        tup[2] += deltaFactor
    elif deltaName == "W":
        tup[2] += deltaFactor * 7
    elif deltaName == "M":
        tup[1] += deltaFactor
    elif deltaName == "Y":
        tup[0] += deltaFactor
    else:
        raise RuntimeError("Invalid datetime delta: " + delta)

    return Date(tup[0], tup[1], tup[2], tup[3], tup[4],
                tup[5]).getTime() / 1000
예제 #3
0
    def draw(self):
        PSCRIPT_OVERLOAD = False  # noqa

        ctx = self.canvas.getContext("2d")

        # Prepare hidpi mode for canvas  (flush state just in case)
        for i in range(4):
            ctx.restore()
        ctx.save()
        ctx.scale(self.pixel_ratio, self.pixel_ratio)

        # Flip y-axis
        ctx.scale(1, -1)
        ctx.translate(0, -self.height)

        # Clear bg
        ctx.clearRect(0, 0, self.width, self.height)

        # Determine drawing area
        x0 = 45
        y0 = 35
        width = self.width - x0 - 15
        height = self.height - y0 - 5

        data = data_per_db[self.dbname]
        if len(data) == 0:
            return

        # Get bounding box
        t1 = data[0].time_start
        t2 = data[-1].time_stop
        mi, ma = self._get_min_max()
        if ma <= mi:
            return
        hscale = width / (t2 - t1)
        vscale = height / (ma - mi)

        unix_from_utc_tuple = Date.UTC  # avoid triggering new
        utc = get_hash_info().get("utc", False)
        xticks = {}

        # Prepare x ticks for hours (one hour is the smallest granularity)
        hourly_tick_units = (1, 3600), (2, 7200), (6, 21600)
        min_tick_dist = 60
        for nhours, tick_unit in hourly_tick_units:
            if tick_unit * hscale >= min_tick_dist:
                break
        else:
            tick_unit = 0
        #
        if tick_unit > 0:
            d = Date(t1 * 1000)
            if utc:
                tup = [
                    d.getUTCFullYear(),
                    d.getUTCMonth(),
                    d.getUTCDate(),
                    d.getUTCHours(),
                ]
                tup[-1] = nhours * int(tup[-1] / nhours)
                t = unix_from_utc_tuple(tup[0], tup[1], tup[2], tup[3]) / 1000
            else:
                tup = [
                    d.getFullYear(),
                    d.getMonth(),
                    d.getDate(),
                    d.getHours()
                ]
                tup[-1] = nhours * int(tup[-1] / nhours)
                t = Date(tup[0], tup[1], tup[2], tup[3]).getTime() / 1000
            while t <= t2:
                if t >= t1:
                    d = Date(t * 1000)
                    if utc:
                        xticks[
                            t] = f"{d.getUTCHours():02i}:{d.getUTCMinutes():02i}"
                    else:
                        xticks[t] = f"{d.getHours():02i}:{d.getMinutes():02i}"
                t += tick_unit

        # Prepare x ticks for days/months
        day_tick_units = (2, 1), (2, 2), (2, 5), (1, 1), (1, 2), (1, 3), (0,
                                                                          365)
        min_tick_dist = 60
        for dindex, nsomething in day_tick_units:
            tick_unit = nsomething * [365 * 86400, 30 * 86400, 86400][dindex]
            if tick_unit * hscale >= min_tick_dist:
                break
        else:
            tick_unit = nsomething = 0
        #
        n_date_ticks = 0
        if nsomething > 0:
            d = Date(t1 * 1000)
            if utc:
                tup = [d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()]
                tup[dindex] = nsomething * int(tup[dindex] / nsomething)
                t = unix_from_utc_tuple(tup[0], tup[1], tup[2]) / 1000
            else:
                tup = [d.getFullYear(), d.getMonth(), d.getDate()]
                tup[dindex] = nsomething * int(tup[dindex] / nsomething)
                t = Date(tup[0], tup[1], tup[2]).getTime() / 1000
            while t <= t2:
                if t >= t1:
                    n_date_ticks += 1
                    d = Date(t * 1000)
                    if utc:
                        dd = f"{d.getUTCDate():02i}"
                        mm = f"{d.getUTCMonth()+1:02i}"
                        yy = f"{d.getUTCFullYear()}"
                        xticks[t] = f"{dd}-{mm}-{yy}"
                    else:
                        dd = f"{d.getDate():02i}"
                        mm = f"{d.getMonth()+1:02i}"
                        yy = f"{d.getFullYear()}"
                        xticks[t] = f"{dd}-{mm}-{yy}"
                tup[dindex] += nsomething
                if utc:
                    t = unix_from_utc_tuple(tup[0], tup[1], tup[2]) / 1000
                else:
                    t = Date(tup[0], tup[1], tup[2]).getTime() / 1000
        #
        extra_x_tick = ""
        if n_date_ticks < 2:
            xtickskeys = xticks.keys()
            if len(xtickskeys) > 0 and hscale * (xtickskeys[0] - t1) < 30:
                xticks.pop(xtickskeys[0])
            d = Date(t1 * 1000)
            if utc:
                extra_x_tick = (
                    f"{d.getUTCFullYear()}-{d.getUTCMonth()+1:02i}-{d.getUTCDate():02i}"
                )
            else:
                extra_x_tick = (
                    f"{d.getFullYear()}-{d.getMonth()+1:02i}-{d.getDate():02i}"
                )

        # Prepare y ticks
        yticks = self._get_ticks(vscale, mi, ma, 25)  # text -> value

        # Prepare drawing
        ctx.lineWidth = 1

        # Draw grid lines
        ctx.strokeStyle = "rgba(128, 128, 128, 0.3)"
        ctx.beginPath()
        for v, text in yticks.items():
            y = y0 + (float(v) - mi) * vscale
            ctx.moveTo(x0, y)
            ctx.lineTo(x0 + width, y)
        ctx.stroke()

        # Draw x ticks
        ctx.strokeStyle = text_color
        ctx.fillStyle = text_color
        ctx.textAlign = "center"
        ctx.textBaseline = "top"  # middle
        ctx.beginPath()
        for t, text in xticks.items():
            x = x0 + (float(t) - t1) * hscale
            ctx.moveTo(x, y0)
            ctx.lineTo(x, y0 - 4)
        ctx.stroke()
        for t, text in xticks.items():
            x = x0 + (float(t) - t1) * hscale
            angle = 0  # -0.15 * Math.PI
            x = min(x, x0 + width - 15)
            self._draw_text(ctx, text, x, y0 - 10, angle)
        if extra_x_tick:
            ctx.textAlign = "left"
            ctx.textBaseline = "bottom"
            self._draw_text(ctx, extra_x_tick, 0, 0)

        # Draw y ticks
        ctx.textAlign = "right"
        ctx.textBaseline = "middle"
        ctx.beginPath()
        for v, text in yticks.items():
            y = y0 + (float(v) - mi) * vscale
            ctx.moveTo(x0 - 4, y)
            ctx.lineTo(x0, y)
        ctx.stroke()
        for v, text in yticks.items():
            y = y0 + (float(v) - mi) * vscale
            self._draw_text(ctx, text, x0 - 8, y)

        # Draw axis
        ctx.strokeStyle = text_color
        ctx.beginPath()
        ctx.moveTo(x0, y0)
        ctx.lineTo(x0 + width, y0)
        ctx.moveTo(x0, y0)
        ctx.lineTo(x0, y0 + height)
        ctx.stroke()

        # Draw content
        self._draw_content(ctx, mi, ma, t1, t2, x0, y0, hscale, vscale)

        # Draw local / UTC
        ctx.fillStyle = "rgba(128, 128, 128, 0.5)"
        ctx.textAlign = "right"
        ctx.textBaseline = "bottom"
        self._draw_text(ctx, "UTC" if utc else "Local time", self.width, 0)