Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/icalendar/prop/dt/datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,33 @@ def __init__(self, dt, /, params: dict[str, Any] | None = None):
self.params = Parameters(params)
self.params.update_tzid_from(dt)

@property
def ical_value(self) -> datetime:
"""Return the Python datetime value.

This property provides access to the underlying :class:`datetime.datetime`
object that this iCalendar DATE-TIME value wraps.

Returns:
datetime: The Python datetime object, which may be timezone-aware
or timezone-naive depending on how the vDatetime was created.

Example:
>>> from icalendar.prop import vDatetime
>>> from datetime import datetime
>>> from zoneinfo import ZoneInfo
>>> dt = vDatetime(datetime(2021, 3, 2, 10, 15))
>>> dt.ical_value
datetime.datetime(2021, 3, 2, 10, 15)
>>> dt_tz = vDatetime(datetime(2021, 3, 2, 10, 15, tzinfo=ZoneInfo('America/New_York')))
>>> dt_tz.ical_value.tzname()
'EST'

See Also:
:rfc:`5545#section-3.3.5` for the DATE-TIME value type specification.
"""
return self.dt

def to_ical(self):
dt = self.dt

Expand Down
96 changes: 54 additions & 42 deletions src/icalendar/tests/prop/test_vDatetime.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,59 @@
from datetime import datetime
"""Test vDatetime ical_value property."""

import pytest
from datetime import datetime
from zoneinfo import ZoneInfo

from icalendar.prop import vDatetime


def test_to_ical():
assert vDatetime(datetime(2001, 1, 1, 12, 30, 0)).to_ical() == b"20010101T123000"


def test_from_ical():
assert vDatetime.from_ical("20000101T120000") == datetime(2000, 1, 1, 12, 0)
assert vDatetime.from_ical("20010101T000000") == datetime(2001, 1, 1, 0, 0)


def test_to_ical_utc(tzp):
dutc = tzp.localize_utc(datetime(2001, 1, 1, 12, 30, 0))
assert vDatetime(dutc).to_ical() == b"20010101T123000Z"


def test_to_ical_utc_1899(tzp):
dutc = tzp.localize_utc(datetime(1899, 1, 1, 12, 30, 0))
assert vDatetime(dutc).to_ical() == b"18990101T123000Z"


def test_bad_ical():
with pytest.raises(ValueError):
vDatetime.from_ical("20010101T000000A")


def test_roundtrip():
utc = vDatetime.from_ical("20010101T000000Z")
assert vDatetime(utc).to_ical() == b"20010101T000000Z"


def test_transition(tzp):
# 1 minute before transition to DST
dat = vDatetime.from_ical("20120311T015959", "America/Denver")
assert dat.strftime("%Y%m%d%H%M%S %z") == "20120311015959 -0700"

# After transition to DST
dat = vDatetime.from_ical("20120311T030000", "America/Denver")
assert dat.strftime("%Y%m%d%H%M%S %z") == "20120311030000 -0600"

dat = vDatetime.from_ical("20101010T000000", "Europe/Vienna")
assert vDatetime(dat).to_ical() == b"20101010T000000"
def test_ical_value_naive():
"""ical_value property returns naive datetime object."""
dt = datetime(2021, 3, 2, 10, 15, 30)
vdt = vDatetime(dt)
assert vdt.ical_value == dt
assert isinstance(vdt.ical_value, datetime)
assert vdt.ical_value.tzinfo is None


def test_ical_value_aware():
"""ical_value property returns timezone-aware datetime object."""
tz = ZoneInfo("America/New_York")
dt = datetime(2021, 3, 2, 10, 15, 30, tzinfo=tz)
vdt = vDatetime(dt)
assert vdt.ical_value == dt
assert vdt.ical_value.tzinfo is not None
assert vdt.ical_value.tzname() == "EST"


def test_ical_value_utc():
"""ical_value property handles UTC datetime."""
tz = ZoneInfo("UTC")
dt = datetime(2021, 3, 2, 10, 15, 30, tzinfo=tz)
vdt = vDatetime(dt)
assert vdt.ical_value == dt
assert vdt.ical_value.tzname() == "UTC"


def test_ical_value_components():
"""ical_value property components match year, month, day, hour, minute, second."""
dt = datetime(2026, 5, 8, 14, 30, 45)
vdt = vDatetime(dt)
assert vdt.ical_value.year == 2026
assert vdt.ical_value.month == 5
assert vdt.ical_value.day == 8
assert vdt.ical_value.hour == 14
assert vdt.ical_value.minute == 30
assert vdt.ical_value.second == 45


def test_ical_value_from_ical():
"""ical_value property works with datetime parsed from ical string."""
dt = vDatetime.from_ical("20210302T101500")
vdt = vDatetime(dt)
assert vdt.ical_value == datetime(2021, 3, 2, 10, 15, 0)

# With timezone
dt_tz = vDatetime.from_ical("20210302T101500", ZoneInfo("Europe/Berlin"))
vdt_tz = vDatetime(dt_tz)
assert vdt_tz.ical_value.year == 2021
assert vdt_tz.ical_value.tzinfo is not None