class_docstr: Parse input objects from the user into a metric query specification.
  
  Input objects are converted into *ResolverInput objects and then passed to the query resolver. The query resolver
  returns concrete specs corresponding to the request input / issues with query resolution.
  
  TODO: Add fuzzy match results.
class_docstr_tok: ["Parse","input","objects","from","the","user","into","a","metric","query","specification",".","Input","objects","are","converted","into","*","ResolverInput","objects","and","then","passed","to","the","query","resolver",".","The","query","resolver","returns","concrete","specs","corresponding","to","the","request","input","\/","issues","with","query","resolution",".","TODO",":","Add","fuzzy","match","results","."]
code: def _adjust_time_constraint(
      self,
      resolution_dag: GroupByItemResolutionDag,
      time_dimension_specs_in_query: Sequence[TimeDimensionSpec],
      time_constraint: TimeRangeConstraint,
  ) -> TimeRangeConstraint:
      metric_time_granularity = (
          MetricFlowQueryParser._metric_time_granularity(
              time_dimension_specs_in_query
          )
      )
      if metric_time_granularity is None:
          group_by_item_resolver = GroupByItemResolver(
              manifest_lookup=self._manifest_lookup,
              resolution_dag=resolution_dag,
          )
          metric_time_granularity = (
              group_by_item_resolver.resolve_min_metric_time_grain()
          )
  
      """Change the time range so that the ends are at the ends of the appropriate time granularity windows.
  
          e.g. [2020-01-15, 2020-2-15] with MONTH granularity -> [2020-01-01, 2020-02-29]
          """
      constraint_start = time_constraint.start_time
      constraint_end = time_constraint.end_time
  
      start_ts = pd.Timestamp(time_constraint.start_time)
      if not is_period_start(metric_time_granularity, start_ts):
          constraint_start = adjust_to_start_of_period(
              metric_time_granularity, start_ts
          ).to_pydatetime()
  
      end_ts = pd.Timestamp(time_constraint.end_time)
      if not is_period_end(metric_time_granularity, end_ts):
          constraint_end = adjust_to_end_of_period(
              metric_time_granularity, end_ts
          ).to_pydatetime()
  
      if constraint_start < TimeRangeConstraint.ALL_TIME_BEGIN():
          constraint_start = TimeRangeConstraint.ALL_TIME_BEGIN()
      if constraint_end > TimeRangeConstraint.ALL_TIME_END():
          constraint_end = TimeRangeConstraint.ALL_TIME_END()
  
      return TimeRangeConstraint(
          start_time=constraint_start, end_time=constraint_end
      )
  
imports: from __future__ import annotations
  import datetime
  import logging
  from typing import List, Optional, Sequence, Tuple, Union
  import pandas
  from dbt_semantic_interfaces.implementations.filters.where_filter import PydanticWhereFilter, PydanticWhereFilterIntersection
  from dbt_semantic_interfaces.pretty_print import pformat_big_objects
  from dbt_semantic_interfaces.protocols import SavedQuery
  from dbt_semantic_interfaces.protocols.where_filter import WhereFilter
  from dbt_semantic_interfaces.type_enums import TimeGranularity
  from metricflow.assert_one_arg import assert_at_most_one_arg_set
  from metricflow.filters.merge_where import merge_to_single_where_filter
  from metricflow.filters.time_constraint import TimeRangeConstraint
  from metricflow.mf_logging.formatting import indent
  from metricflow.mf_logging.pretty_print import mf_pformat
  from metricflow.mf_logging.runtime import log_runtime
  from metricflow.model.semantic_manifest_lookup import SemanticManifestLookup
  from metricflow.naming.dunder_scheme import DunderNamingScheme
  from metricflow.naming.metric_scheme import MetricNamingScheme
  from metricflow.naming.object_builder_scheme import ObjectBuilderNamingScheme
  from metricflow.protocols.query_parameter import GroupByParameter, MetricQueryParameter, OrderByQueryParameter, SavedQueryParameter
  from metricflow.query.group_by_item.filter_spec_resolution.filter_pattern_factory import DefaultWhereFilterPatternFactory, WhereFilterPatternFactory
  from metricflow.query.group_by_item.group_by_item_resolver import GroupByItemResolver
  from metricflow.query.group_by_item.resolution_dag.dag import GroupByItemResolutionDag
  from metricflow.query.issues.issues_base import MetricFlowQueryResolutionIssueSet
  from metricflow.query.issues.parsing.string_input_parsing_issue import StringInputParsingIssue
  from metricflow.query.query_exceptions import InvalidQueryException
  from metricflow.query.query_resolution import InputToIssueSetMapping, InputToIssueSetMappingItem
  from metricflow.query.query_resolver import MetricFlowQueryResolver
  from metricflow.query.resolver_inputs.base_resolver_inputs import MetricFlowQueryResolverInput
  from metricflow.query.resolver_inputs.query_resolver_inputs import InvalidStringInput, ResolverInputForGroupByItem, ResolverInputForLimit, ResolverInputForMetric, ResolverInputForMinMaxOnly, ResolverInputForOrderByItem, ResolverInputForQuery, ResolverInputForQueryLevelWhereFilterIntersection
  from metricflow.specs.patterns.base_time_grain import BaseTimeGrainPattern
  from metricflow.specs.patterns.metric_time_pattern import MetricTimePattern
  from metricflow.specs.patterns.none_date_part import NoneDatePartPattern
  from metricflow.specs.specs import InstanceSpec, InstanceSpecSet, MetricFlowQuerySpec, TimeDimensionSpec
  from metricflow.time.time_granularity import adjust_to_end_of_period, adjust_to_start_of_period, is_period_end, is_period_start
label_desc: Use image node_id 5 for calling the MetricFlowQueryParser obj's underlying member method code with example usage: obj._adjust_time_constraint(resolution_dag, time_dimension_specs_in_query, time_constraint) and returns: TimeRangeConstraint