Repository: sunpy/sunpy

Issue:
`RotatedSunFrame` should accept an `astropy.time.TimeDelta` object as `durations=` input
### Describe the feature

If you do `map1.date - map2.date` and pass that into `durations=` you get a `TimeDelta` object which isn't a valid quantity so you have to call the `.to` method which seems silly.


Discussion:
nabobalis: The test is failing, I am not sure what the problem.
Prtm2110: > The test is failing, I am not sure what the problem.

Got it now, the test itself is having an error from upstream i.e. the import was `from datetime import timedelta` but it should be `from astropy.time import TimeDelta` 

Prtm2110: @nabobalis are there any other necessary changes?
Prtm2110: Surely 
ayshih: Also, in the class docstring, please add `TimeDelta` as an acceptable type for the `duration` parameter
Prtm2110: > Also, in the class docstring, please add `TimeDelta` as an acceptable type for the `duration` parameter

Sure. Should I also provide a brief explanation of the updated code, or is the current documentation sufficient?

Patch:
diff --git a/changelog/7752.feature.rst b/changelog/7752.feature.rst
new file mode 100644
index 000000000..df61fbc66
--- /dev/null
+++ b/changelog/7752.feature.rst
@@ -0,0 +1,1 @@
+The `~sunpy.coordinates.RotatedSunFrame` class now accepts a `~astropy.time.TimeDelta` object for the ``duration`` parameter.
diff --git a/sunpy/coordinates/metaframes.py b/sunpy/coordinates/metaframes.py
index 1388ac4e9..849868188 100644
--- a/sunpy/coordinates/metaframes.py
+++ b/sunpy/coordinates/metaframes.py
@@ -119,8 +119,8 @@ class RotatedSunFrame(SunPyBaseCoordinateFrame):
         A representation object or ``None`` to have no data.  Alternatively, use coordinate
         component keyword arguments, which depend on the base frame.
     base : `~astropy.coordinates.SkyCoord` or low-level coordinate object.
-        The coordinate which specifies the base coordinate frame.  The frame must be a SunPy frame.
-    duration : `~astropy.units.Quantity`
+        The coordinate which specifies the base coordinate frame. The frame must be a SunPy frame.
+    duration : `~astropy.units.Quantity` or `~astropy.time.TimeDelta`
         The duration of solar rotation (defaults to zero days).
     rotated_time : {parse_time_types}
         The time to rotate the Sun to.  If provided, ``duration`` will be set to the difference
@@ -154,7 +154,7 @@ class RotatedSunFrame(SunPyBaseCoordinateFrame):
 
     def __new__(cls, *args, **kwargs):
         # We don't want to call this method if we've already set up
-        # an rotated-Sun frame for this class.
+        # a rotated-Sun frame for this class.
         if not (issubclass(cls, RotatedSunFrame) and cls is not RotatedSunFrame):
             # We get the base argument, and handle it here.
             base_frame = kwargs.get('base', None)
@@ -178,13 +178,21 @@ class RotatedSunFrame(SunPyBaseCoordinateFrame):
 
     def __init__(self, *args, **kwargs):
         # Validate inputs
-        if kwargs['base'].obstime is None:
+        base_frame = kwargs.get('base')
+        if base_frame is None or base_frame.obstime is None:
             raise ValueError("The base coordinate frame must have a defined `obstime`.")
 
-        if 'rotated_time' in kwargs:
-            rotated_time = parse_time(kwargs['rotated_time'])
-            kwargs['duration'] = (rotated_time - kwargs['base'].obstime).to('day')
-            kwargs.pop('rotated_time')
+        duration = kwargs.pop('duration', None)
+        rotated_time = kwargs.pop('rotated_time', None)
+
+        if duration is not None and rotated_time is not None:
+            raise ValueError("Specify either `duration` or `rotated_time`, not both.")
+
+        if duration is not None:
+            rotated_time = base_frame.obstime + duration
+
+        if rotated_time is not None:
+            kwargs['duration'] = (parse_time(rotated_time) - base_frame.obstime).to('day')
 
         super().__init__(*args, **kwargs)
 


Test patch:
diff --git a/sunpy/coordinates/tests/test_metaframes.py b/sunpy/coordinates/tests/test_metaframes.py
index 5abf65175..9b1430bde 100644
--- a/sunpy/coordinates/tests/test_metaframes.py
+++ b/sunpy/coordinates/tests/test_metaframes.py
@@ -6,7 +6,7 @@ from hypothesis import given, settings
 import astropy.units as u
 from astropy.coordinates import HeliocentricMeanEcliptic, SkyCoord, frame_transform_graph
 from astropy.tests.helper import assert_quantity_allclose
-from astropy.time import Time
+from astropy.time import Time, TimeDelta
 
 import sunpy.coordinates.frames as f
 from sunpy.coordinates.metaframes import RotatedSunFrame, _rotatedsun_cache
@@ -146,6 +146,42 @@ def test_rotated_time_to_duration():
     assert_quantity_allclose(r2.duration, -1*u.day)
 
 
+def test_duration_from_timedelta():
+    base_frame = f.HeliographicStonyhurst(obstime='2001-01-01')
+
+    duration_timedelta = TimeDelta(4 * u.day)
+    r = RotatedSunFrame(base=base_frame, duration=duration_timedelta)
+
+    # Verify that the duration is correctly converted to a quantity in days
+    assert_quantity_allclose(r.duration, 4 * u.day)
+
+
+def test_duration_with_quantity_hours():
+    base_frame = f.HeliographicStonyhurst(obstime='2001-01-01')
+
+    # Testing with Quantity in hours (conversion needed)
+    duration_quantity = 96 * u.hour  # 4 days in hours
+    r = RotatedSunFrame(base=base_frame, duration=duration_quantity)
+    assert_quantity_allclose(r.duration, 4 * u.day)
+
+
+def test_both_duration_and_rotated_time_provided():
+    base_frame = f.HeliographicStonyhurst(obstime='2001-01-01')
+
+    with pytest.raises(ValueError, match="Specify either `duration` or `rotated_time`, not both."):
+        RotatedSunFrame(base=base_frame, duration=TimeDelta(1*u.day), rotated_time=Time('2001-01-02'))
+
+
+def test_duration_calculation():
+
+    base_time = Time('2001-01-01')
+    base_frame = f.HeliographicStonyhurst(obstime=base_time)
+    rotated_time = Time('2001-01-02')
+    r = RotatedSunFrame(base=base_frame, rotated_time=rotated_time)
+    expected_duration = (rotated_time.utc - base_time).to('day')
+    assert r.duration == expected_duration
+
+
 def test_rotated_time_property():
     r1 = RotatedSunFrame(base=f.HeliographicStonyhurst(obstime='2001-01-02'), duration=1*u.day)
     assert r1.rotated_time == Time('2001-01-03')