from typing import NewType
from datetime import datetime, time, timezone, date


TimeTz = NewType('TimeTz', time)
DateTimeTz = NewType('DateTimeTz', datetime)
DateTimeNoTz = NewType('DateTimeNoTz', datetime)


def time_min() -> TimeTz:
    return time.min.replace(tzinfo=timezone.utc)


def time_max() -> TimeTz:
    return time.max.replace(tzinfo=timezone.utc)


def datetime_min() -> DateTimeTz:
    return datetime.min.replace(tzinfo=timezone.utc)


def datetime_max() -> DateTimeTz:
    return datetime.max.replace(tzinfo=timezone.utc)

from typing import NewType, Optional
from datetime import datetime, time, timezone, date


TimeTz = NewType('TimeTz', time)
DateTimeTz = NewType('DateTimeTz', datetime)
DateTimeNoTz = NewType('DateTimeNoTz', datetime)


def time_min() -> TimeTz:
    return time.min.replace(tzinfo=timezone.utc)


def time_max() -> TimeTz:
    return time.max.replace(tzinfo=timezone.utc)


def datetime_min() -> DateTimeTz:
    return datetime.min.replace(tzinfo=timezone.utc)


def datetime_max() -> DateTimeTz:
    return datetime.max.replace(tzinfo=timezone.utc)


def with_min_time(d: date) -> DateTimeTz:
    return DateTimeTz(datetime.combine(d, time_min()))


def with_max_time(d: date) -> DateTimeTz:
    return DateTimeTz(datetime.combine(d, time_max()))


def safe_combine(d: date, t: TimeTz) -> DateTimeTz:
    return DateTimeTz(datetime.combine(d, t))


def ensure_tzinfo(t: time) -> TimeTz:
    if t.tzinfo is not None:
        return TimeTz(t)
    return TimeTz(t.replace(tzinfo=timezone.utc))


def combine_ensure_tzinfo(d: date, t: time) -> DateTimeTz:
    return safe_combine(d, ensure_tzinfo(t))


def combine_or_midnight(d: date, t: Optional[time]) -> DateTimeTz:
    if t is not None:
        return combine_ensure_tzinfo(d, t)
    return with_min_time(d)

Introduce many strictly typed datetime helper functions
Introduce many strictly typed datetime helper functions

- from typing import NewType
+ from typing import NewType, Optional
  from datetime import datetime, time, timezone, date
  
  
  TimeTz = NewType('TimeTz', time)
  DateTimeTz = NewType('DateTimeTz', datetime)
  DateTimeNoTz = NewType('DateTimeNoTz', datetime)
  
  
  def time_min() -> TimeTz:
      return time.min.replace(tzinfo=timezone.utc)
  
  
  def time_max() -> TimeTz:
      return time.max.replace(tzinfo=timezone.utc)
  
  
  def datetime_min() -> DateTimeTz:
      return datetime.min.replace(tzinfo=timezone.utc)
  
  
  def datetime_max() -> DateTimeTz:
      return datetime.max.replace(tzinfo=timezone.utc)
  
+ 
+ def with_min_time(d: date) -> DateTimeTz:
+     return DateTimeTz(datetime.combine(d, time_min()))
+ 
+ 
+ def with_max_time(d: date) -> DateTimeTz:
+     return DateTimeTz(datetime.combine(d, time_max()))
+ 
+ 
+ def safe_combine(d: date, t: TimeTz) -> DateTimeTz:
+     return DateTimeTz(datetime.combine(d, t))
+ 
+ 
+ def ensure_tzinfo(t: time) -> TimeTz:
+     if t.tzinfo is not None:
+         return TimeTz(t)
+     return TimeTz(t.replace(tzinfo=timezone.utc))
+ 
+ 
+ def combine_ensure_tzinfo(d: date, t: time) -> DateTimeTz:
+     return safe_combine(d, ensure_tzinfo(t))
+ 
+ 
+ def combine_or_midnight(d: date, t: Optional[time]) -> DateTimeTz:
+     if t is not None:
+         return combine_ensure_tzinfo(d, t)
+     return with_min_time(d)
+ 
Introduce many strictly typed datetime helper functions
## Code Before:
from typing import NewType
from datetime import datetime, time, timezone, date


TimeTz = NewType('TimeTz', time)
DateTimeTz = NewType('DateTimeTz', datetime)
DateTimeNoTz = NewType('DateTimeNoTz', datetime)


def time_min() -> TimeTz:
    return time.min.replace(tzinfo=timezone.utc)


def time_max() -> TimeTz:
    return time.max.replace(tzinfo=timezone.utc)


def datetime_min() -> DateTimeTz:
    return datetime.min.replace(tzinfo=timezone.utc)


def datetime_max() -> DateTimeTz:
    return datetime.max.replace(tzinfo=timezone.utc)

## Instruction:
Introduce many strictly typed datetime helper functions
## Code After:
from typing import NewType, Optional
from datetime import datetime, time, timezone, date


TimeTz = NewType('TimeTz', time)
DateTimeTz = NewType('DateTimeTz', datetime)
DateTimeNoTz = NewType('DateTimeNoTz', datetime)


def time_min() -> TimeTz:
    return time.min.replace(tzinfo=timezone.utc)


def time_max() -> TimeTz:
    return time.max.replace(tzinfo=timezone.utc)


def datetime_min() -> DateTimeTz:
    return datetime.min.replace(tzinfo=timezone.utc)


def datetime_max() -> DateTimeTz:
    return datetime.max.replace(tzinfo=timezone.utc)


def with_min_time(d: date) -> DateTimeTz:
    return DateTimeTz(datetime.combine(d, time_min()))


def with_max_time(d: date) -> DateTimeTz:
    return DateTimeTz(datetime.combine(d, time_max()))


def safe_combine(d: date, t: TimeTz) -> DateTimeTz:
    return DateTimeTz(datetime.combine(d, t))


def ensure_tzinfo(t: time) -> TimeTz:
    if t.tzinfo is not None:
        return TimeTz(t)
    return TimeTz(t.replace(tzinfo=timezone.utc))


def combine_ensure_tzinfo(d: date, t: time) -> DateTimeTz:
    return safe_combine(d, ensure_tzinfo(t))


def combine_or_midnight(d: date, t: Optional[time]) -> DateTimeTz:
    if t is not None:
        return combine_ensure_tzinfo(d, t)
    return with_min_time(d)
