docs: def get_concepts_to_recalculate(self, users, lang, concepts=None):
          """
          Get concept which have same changes and have to be recalculated
  
          Args:
              users (list of users or user): users whose user stats we are interesting in
              lang (str): language of used concepts
              concepts (Optional[list of concepts]): list of primary keys of concepts or concepts
                  Defaults to None meaning all concepts.
  
          Returns:
              dict: user -> set of concepts (int) - in case of list of users
              list of stats (str) - in case of one user
          """
          only_one_user = False
          if not isinstance(users, list):
              only_one_user = True
              users = [users]
  
          mapping = self.get_item_concept_mapping(lang)
          current_user_stats = defaultdict(lambda: {})
          user_stats_qs = UserStat.objects.filter(user__in=users, stat="answer_count")     # we need only one type
          if concepts is not None:
              user_stats_qs = user_stats_qs.filter(concept__in=concepts)
          for user_stat in user_stats_qs:
              current_user_stats[user_stat.user_id][user_stat.concept_id] = user_stat
  
          concepts_to_recalculate = defaultdict(lambda: set())
          for user, item, time in Answer.objects.filter(user__in=users)\
                  .values_list("user_id", "item").annotate(Max("time")):
              if item not in mapping:
                  # in reality this should by corner case, so it is efficient to not filter Answers
                  continue    # item is not in concept
              time_expiration_lower_bound = get_config('proso_models', 'knowledge_overview.time_shift_hours', default=4)
              time_expiration_factor = get_config('proso_models', 'knowledge_overview.time_expiration_factor', default=2)
              for concept in mapping[item]:
                  if user in current_user_stats and concept in current_user_stats[user] \
                          and current_user_stats[user][concept].time > time:
                      if not self.has_time_expired(current_user_stats[user][concept].time, time, time_expiration_lower_bound, time_expiration_factor):
                          continue  # cache is up to date
  
                  if concepts is None or concept in ([c.pk for c in concepts] if type(concepts[0]) == Concept else Concept):
                      concepts_to_recalculate[user].add(concept)
  
          if only_one_user:
              return concepts_to_recalculate[users[0]]
          return concepts_to_recalculate