Zope DateTime

Description

Using Zope DateTime class in Plone programming

Introduction

Some Plone dates are stored as Zope DateTime objects. This is different from standard Python datetime (notice the letter casing). Zope DateTime predates Python datetime which was added in Python 2.4. Zope DateTime is old code, so do rites necessary for your religion before programming with it.

Note

Using Python datetime is recommended if possible. Zope DateTime should be dealt in legacy systems only as Python datetime is much more documented and widely used.

Default formatting

Since Plone 4

  • A per-language format string from a translations is preferred
  • If such string is not available the default is taken from portal_properties / site_properties

Formatting examples

US example:

localTimeFormat: %b %d, %Y
localLongTimeFormat: %b %d, %Y %I:%M %p

European style format:

localTimeFormat: %d.%m.%Y (like 1.12.2010) localLongTimeFormat: %H:%M %d.%m.%Y (like 12:59 1.12.2010)

More info

Converting between DateTime and datetime

Since two different datetime object types are used, you need to often convert between them.

You can convert Zope DateTime objects to datetime objects like so:

from DateTime import DateTime
zope_DT = DateTime() # this is now.
python_dt = zope_DT.asdatetime()

Vice versa, to convert from a Python datetime object to a Zope DateTime one:

zope_DT = DateTime(python_dt)

Note, if you use timezone information in python datetime objects, you might loose some information when converting. Zope DateTime handles all timezone information as offsets from GMT.

DateTime problems and pitfalls

This will fail silenty and you get a wrong date:

dt = DateTime("02.07.2010") # Parses like US date 02/07/2010

Please see

Parsing both US and European dates

Example:

# Lazy-ass way to parse both formats
# 2010/12/31
# 31.12.2010
try:
    if "." in rendDate:
        # European
        end = DateTime(rendDate, datefmt='international')
    else:
        # US
        end = DateTime(rendDate)

Friendly date/time formatting

Format datetime relative to the current time, human-readable:

def format_datetime_friendly_ago(date):
    """ Format date & time using site specific settings.

    @param date: datetime object
    """

    if date == None:
        return ""

    date = DT2dt(date) # zope DateTime -> python datetime

    # How long ago the timestamp is
    # See timedelta doc http://docs.python.org/lib/datetime-timedelta.html
    #since = datetime.datetime.utcnow() - date

    now = datetime.datetime.utcnow()
    now = now.replace(tzinfo=pytz.utc)

    since = now - date

    seconds = since.seconds + since.microseconds / 1E6 + since.days * 86400

    days = math.floor(seconds / (3600*24))

    if days <= 0 and seconds <= 0:
        # Timezone confusion, is in future
        return "moment ago"

    if days > 7:
        # Full date
        return date.strftime("%d.%m.%Y %H:%M")
    elif days >= 1:
        # Week day format
        return date.strftime("%A %H:%M")
    else:
        hours = math.floor(seconds/3600.0)
        minutes = math.floor((seconds % 3600) /60)
        if hours > 0:
            return "%d hours %d minutes ago" % (hours, minutes)
        else:
            if minutes > 0:
                return "%d minutes ago" % minutes
            else:
                return "few seconds ago"

Friendly date/time from TAL

From within your TAL templates, you can call toLocalizedTime() like:

<span tal:replace="python:here.toLocalizedTime(o.ModificationDate)"></span>