method performs *timeperiod's stem grouping*.
        :param timeperiod: timeperiod to augment
        :param stem: inclusive lower boundary for the timeperiod's corresponding token. For instance:
                - for 2015010520 and QUALIFIER_MONTHLY, stem would be 01
                - for 2015010520 and QUALIFIER_DAILY, stem would be 05
                - for 2015010520 and QUALIFIER_HOURLY, stem would be 20
        :return: grouped stem. For instance:
                - for 2015010520 and QUALIFIER_MONTHLY and time_grouping=3, stem would be 03
                - for 2015010520 and QUALIFIER_DAILY and time_grouping=2, stem would be 06
                - for 2015010520 and QUALIFIER_HOURLY and time_grouping=8, stem would be 23

def _do_stem_grouping(self, timeperiod, stem):
        """
        method performs *timeperiod's stem grouping*.
        :param timeperiod: timeperiod to augment
        :param stem: inclusive lower boundary for the timeperiod's corresponding token. For instance:
                - for 2015010520 and QUALIFIER_MONTHLY, stem would be 01
                - for 2015010520 and QUALIFIER_DAILY, stem would be 05
                - for 2015010520 and QUALIFIER_HOURLY, stem would be 20
        :return: grouped stem. For instance:
                - for 2015010520 and QUALIFIER_MONTHLY and time_grouping=3, stem would be 03
                - for 2015010520 and QUALIFIER_DAILY and time_grouping=2, stem would be 06
                - for 2015010520 and QUALIFIER_HOURLY and time_grouping=8, stem would be 23
        """

        # exclude 00 from lower boundary, unless the grouping == 1
        lower_boundary = 0 if self.time_grouping == 1 else 1
        upper_boundary = self._get_stem_upper_boundary(timeperiod)

        for i in range(lower_boundary, upper_boundary):
            candidate = i * self.time_grouping
            if stem <= candidate <= upper_boundary:
                return candidate
        return upper_boundary