```
import datetime
import pytz
from math import cos, radians, sin, degrees, acos, tan, asin, fabs, sqrt

# Solar apparent radius in degrees
SUN_APPARENT_RADIUS = 32.0 / (60.0 * 2.0)

class Observer:
    """Represents an observer's location on Earth.

    Attributes:
        latitude (float): Latitude in decimal degrees (positive for North).
        longitude (float): Longitude in decimal degrees (positive for East).
        elevation (float or tuple, optional): Elevation above sea level in meters.
          If a tuple is provided, it should be (height, distance) representing the height
          of an obscuring feature and its distance from the observer. Defaults to 0.0.
    """

    def __init__(self, latitude, longitude, elevation=0.0):
        self.latitude = latitude
        self.longitude = longitude
        self.elevation = elevation

def geometric_mean_anomaly_sun(julian_century: float) -> float:
    """Calculate the geometric mean anomaly of the Sun.

    Args:
        julian_century: Julian century.

    Returns:
        Geometric mean anomaly of the Sun in degrees.
    """
    return 357.52911 + julian_century * (35999.05029 - 0.0001537 * julian_century)

def sun_equation_of_center(julian_century: float) -> float:
    """Calculate the equation of the center of the Sun.

    Args:
        julian_century: Julian century.

    Returns:
        Equation of the center of the Sun in degrees.
    """
    m = geometric_mean_anomaly_sun(julian_century)
    m_rad = radians(m)
    sin_m = sin(m_rad)
    sin_2m = sin(2 * m_rad)
    sin_3m = sin(3 * m_rad)

    c = (sin_m * (1.914602 - julian_century * (0.004817 + 0.000014 * julian_century))
         + sin_2m * (0.019993 - 0.000101 * julian_century)
         + sin_3m * 0.000289)

    return c

def geometric_mean_longitude_sun(julian_century: float) -> float:
    """Calculate the geometric mean longitude of the Sun.

    Args:
        julian_century: Julian century.

    Returns:
        Geometric mean longitude of the Sun in degrees.
    """
    l0 = 280.46646 + julian_century * (36000.76983 + 0.0003032 * julian_century)
    return l0 % 360.0

def sun_true_longitude(julian_century: float) -> float:
    """Calculate the Sun's true longitude.

    Args:
        julian_century: Julian century.

    Returns:
        Sun's true longitude in degrees.
    """
    l0 = geometric_mean_longitude_sun(julian_century)
    c = sun_equation_of_center(julian_century)
    return l0 + c

def mean_obliquity_of_ecliptic(julian_century: float) -> float:
    """Calculate the mean obliquity of the ecliptic.

    Args:
        julian_century: Julian century.

    Returns:
        Mean obliquity of the ecliptic in degrees.
    """
    seconds = 21.448 - julian_century * (46.815 + julian_century * (0.00059 - julian_century * 0.001813))
    return 23.0 + (26.0 + (seconds / 60.0)) / 60.0

def obliquity_correction(julian_century: float) -> float:
    """Calculate the obliquity correction.

    Args:
        julian_century: Julian century.

    Returns:
        Obliquity correction in degrees.
    """
    e0 = mean_obliquity_of_ecliptic(julian_century)
    omega = 125.04 - 1934.136 * julian_century
    return e0 + 0.00256 * cos(radians(omega))

def sun_apparent_longitude(julian_century: float) -> float:
    """Calculate the Sun's apparent longitude.

    Args:
        julian_century: Julian century.

    Returns:
        Sun's apparent longitude in degrees.
    """
    true_long = sun_true_longitude(julian_century)
    omega = 125.04 - 1934.136 * julian_century
    return true_long - 0.00569 - 0.00478 * sin(radians(omega))

def sun_declination(julian_century: float) -> float:
    """Calculate the Sun's declination.

    Args:
        julian_century: Julian century.

    Returns:
        Sun's declination in degrees.
    """
    e = obliquity_correction(julian_century)
    lambd = sun_apparent_longitude(julian_century)
    sin_t = sin(radians(e)) * sin(radians(lambd))
    return degrees(asin(sin_t))

def julian_day(date_and_time: datetime.datetime | datetime.date, calendar: int = 1) -> float:
    """Calculate the Julian Day for the specified date/time.

    Julian Day numbers for dates are calculated for the start of the day.

    Args:
        date_and_time: Date and time.
        calendar: Calendar system (1 for Gregorian, other values for Julian).

    Returns:
        Julian Day number.
    """
    year = date_and_time.year
    month = date_and_time.month
    day = date_and_time.day

    if month <= 2:
        year -= 1
        month += 12

    a = int(year / 100)
    if calendar == 1:
        b = 2 - a + int(a / 4)
    else:
        b = 0

    day_fraction = 0.0
    if isinstance(date_and_time, datetime.datetime):
        day_fraction = (date_and_time.hour * 3600 + date_and_time.minute * 60 + date_and_time.second) / 86400.0

    jd = int(365.25 * (year + 4716)) + int(30.6001 * (month + 1)) + day + day_fraction + b - 1524.5
    return jd

def julian_day_to_julian_century(julian_day: float) -> float:
    """Convert a Julian Day number to a Julian Century."""
    return (julian_day - 2451545.0) / 36525.0

def julian_century_to_julian_day(julian_century: float) -> float:
    """Convert a Julian Century number to a Julian Day."""
    return (julian_century * 36525.0) + 2451545.0

def julian_day_2000(date_and_time: datetime.datetime | datetime.date) -> float:
    """Calculate the number of Julian Days since Jan 1.5, 2000."""
    return julian_day(date_and_time) - 2451545.0

def now(tz=None) -> datetime.datetime:
    """Returns the current time in the specified time zone."""
    now_utc = datetime.datetime.now(datetime.timezone.utc)
    if tz is None:
        return now_utc
    return now_utc.astimezone(tz)

def refraction_at_zenith(zenith: float) -> float:
    """Calculate the atmospheric refraction correction for the given zenith angle.

    Args:
        zenith: Zenith angle in degrees.

    Returns:
        Atmospheric refraction correction in degrees.
    """
    elevation = 90.0 - zenith
    if elevation >= 85.0:
        return 0.0

    refraction_correction = 0.0
    tan_elevation = tan(radians(elevation))

    if elevation > 5.0:
        refraction_correction = 58.1 / tan_elevation - 0.07 / (tan_elevation**3) + 0.000086 / (tan_elevation**5)
    elif elevation > -0.575:
        refraction_correction = 1735.0 + elevation * (-518.2 + elevation * (103.4 + elevation * (-12.79 + elevation * 0.711)))
    else:
        refraction_correction = -20.774 / tan_elevation

    return refraction_correction / 3600.0

def zenith_and_azimuth(observer: Observer, date_and_time: datetime.datetime, with_refraction: bool = True):
    """Calculate the solar zenith and azimuth angles.

    Args:
        observer: Observer's location.
        date_and_time: Date and time.
        with_refraction: Whether to apply atmospheric refraction correction.

    Returns:
        Tuple containing zenith and azimuth angles in degrees.
    """

    latitude = min(max(observer.latitude, -89.8), 89.8)  # Clamp latitude to avoid math domain errors
    longitude = observer.longitude

    if date_and_time.tzinfo is None:
        zone = 0.0
        utc_datetime = date_and_time
    else:
        zone = -date_and_time.utcoffset().total_seconds() / 3600.0  # type: ignore
        utc_datetime = date_and_time.astimezone(datetime.timezone.utc)

    jd = julian_day(utc_datetime)
    t = julian_day_to_julian_century(jd)
    declination = sun_declination(t)
    eqtime = equation_of_time(t)  # Use corrected function name

    solar_time_fix = eqtime + 4.0 * longitude + 60.0 * zone
    true_solar_time = date_and_time.hour * 60.0 + date_and_time.minute + date_and_time.second / 60.0 + solar_time_fix
    true_solar_time %= 1440.0  # Keep within 0-1440 minutes

    hour_angle = true_solar_time / 4.0 - 180.0
    if hour_angle < -180.0:
        hour_angle += 360.0

    cos_h = cos(radians(hour_angle))
    cos_lat = cos(radians(latitude))
    sin_lat = sin(radians(latitude))
    sin_dec = sin(radians(declination))
    cos_dec = cos(radians(declination))

    cos_zenith = cos_lat * cos_dec * cos_h + sin_lat * sin_dec
    cos_zenith = min(max(cos_zenith, -1.0), 1.0)  # Clamp to avoid math domain errors

    zenith = degrees(acos(cos_zenith))

    azimuth_denom = cos_lat * sin(radians(zenith))
    if abs(azimuth_denom) > 0.001:
        azimuth_rad = (sin_lat * cos(radians(zenith)) - sin_dec) / azimuth_denom
        azimuth_rad = min(max(azimuth_rad, -1.0), 1.0)  # Clamp to avoid math domain error
        azimuth = 180.0 - degrees(acos(azimuth_rad))
        if hour_angle > 0.0:
            azimuth = -azimuth
    else:
        azimuth = 180.0 if latitude > 0.0 else 0.0

    azimuth %= 360.0

    if with_refraction:
        zenith -= refraction_at_zenith(zenith)

    return zenith, azimuth

def zenith(observer: Observer, date_and_time: datetime.datetime, with_refraction: bool = True) -> float:
    """Calculate the solar zenith angle."""
    return zenith_and_azimuth(observer, date_and_time, with_refraction)[0]

def eccentric_location_earth_orbit(julian_century: float) -> float:
    """Calculate the eccentricity of Earth's orbit."""
    return 0.016708634 - julian_century * (0.000042037 + 0.0000001267 * julian_century)

def var_y(julian_century: float) -> float:
    """Calculate the var_y value for equation of time calculation."""
    epsilon = obliquity_correction(julian_century)
    y = tan(radians(epsilon) / 2.0)
    return y * y

def equation_of_time(julian_century: float) -> float:
    """Calculate the equation of time.

    Args:
        julian_century: The Julian century.

    Returns:
        The equation of time in minutes.
    """
    l0 = geometric_mean_longitude_sun(julian_century)
    e = eccentric_location_earth_orbit(julian_century)
    m = geometric_mean_anomaly_sun(julian_century)
    y = var_y(julian_century)

    sin_2l0 = sin(2.0 * radians(l0))
    sin_m = sin(radians(m))
    cos_2l0 = cos(2.0 * radians(l0))
    sin_4l0 = sin(4.0 * radians(l0))
    sin_2m = sin(2.0 * radians(m))

    etime = (y * sin_2l0 - 2.0 * e * sin_m + 4.0 * e * y * sin_m * cos_2l0
             - 0.5 * y * y * sin_4l0 - 1.25 * e * e * sin_2m)

    return degrees(etime) * 4.0

def adjust_to_horizon(elevation: float) -> float:
    """Calculate the horizon adjustment for elevation."""
    if elevation <= 0:
        return 0.0
    r = 6356900.0  # Earth's radius in meters
    a1 = r
    h1 = r + elevation
    theta1 = acos(a1 / h1)
    return degrees(theta1)

def adjust_to_obscuring_feature(elevation: tuple) -> float:
    """Calculate adjustment for an obscuring feature."""
    if elevation[0] == 0.0:
        return 0.0
    sign = -1 if elevation[0] < 0.0 else 1
    return sign * degrees(acos(fabs(elevation[0]) / sqrt(elevation[0]**2 + elevation[1]**2)))

def hour_angle(latitude: float, declination: float, zenith: float, direction: int) -> float:
    """Calculate the hour angle."""
    lat_rad = radians(latitude)
    dec_rad = radians(declination)
    zenith_rad = radians(zenith)

    h = (cos(zenith_rad) - sin(lat_rad) * sin(dec_rad)) / (cos(lat_rad) * cos(dec_rad))

    if abs(h) > 1:
        raise ValueError("math domain error")  # Sun never rises/sets

    hour_angle_rad = acos(h)
    return hour_angle_rad if direction == 1 else -hour_angle_rad

def minutes_to_timedelta(minutes: float) -> datetime.timedelta:
    """Convert minutes to timedelta."""
    return datetime.timedelta(minutes=minutes)

def time_of_transit(
        observer: Observer,
        date: datetime.date,
        zenith: float,
        direction: int,
        with_refraction: bool = True
) -> datetime.datetime:
    """Calculate time of transit for a given zenith angle.

    Args:
        observer: Observer instance.
        date: Date of transit.
        zenith: Zenith angle for transit.
        direction: 1 for sunrise, -1 for sunset.
        with_refraction: Whether to include refraction.

    Returns:
        Datetime of transit in UTC.

    Raises:
        ValueError: If no transit occurs.
    """
    latitude = min(max(observer.latitude, -89.8), 89.8)

    elevation_adjustment = 0.0
    if isinstance(observer.elevation, float) and observer.elevation > 0.0:
        elevation_adjustment = adjust_to_horizon(observer.elevation)
    elif isinstance(observer.elevation, tuple):
        elevation_adjustment = adjust_to_obscuring_feature(observer.elevation)

    refraction_adjustment = refraction_at_zenith(zenith + elevation_adjustment) if with_refraction else 0.0

    jd = julian_day(date)
    time_utc = 0.0

    for _ in range(2):  # Iterate twice for accuracy
        jc = julian_day_to_julian_century(jd + time_utc / 1440.0)
        declination = sun_declination(jc)
        try:
            hour_angle_rad = hour_angle(latitude, declination, zenith + elevation_adjustment + refraction_adjustment, direction)
        except ValueError:
            raise ValueError("Sun never rises/sets on this date at this location") from None

        delta = -observer.longitude - degrees(hour_angle_rad)
        eqtime = equation_of_time(jc)
        offset = delta * 4.0 - eqtime
        time_utc = 720.0 + offset
        time_utc %= 1440  # Normalize to 0-1440 minutes

    td = minutes_to_timedelta(time_utc)
    dt = datetime.datetime.combine(date, datetime.time(0, 0)) + td
    dt = dt.replace(tzinfo=datetime.timezone.utc)
    return dt

def noon(observer: Observer, date: datetime.date, tzinfo: datetime.tzinfo | str) -> datetime.datetime:
    """Calculate solar noon."""
    if isinstance(tzinfo, str):
        tzinfo = pytz.timezone(tzinfo)

    jc = julian_day_to_julian_century(julian_day(date))
    eqtime = equation_of_time(jc)
    time_utc = (720.0 - 4.0 * observer.longitude - eqtime)
    td = minutes_to_timedelta(time_utc)

    dt = datetime.datetime.combine(date, datetime.time(0, 0)) + td
    dt = dt.replace(tzinfo=datetime.timezone.utc)
    return dt.astimezone(tzinfo)

def calculate_sunrise(observer: Observer, date: datetime.date, tzinfo: datetime.tzinfo | str) -> datetime.datetime:
    """Calculate sunrise time."""
    if isinstance(tzinfo, str):
        tzinfo = pytz.timezone(tzinfo)

    try:
        sunrise = time_of_transit(observer, date, 90.0 + SUN_APPARENT_RADIUS, 1).astimezone(tzinfo)
        return sunrise
    except ValueError as e:
        raise ValueError(str(e)) from e

def calculate_sunset(observer: Observer, date: datetime.date, tzinfo: datetime.tzinfo | str) -> datetime.datetime:
    """Calculate sunset time."""
    if isinstance(tzinfo, str):
        tzinfo = pytz.timezone(tzinfo)
    try:
        sunset = time_of_transit(observer, date, 90.0 + SUN_APPARENT_RADIUS, -1).astimezone(tzinfo)
        return sunset

    except ValueError as e:
        raise ValueError(str(e)) from e

def calculate_sunrise_sunset_astral(latitude, longitude, timezone: str, date: datetime.date = None):
    """Calculate sunrise and sunset times using Astral package."""
    if date is None:
        date = datetime.date.today()
        
    observer = Observer(latitude=latitude, longitude=longitude)
    sunrise = calculate_sunrise(observer, date, timezone)
    sunset = calculate_sunset(observer, date, timezone)
    return sunrise, sunset

if __name__ == "__main__":
    # Example usage:
    latitude=9.9500167
    longitude=76.283925
    date = datetime.date(2024, 10, 14)
    timezone = 'Asia/Kolkata'

    sunrise, sunset = calculate_sunrise_sunset_astral(latitude, longitude, timezone, date)

    sunrise_str = sunrise.strftime("%dth %B %Y %I:%M:%S %p")
    sunset_str = sunset.strftime("%dth %B %Y %I:%M:%S %p")

    print(f"Sunrise: {sunrise_str}")
    print(f"Sunset: {sunset_str}")
```

simplify this code, remove unecessary logic. Ensure the working is still same and return full code.