apache/beam · error · ValueError

dt not in UTC

Error message

dt not in UTC: %s

What it means

from_utc_datetime() accepts only datetimes whose tzinfo is exactly pytz.utc or datetime.timezone.utc; aware datetimes in other timezones (e.g. pytz timezone 'US/Pacific' or a +05:00 fixed offset) raise this ValueError. The API name means 'from a UTC datetime', not 'convert any datetime to UTC'.

Solutions

  1. Convert first: dt.astimezone(pytz.utc) or dt.astimezone(datetime.timezone.utc), then call from_utc_datetime
  2. Use Timestamp.of(dt), which handles any aware datetime via from_utc_datetime after conversion in newer code paths
  3. Store/produce UTC datetimes at the source instead of local ones

Example fix

// before
Timestamp.from_utc_datetime(local_dt)
// after
Timestamp.from_utc_datetime(local_dt.astimezone(pytz.utc))
Defensive patterns

Strategy: type-guard

Validate before calling

if dt.tzinfo not in (pytz.utc, datetime.timezone.utc):
    dt = dt.astimezone(pytz.utc)

Type guard

def is_utc(dt: datetime.datetime) -> bool:
    return dt.tzinfo in (pytz.utc, datetime.timezone.utc)

Try / catch

try:
    ts = Timestamp.from_utc_datetime(dt)
except ValueError as e:
    if 'not in UTC' in str(e):
        ts = Timestamp.from_utc_datetime(dt.astimezone(pytz.utc))
    else:
        raise

Prevention

When it happens

Trigger: Passing datetime(2024,1,1, tzinfo=timezone(timedelta(hours=5))); passing pytz.timezone('UTC').localize(dt) variants whose tzinfo compares unequal to pytz.utc; passing dt.astimezone() results in some non-UTC tz.

Common situations: Application timezone-aware datetimes passed directly instead of converted; pytz's localize used with wrong tz; reading aware datetimes from databases in local tz.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/b4bdaa1c50c09925. Report an issue: GitHub.

Appendix: source

Thrown at sdks/python/apache_beam/utils/timestamp.py:167

  @staticmethod
  def _epoch_datetime_utc() -> datetime.datetime:
    return datetime.datetime.fromtimestamp(0, pytz.utc)

  @classmethod
  def from_utc_datetime(cls, dt: datetime.datetime) -> 'Timestamp':
    """Create a ``Timestamp`` instance from a ``datetime.datetime`` object.

    Args:
      dt: A ``datetime.datetime`` object in UTC (offset-aware).
    """
    if dt.tzinfo is None:
      raise ValueError(
          "dt has no timezone info " +
          "(https://docs.python.org/3/library/datetime.html" +
          "#aware-and-naive-objects): %s" % dt)
    if dt.tzinfo != pytz.utc and dt.tzinfo != datetime.timezone.utc:
      raise ValueError('dt not in UTC: %s' % dt)
    duration = dt - cls._epoch_datetime_utc()
    # Avoid total_seconds(): its float result can be off by a microsecond.
    return Timestamp(
        seconds=duration.days * 86400 + duration.seconds,
        micros=duration.microseconds)

  @classmethod
  def from_rfc3339(cls, rfc3339: str) -> 'Timestamp':
    """Create a ``Timestamp`` instance from an RFC 3339 compliant string.

    Fractional seconds up to microseconds produce a microsecond-precision
    Timestamp; a longer fraction (up to nanoseconds) produces a Timestamp
    whose precision matches the number of fractional digits.

    .. note::
      All timezones are implicitly converted to UTC.

    Args:

View on GitHub (pinned to 12126d8942)