def _set_date(self, date):
        """
        implementation for set_date
        """
        # unwrap if necessary
        if isinstance(date, NowNodeValue):
            tmp = cython.declare(NowNodeValue)
            tmp = date
            date = tmp.value

        if date == self._now:
            return

        # remember the date before it's changed
        prev_date = self._now

        # don't allow the date to be changed on a shifted context as it will
        # potentially update values in the context below
        if self._shift_set and _now_node not in self._shift_set:
            raise Exception("Can't change the date on a shifted context")

        ctx = cython.declare(MDFContext)
        parent = cython.declare(MDFContext)
        prev_ctx = cython.declare(MDFContext)
        shifted_ctx = cython.declare(MDFContext)
        cookie = cython.declare(Cookie)
        node = cython.declare(MDFNodeBase)

        # get the prev_ctx and thread_id by activating the current context
        cookie = self._activate(None, None)
        thread_id = cookie.thread_id
        prev_ctx = cookie.prev_context
        self._deactivate(cookie)

        # get a list of all the contexts that are shifted by the same now
        # node as this context
        parent = self._parent if self._parent is not None else self
        all_shifted_contexts = parent.get_shifted_contexts()

        # create all_contexts as a list with the max number of elements potentially required
        all_contexts = cython.declare(list)
        all_contexts = [None] * (len(all_shifted_contexts) + 1)
        all_contexts[0] = self

        num_contexts = cython.declare(int)
        num_contexts = 1

        contexts_with_set_date_callbacks = cython.declare(list, [])
        have_on_set_date_callbacks = cython.declare(int, False)
        if self._has_nodes_requiring_set_date_callback:
            contexts_with_set_date_callbacks.append(self)
            have_on_set_date_callbacks = True

        if _now_node in self._shift_set:
            shifted_now = self._shift_set[_now_node]
            for shifted_ctx in all_shifted_contexts:
                shifted_shift_set = shifted_ctx.get_shift_set()
                try:
                    if shifted_shift_set[_now_node] is shifted_now:
                        if shifted_ctx is not self:
                            all_contexts[num_contexts] = shifted_ctx
                            num_contexts += 1
                            if shifted_ctx._has_nodes_requiring_set_date_callback:
                                contexts_with_set_date_callbacks.append(shifted_ctx)
                                have_on_set_date_callbacks = True
                except __HOLE__:
                    pass
        else:
            # now hasn't been shifted in this context so include all
            # other contexts also not shifted by now
            for shifted_ctx in all_shifted_contexts:
                if _now_node not in shifted_ctx.get_shift_set():
                    if shifted_ctx is not self:
                        all_contexts[num_contexts] = shifted_ctx
                        num_contexts += 1
                        if shifted_ctx._has_nodes_requiring_set_date_callback:
                            contexts_with_set_date_callbacks.append(shifted_ctx)
                            have_on_set_date_callbacks = True

        # trim any unused slots
        all_contexts = all_contexts[:num_contexts]

        # call the 'on_set_date' callback on any nodes needing it before
        # actually setting the date on the context.
        # If on_set_date returns True that indicates the node will become dirty
        # once the date has been changed.
        on_set_date_dirty = cython.declare(list)
        on_set_date_dirty_count = cython.declare(int, 0)
        if have_on_set_date_callbacks:
            on_set_date_dirty = []

            for ctx in contexts_with_set_date_callbacks:
                # get the calling node and activate the context once and for all nodes
                calling_node = ctx._get_calling_node(prev_ctx)
                cookie = ctx._activate(prev_ctx, thread_id)
                try:
                    # call the callbacks (this may call other nodes and so might
                    # modify the set of nodes with callbacks)
                    for node in ctx._nodes_requiring_set_date_callback.keys():
                        cqueue_push(ctx._node_eval_stack, node)
                        try:
                            with ctx._profile(node) as timer:
                                dirty = node.on_set_date(ctx, date)
                            if dirty:
                                on_set_date_dirty.append((node, ctx))
                                on_set_date_dirty_count += 1
                        finally:
                            cqueue_pop(ctx._node_eval_stack)
                finally:
                    ctx._deactivate(cookie)

        # now all the on_set_date callbacks have been called update the date
        # for each context and mark any incrementally updated nodes as dirty.
        for ctx in all_contexts:
            # set now on the context
            ctx._now = date

            # mark any incrementally updated nodes as dirty
            if ctx._has_incrementally_updated_nodes:
                for node in ctx._incrementally_updated_nodes.iterkeys():
                    node.set_dirty(ctx, DIRTY_FLAGS_TIME)

        # mark any nodes that indicated they would become dirty after calling 'on_set_date'
        if on_set_date_dirty_count > 0:
            for node, ctx in on_set_date_dirty:
                node.set_dirty(ctx, DIRTY_FLAGS_TIME)

        # set the now node value in the least shifted context
        # (anything dependent on now will be dependent on
        # it in this context so no need to touch it in the shifted contexts)
        alt_ctx = _now_node.get_alt_context(self)
        alt_ctx.set_value(_now_node, date)

        if date < prev_date:
            # if setting the date to a date in the past clear any incrementally
            # updated nodes so they'll start from their initial values again
            for ctx in all_contexts:
                # clear any cached values for the incrementally updated nodes
                for node in ctx._incrementally_updated_nodes.iterkeys():
                    node.clear_value(ctx)

                # these will be re-established as the date is incremented
                ctx._incrementally_updated_nodes.clear()
                ctx._has_incrementally_updated_nodes = False

                ctx._nodes_requiring_set_date_callback.clear()
                ctx._has_nodes_requiring_set_date_callback = False

            return

        # Evaluate any nodes that have to be updated incrementally each timestep.
        # They're marked as dirty first as they should be called every timestep
        # regardless of whether anything underneath has changed.
        #
        # this is done in two phases, setting flags then updating so that
        # if one node depends on another and causes it to get evaluated
        # it doesn't get called twice.
        # (the flags are already set in the loop previous to this one)
        for ctx in all_contexts:
            if not ctx._has_incrementally_updated_nodes:
                continue

            # get the calling node and activate the context once and for all nodes
            calling_node = ctx._get_calling_node(prev_ctx)
            cookie = ctx._activate(prev_ctx, thread_id)

            try:
                # get the value to trigger the update
                for node in ctx._incrementally_updated_nodes.keys():
                    ctx._get_node_value(node, calling_node, ctx, thread_id)
            finally:
                ctx._deactivate(cookie)
dataset/ETHPy150Open manahl/mdf/mdf/context.py/MDFContext._set_date