code: def get_timestamp_ceil(ts, freq):
      """Returns the smallest timestamp that is greater than or equal to `ts`
      and is also a multiple of the `freq`.
      Assume hourly frequency i.e. `freq` = "H". Then
      If `ts` = 1:30, this function returns 2:00.
      If `ts` = 1:00, this function returns 1:00.
  
      Parameters
      ----------
      ts: `str`
          Timestamp in `str` format.
      freq: `str`
          Pandas timeseries frequency string.
  
      Returns
      -------
      dt_ceil: `pd.Timestamp`
          The smallest timestamp that is greater than or equal to `ts`
          and is also a multiple of the `freq`.
      """
      dt = pd.to_datetime(ts)
      try:
          return dt.ceil(freq=freq)
      # `pd.Timestamp.ceil` raises a ValueError when `freq` is a non-fixed frequency
      # e.g. weekly ("W-MON"), business day ("B) or monthly ("M")
      except ValueError:
          return dt.to_period(freq).to_timestamp(how="E").normalize()
  
file_path: greykite/greykite/detection/detector/ad_utils.py
imports: from functools import reduce
  import pandas
  from greykite.common.constants import ANOMALY_COL
  from greykite.common.constants import END_TIME_COL
  from greykite.common.constants import START_TIME_COL
  from greykite.common.constants import TIME_COL
  from greykite.common.features.outlier import ZScoreOutlierDetector
  from greykite.common.logging import LoggingLevelEnum
  from greykite.common.logging import log_message
  from greykite.detection.detector.constants import Z_SCORE_CUTOFF
label_desc: Use image node_id 8 for calling a global function with example usage: get_timestamp_ceil(ts, freq) and returns: dt, dt