jpayne@69: Metadata-Version: 2.1 jpayne@69: Name: DateTime jpayne@69: Version: 5.5 jpayne@69: Summary: This package provides a DateTime data type, as known from Zope. Unless you need to communicate with Zope APIs, you're probably better off using Python's built-in datetime module. jpayne@69: Home-page: https://github.com/zopefoundation/DateTime jpayne@69: Author: Zope Foundation and Contributors jpayne@69: Author-email: zope-dev@zope.org jpayne@69: License: ZPL 2.1 jpayne@69: Classifier: Development Status :: 6 - Mature jpayne@69: Classifier: Environment :: Web Environment jpayne@69: Classifier: Framework :: Zope :: 4 jpayne@69: Classifier: License :: OSI Approved :: Zope Public License jpayne@69: Classifier: Operating System :: OS Independent jpayne@69: Classifier: Programming Language :: Python jpayne@69: Classifier: Programming Language :: Python :: 3 jpayne@69: Classifier: Programming Language :: Python :: 3.7 jpayne@69: Classifier: Programming Language :: Python :: 3.8 jpayne@69: Classifier: Programming Language :: Python :: 3.9 jpayne@69: Classifier: Programming Language :: Python :: 3.10 jpayne@69: Classifier: Programming Language :: Python :: 3.11 jpayne@69: Classifier: Programming Language :: Python :: 3.12 jpayne@69: Classifier: Programming Language :: Python :: Implementation :: CPython jpayne@69: Classifier: Programming Language :: Python :: Implementation :: PyPy jpayne@69: Requires-Python: >=3.7 jpayne@69: License-File: LICENSE.txt jpayne@69: Requires-Dist: zope.interface jpayne@69: Requires-Dist: pytz jpayne@69: jpayne@69: .. image:: https://github.com/zopefoundation/DateTime/workflows/tests/badge.svg jpayne@69: :target: https://github.com/zopefoundation/DateTime/actions?query=workflow%3Atests jpayne@69: :alt: CI status jpayne@69: jpayne@69: .. image:: https://img.shields.io/pypi/v/DateTime.svg jpayne@69: :target: https://pypi.org/project/DateTime/ jpayne@69: :alt: Current version on PyPI jpayne@69: jpayne@69: .. image:: https://img.shields.io/pypi/pyversions/DateTime.svg jpayne@69: :target: https://pypi.org/project/DateTime/ jpayne@69: :alt: Supported Python versions jpayne@69: jpayne@69: jpayne@69: DateTime jpayne@69: ======== jpayne@69: jpayne@69: This package provides a DateTime data type, as known from Zope. jpayne@69: jpayne@69: Unless you need to communicate with Zope APIs, you're probably better jpayne@69: off using Python's built-in datetime module. jpayne@69: jpayne@69: For further documentation, please have a look at `src/DateTime/DateTime.txt`. jpayne@69: jpayne@69: jpayne@69: .. contents:: jpayne@69: jpayne@69: The DateTime package jpayne@69: ==================== jpayne@69: jpayne@69: Encapsulation of date/time values. jpayne@69: jpayne@69: jpayne@69: Function Timezones() jpayne@69: -------------------- jpayne@69: jpayne@69: Returns the list of recognized timezone names: jpayne@69: jpayne@69: >>> from DateTime import Timezones jpayne@69: >>> zones = set(Timezones()) jpayne@69: jpayne@69: Almost all of the standard pytz timezones are included, with the exception jpayne@69: of some commonly-used but ambiguous abbreviations, where historical Zope jpayne@69: usage conflicts with the name used by pytz: jpayne@69: jpayne@69: >>> import pytz jpayne@69: >>> [x for x in pytz.all_timezones if x not in zones] jpayne@69: ['CET', 'EET', 'EST', 'MET', 'MST', 'WET'] jpayne@69: jpayne@69: Class DateTime jpayne@69: -------------- jpayne@69: jpayne@69: DateTime objects represent instants in time and provide interfaces for jpayne@69: controlling its representation without affecting the absolute value of jpayne@69: the object. jpayne@69: jpayne@69: DateTime objects may be created from a wide variety of string or jpayne@69: numeric data, or may be computed from other DateTime objects. jpayne@69: DateTimes support the ability to convert their representations to many jpayne@69: major timezones, as well as the ability to create a DateTime object jpayne@69: in the context of a given timezone. jpayne@69: jpayne@69: DateTime objects provide partial numerical behavior: jpayne@69: jpayne@69: * Two date-time objects can be subtracted to obtain a time, in days jpayne@69: between the two. jpayne@69: jpayne@69: * A date-time object and a positive or negative number may be added to jpayne@69: obtain a new date-time object that is the given number of days later jpayne@69: than the input date-time object. jpayne@69: jpayne@69: * A positive or negative number and a date-time object may be added to jpayne@69: obtain a new date-time object that is the given number of days later jpayne@69: than the input date-time object. jpayne@69: jpayne@69: * A positive or negative number may be subtracted from a date-time jpayne@69: object to obtain a new date-time object that is the given number of jpayne@69: days earlier than the input date-time object. jpayne@69: jpayne@69: DateTime objects may be converted to integer, long, or float numbers jpayne@69: of days since January 1, 1901, using the standard int, long, and float jpayne@69: functions (Compatibility Note: int, long and float return the number jpayne@69: of days since 1901 in GMT rather than local machine timezone). jpayne@69: DateTime objects also provide access to their value in a float format jpayne@69: usable with the Python time module, provided that the value of the jpayne@69: object falls in the range of the epoch-based time module. jpayne@69: jpayne@69: A DateTime object should be considered immutable; all conversion and numeric jpayne@69: operations return a new DateTime object rather than modify the current object. jpayne@69: jpayne@69: A DateTime object always maintains its value as an absolute UTC time, jpayne@69: and is represented in the context of some timezone based on the jpayne@69: arguments used to create the object. A DateTime object's methods jpayne@69: return values based on the timezone context. jpayne@69: jpayne@69: Note that in all cases the local machine timezone is used for jpayne@69: representation if no timezone is specified. jpayne@69: jpayne@69: Constructor for DateTime jpayne@69: ------------------------ jpayne@69: jpayne@69: DateTime() returns a new date-time object. DateTimes may be created jpayne@69: with from zero to seven arguments: jpayne@69: jpayne@69: * If the function is called with no arguments, then the current date/ jpayne@69: time is returned, represented in the timezone of the local machine. jpayne@69: jpayne@69: * If the function is invoked with a single string argument which is a jpayne@69: recognized timezone name, an object representing the current time is jpayne@69: returned, represented in the specified timezone. jpayne@69: jpayne@69: * If the function is invoked with a single string argument jpayne@69: representing a valid date/time, an object representing that date/ jpayne@69: time will be returned. jpayne@69: jpayne@69: As a general rule, any date-time representation that is recognized jpayne@69: and unambiguous to a resident of North America is acceptable. (The jpayne@69: reason for this qualification is that in North America, a date like: jpayne@69: 2/1/1994 is interpreted as February 1, 1994, while in some parts of jpayne@69: the world, it is interpreted as January 2, 1994.) A date/ time jpayne@69: string consists of two components, a date component and an optional jpayne@69: time component, separated by one or more spaces. If the time jpayne@69: component is omitted, 12:00am is assumed. jpayne@69: jpayne@69: Any recognized timezone name specified as the final element of the jpayne@69: date/time string will be used for computing the date/time value. jpayne@69: (If you create a DateTime with the string, jpayne@69: "Mar 9, 1997 1:45pm US/Pacific", the value will essentially be the jpayne@69: same as if you had captured time.time() at the specified date and jpayne@69: time on a machine in that timezone). If no timezone is passed, then jpayne@69: the timezone configured on the local machine will be used, **except** jpayne@69: that if the date format matches ISO 8601 ('YYYY-MM-DD'), the instance jpayne@69: will use UTC / GMT+0 as the timezone. jpayne@69: jpayne@69: o Returns current date/time, represented in US/Eastern: jpayne@69: jpayne@69: >>> from DateTime import DateTime jpayne@69: >>> e = DateTime('US/Eastern') jpayne@69: >>> e.timezone() jpayne@69: 'US/Eastern' jpayne@69: jpayne@69: o Returns specified time, represented in local machine zone: jpayne@69: jpayne@69: >>> x = DateTime('1997/3/9 1:45pm') jpayne@69: >>> x.parts() # doctest: +ELLIPSIS jpayne@69: (1997, 3, 9, 13, 45, ...) jpayne@69: jpayne@69: o Specified time in local machine zone, verbose format: jpayne@69: jpayne@69: >>> y = DateTime('Mar 9, 1997 13:45:00') jpayne@69: >>> y.parts() # doctest: +ELLIPSIS jpayne@69: (1997, 3, 9, 13, 45, ...) jpayne@69: >>> y == x jpayne@69: True jpayne@69: jpayne@69: o Specified time in UTC via ISO 8601 rule: jpayne@69: jpayne@69: >>> z = DateTime('2014-03-24') jpayne@69: >>> z.parts() # doctest: +ELLIPSIS jpayne@69: (2014, 3, 24, 0, 0, ...) jpayne@69: >>> z.timezone() jpayne@69: 'GMT+0' jpayne@69: jpayne@69: The date component consists of year, month, and day values. The jpayne@69: year value must be a one-, two-, or four-digit integer. If a one- jpayne@69: or two-digit year is used, the year is assumed to be in the jpayne@69: twentieth century. The month may an integer, from 1 to 12, a month jpayne@69: name, or a month abbreviation, where a period may optionally follow jpayne@69: the abbreviation. The day must be an integer from 1 to the number of jpayne@69: days in the month. The year, month, and day values may be separated jpayne@69: by periods, hyphens, forward slashes, or spaces. Extra spaces are jpayne@69: permitted around the delimiters. Year, month, and day values may be jpayne@69: given in any order as long as it is possible to distinguish the jpayne@69: components. If all three components are numbers that are less than jpayne@69: 13, then a month-day-year ordering is assumed. jpayne@69: jpayne@69: The time component consists of hour, minute, and second values jpayne@69: separated by colons. The hour value must be an integer between 0 jpayne@69: and 23 inclusively. The minute value must be an integer between 0 jpayne@69: and 59 inclusively. The second value may be an integer value jpayne@69: between 0 and 59.999 inclusively. The second value or both the jpayne@69: minute and second values may be omitted. The time may be followed jpayne@69: by am or pm in upper or lower case, in which case a 12-hour clock is jpayne@69: assumed. jpayne@69: jpayne@69: * If the DateTime function is invoked with a single numeric argument, jpayne@69: the number is assumed to be either a floating point value such as jpayne@69: that returned by time.time(), or a number of days after January 1, jpayne@69: 1901 00:00:00 UTC. jpayne@69: jpayne@69: A DateTime object is returned that represents either the GMT value jpayne@69: of the time.time() float represented in the local machine's jpayne@69: timezone, or that number of days after January 1, 1901. Note that jpayne@69: the number of days after 1901 need to be expressed from the jpayne@69: viewpoint of the local machine's timezone. A negative argument will jpayne@69: yield a date-time value before 1901. jpayne@69: jpayne@69: * If the function is invoked with two numeric arguments, then the jpayne@69: first is taken to be an integer year and the second argument is jpayne@69: taken to be an offset in days from the beginning of the year, in the jpayne@69: context of the local machine timezone. The date-time value returned jpayne@69: is the given offset number of days from the beginning of the given jpayne@69: year, represented in the timezone of the local machine. The offset jpayne@69: may be positive or negative. Two-digit years are assumed to be in jpayne@69: the twentieth century. jpayne@69: jpayne@69: * If the function is invoked with two arguments, the first a float jpayne@69: representing a number of seconds past the epoch in GMT (such as jpayne@69: those returned by time.time()) and the second a string naming a jpayne@69: recognized timezone, a DateTime with a value of that GMT time will jpayne@69: be returned, represented in the given timezone. jpayne@69: jpayne@69: >>> import time jpayne@69: >>> t = time.time() jpayne@69: jpayne@69: Time t represented as US/Eastern: jpayne@69: jpayne@69: >>> now_east = DateTime(t, 'US/Eastern') jpayne@69: jpayne@69: Time t represented as US/Pacific: jpayne@69: jpayne@69: >>> now_west = DateTime(t, 'US/Pacific') jpayne@69: jpayne@69: Only their representations are different: jpayne@69: jpayne@69: >>> now_east.equalTo(now_west) jpayne@69: True jpayne@69: jpayne@69: * If the function is invoked with three or more numeric arguments, jpayne@69: then the first is taken to be an integer year, the second is taken jpayne@69: to be an integer month, and the third is taken to be an integer day. jpayne@69: If the combination of values is not valid, then a DateTimeError is jpayne@69: raised. One- or two-digit years up to 69 are assumed to be in the jpayne@69: 21st century, whereas values 70-99 are assumed to be 20th century. jpayne@69: The fourth, fifth, and sixth arguments are floating point, positive jpayne@69: or negative offsets in units of hours, minutes, and days, and jpayne@69: default to zero if not given. An optional string may be given as jpayne@69: the final argument to indicate timezone (the effect of this is as if jpayne@69: you had taken the value of time.time() at that time on a machine in jpayne@69: the specified timezone). jpayne@69: jpayne@69: If a string argument passed to the DateTime constructor cannot be jpayne@69: parsed, it will raise SyntaxError. Invalid date, time, or jpayne@69: timezone components will raise a DateTimeError. jpayne@69: jpayne@69: The module function Timezones() will return a list of the timezones jpayne@69: recognized by the DateTime module. Recognition of timezone names is jpayne@69: case-insensitive. jpayne@69: jpayne@69: Instance Methods for DateTime (IDateTime interface) jpayne@69: --------------------------------------------------- jpayne@69: jpayne@69: Conversion and comparison methods jpayne@69: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ jpayne@69: jpayne@69: * ``timeTime()`` returns the date/time as a floating-point number in jpayne@69: UTC, in the format used by the Python time module. Note that it is jpayne@69: possible to create date /time values with DateTime that have no jpayne@69: meaningful value to the time module, and in such cases a jpayne@69: DateTimeError is raised. A DateTime object's value must generally jpayne@69: be between Jan 1, 1970 (or your local machine epoch) and Jan 2038 to jpayne@69: produce a valid time.time() style value. jpayne@69: jpayne@69: >>> dt = DateTime('Mar 9, 1997 13:45:00 US/Eastern') jpayne@69: >>> dt.timeTime() jpayne@69: 857933100.0 jpayne@69: jpayne@69: >>> DateTime('2040/01/01 UTC').timeTime() jpayne@69: 2208988800.0 jpayne@69: jpayne@69: >>> DateTime('1900/01/01 UTC').timeTime() jpayne@69: -2208988800.0 jpayne@69: jpayne@69: * ``toZone(z)`` returns a DateTime with the value as the current jpayne@69: object, represented in the indicated timezone: jpayne@69: jpayne@69: >>> dt.toZone('UTC') jpayne@69: DateTime('1997/03/09 18:45:00 UTC') jpayne@69: jpayne@69: >>> dt.toZone('UTC').equalTo(dt) jpayne@69: True jpayne@69: jpayne@69: * ``isFuture()`` returns true if this object represents a date/time jpayne@69: later than the time of the call: jpayne@69: jpayne@69: >>> dt.isFuture() jpayne@69: False jpayne@69: >>> DateTime('Jan 1 3000').isFuture() # not time-machine safe! jpayne@69: True jpayne@69: jpayne@69: * ``isPast()`` returns true if this object represents a date/time jpayne@69: earlier than the time of the call: jpayne@69: jpayne@69: >>> dt.isPast() jpayne@69: True jpayne@69: >>> DateTime('Jan 1 3000').isPast() # not time-machine safe! jpayne@69: False jpayne@69: jpayne@69: * ``isCurrentYear()`` returns true if this object represents a jpayne@69: date/time that falls within the current year, in the context of this jpayne@69: object's timezone representation: jpayne@69: jpayne@69: >>> dt.isCurrentYear() jpayne@69: False jpayne@69: >>> DateTime().isCurrentYear() jpayne@69: True jpayne@69: jpayne@69: * ``isCurrentMonth()`` returns true if this object represents a jpayne@69: date/time that falls within the current month, in the context of jpayne@69: this object's timezone representation: jpayne@69: jpayne@69: >>> dt.isCurrentMonth() jpayne@69: False jpayne@69: >>> DateTime().isCurrentMonth() jpayne@69: True jpayne@69: jpayne@69: * ``isCurrentDay()`` returns true if this object represents a jpayne@69: date/time that falls within the current day, in the context of this jpayne@69: object's timezone representation: jpayne@69: jpayne@69: >>> dt.isCurrentDay() jpayne@69: False jpayne@69: >>> DateTime().isCurrentDay() jpayne@69: True jpayne@69: jpayne@69: * ``isCurrentHour()`` returns true if this object represents a jpayne@69: date/time that falls within the current hour, in the context of this jpayne@69: object's timezone representation: jpayne@69: jpayne@69: >>> dt.isCurrentHour() jpayne@69: False jpayne@69: jpayne@69: >>> DateTime().isCurrentHour() jpayne@69: True jpayne@69: jpayne@69: * ``isCurrentMinute()`` returns true if this object represents a jpayne@69: date/time that falls within the current minute, in the context of jpayne@69: this object's timezone representation: jpayne@69: jpayne@69: >>> dt.isCurrentMinute() jpayne@69: False jpayne@69: >>> DateTime().isCurrentMinute() jpayne@69: True jpayne@69: jpayne@69: * ``isLeapYear()`` returns true if the current year (in the context of jpayne@69: the object's timezone) is a leap year: jpayne@69: jpayne@69: >>> dt.isLeapYear() jpayne@69: False jpayne@69: >>> DateTime('Mar 8 2004').isLeapYear() jpayne@69: True jpayne@69: jpayne@69: * ``earliestTime()`` returns a new DateTime object that represents the jpayne@69: earliest possible time (in whole seconds) that still falls within jpayne@69: the current object's day, in the object's timezone context: jpayne@69: jpayne@69: >>> dt.earliestTime() jpayne@69: DateTime('1997/03/09 00:00:00 US/Eastern') jpayne@69: jpayne@69: * ``latestTime()`` return a new DateTime object that represents the jpayne@69: latest possible time (in whole seconds) that still falls within the jpayne@69: current object's day, in the object's timezone context jpayne@69: jpayne@69: >>> dt.latestTime() jpayne@69: DateTime('1997/03/09 23:59:59 US/Eastern') jpayne@69: jpayne@69: Component access jpayne@69: ~~~~~~~~~~~~~~~~ jpayne@69: jpayne@69: * ``parts()`` returns a tuple containing the calendar year, month, jpayne@69: day, hour, minute second and timezone of the object jpayne@69: jpayne@69: >>> dt.parts() # doctest: +ELLIPSIS jpayne@69: (1997, 3, 9, 13, 45, ... 'US/Eastern') jpayne@69: jpayne@69: * ``timezone()`` returns the timezone in which the object is represented: jpayne@69: jpayne@69: >>> dt.timezone() in Timezones() jpayne@69: True jpayne@69: jpayne@69: * ``tzoffset()`` returns the timezone offset for the objects timezone: jpayne@69: jpayne@69: >>> dt.tzoffset() jpayne@69: -18000 jpayne@69: jpayne@69: * ``year()`` returns the calendar year of the object: jpayne@69: jpayne@69: >>> dt.year() jpayne@69: 1997 jpayne@69: jpayne@69: * ``month()`` returns the month of the object as an integer: jpayne@69: jpayne@69: >>> dt.month() jpayne@69: 3 jpayne@69: jpayne@69: * ``Month()`` returns the full month name: jpayne@69: jpayne@69: >>> dt.Month() jpayne@69: 'March' jpayne@69: jpayne@69: * ``aMonth()`` returns the abbreviated month name: jpayne@69: jpayne@69: >>> dt.aMonth() jpayne@69: 'Mar' jpayne@69: jpayne@69: * ``pMonth()`` returns the abbreviated (with period) month name: jpayne@69: jpayne@69: >>> dt.pMonth() jpayne@69: 'Mar.' jpayne@69: jpayne@69: * ``day()`` returns the integer day: jpayne@69: jpayne@69: >>> dt.day() jpayne@69: 9 jpayne@69: jpayne@69: * ``Day()`` returns the full name of the day of the week: jpayne@69: jpayne@69: >>> dt.Day() jpayne@69: 'Sunday' jpayne@69: jpayne@69: * ``dayOfYear()`` returns the day of the year, in context of the jpayne@69: timezone representation of the object: jpayne@69: jpayne@69: >>> dt.dayOfYear() jpayne@69: 68 jpayne@69: jpayne@69: * ``aDay()`` returns the abbreviated name of the day of the week: jpayne@69: jpayne@69: >>> dt.aDay() jpayne@69: 'Sun' jpayne@69: jpayne@69: * ``pDay()`` returns the abbreviated (with period) name of the day of jpayne@69: the week: jpayne@69: jpayne@69: >>> dt.pDay() jpayne@69: 'Sun.' jpayne@69: jpayne@69: * ``dow()`` returns the integer day of the week, where Sunday is 0: jpayne@69: jpayne@69: >>> dt.dow() jpayne@69: 0 jpayne@69: jpayne@69: * ``dow_1()`` returns the integer day of the week, where sunday is 1: jpayne@69: jpayne@69: >>> dt.dow_1() jpayne@69: 1 jpayne@69: jpayne@69: * ``h_12()`` returns the 12-hour clock representation of the hour: jpayne@69: jpayne@69: >>> dt.h_12() jpayne@69: 1 jpayne@69: jpayne@69: * ``h_24()`` returns the 24-hour clock representation of the hour: jpayne@69: jpayne@69: >>> dt.h_24() jpayne@69: 13 jpayne@69: jpayne@69: * ``ampm()`` returns the appropriate time modifier (am or pm): jpayne@69: jpayne@69: >>> dt.ampm() jpayne@69: 'pm' jpayne@69: jpayne@69: * ``hour()`` returns the 24-hour clock representation of the hour: jpayne@69: jpayne@69: >>> dt.hour() jpayne@69: 13 jpayne@69: jpayne@69: * ``minute()`` returns the minute: jpayne@69: jpayne@69: >>> dt.minute() jpayne@69: 45 jpayne@69: jpayne@69: * ``second()`` returns the second: jpayne@69: jpayne@69: >>> dt.second() == 0 jpayne@69: True jpayne@69: jpayne@69: * ``millis()`` returns the milliseconds since the epoch in GMT. jpayne@69: jpayne@69: >>> dt.millis() == 857933100000 jpayne@69: True jpayne@69: jpayne@69: strftime() jpayne@69: ~~~~~~~~~~ jpayne@69: jpayne@69: See ``tests/test_datetime.py``. jpayne@69: jpayne@69: General formats from previous DateTime jpayne@69: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ jpayne@69: jpayne@69: * ``Date()`` return the date string for the object: jpayne@69: jpayne@69: >>> dt.Date() jpayne@69: '1997/03/09' jpayne@69: jpayne@69: * ``Time()`` returns the time string for an object to the nearest jpayne@69: second: jpayne@69: jpayne@69: >>> dt.Time() jpayne@69: '13:45:00' jpayne@69: jpayne@69: * ``TimeMinutes()`` returns the time string for an object not showing jpayne@69: seconds: jpayne@69: jpayne@69: >>> dt.TimeMinutes() jpayne@69: '13:45' jpayne@69: jpayne@69: * ``AMPM()`` returns the time string for an object to the nearest second: jpayne@69: jpayne@69: >>> dt.AMPM() jpayne@69: '01:45:00 pm' jpayne@69: jpayne@69: * ``AMPMMinutes()`` returns the time string for an object not showing jpayne@69: seconds: jpayne@69: jpayne@69: >>> dt.AMPMMinutes() jpayne@69: '01:45 pm' jpayne@69: jpayne@69: * ``PreciseTime()`` returns the time string for the object: jpayne@69: jpayne@69: >>> dt.PreciseTime() jpayne@69: '13:45:00.000' jpayne@69: jpayne@69: * ``PreciseAMPM()`` returns the time string for the object: jpayne@69: jpayne@69: >>> dt.PreciseAMPM() jpayne@69: '01:45:00.000 pm' jpayne@69: jpayne@69: * ``yy()`` returns the calendar year as a 2 digit string jpayne@69: jpayne@69: >>> dt.yy() jpayne@69: '97' jpayne@69: jpayne@69: * ``mm()`` returns the month as a 2 digit string jpayne@69: jpayne@69: >>> dt.mm() jpayne@69: '03' jpayne@69: jpayne@69: * ``dd()`` returns the day as a 2 digit string: jpayne@69: jpayne@69: >>> dt.dd() jpayne@69: '09' jpayne@69: jpayne@69: * ``rfc822()`` returns the date in RFC 822 format: jpayne@69: jpayne@69: >>> dt.rfc822() jpayne@69: 'Sun, 09 Mar 1997 13:45:00 -0500' jpayne@69: jpayne@69: New formats jpayne@69: ~~~~~~~~~~~ jpayne@69: jpayne@69: * ``fCommon()`` returns a string representing the object's value in jpayne@69: the format: March 9, 1997 1:45 pm: jpayne@69: jpayne@69: >>> dt.fCommon() jpayne@69: 'March 9, 1997 1:45 pm' jpayne@69: jpayne@69: * ``fCommonZ()`` returns a string representing the object's value in jpayne@69: the format: March 9, 1997 1:45 pm US/Eastern: jpayne@69: jpayne@69: >>> dt.fCommonZ() jpayne@69: 'March 9, 1997 1:45 pm US/Eastern' jpayne@69: jpayne@69: * ``aCommon()`` returns a string representing the object's value in jpayne@69: the format: Mar 9, 1997 1:45 pm: jpayne@69: jpayne@69: >>> dt.aCommon() jpayne@69: 'Mar 9, 1997 1:45 pm' jpayne@69: jpayne@69: * ``aCommonZ()`` return a string representing the object's value in jpayne@69: the format: Mar 9, 1997 1:45 pm US/Eastern: jpayne@69: jpayne@69: >>> dt.aCommonZ() jpayne@69: 'Mar 9, 1997 1:45 pm US/Eastern' jpayne@69: jpayne@69: * ``pCommon()`` returns a string representing the object's value in jpayne@69: the format Mar. 9, 1997 1:45 pm: jpayne@69: jpayne@69: >>> dt.pCommon() jpayne@69: 'Mar. 9, 1997 1:45 pm' jpayne@69: jpayne@69: * ``pCommonZ()`` returns a string representing the object's value in jpayne@69: the format: Mar. 9, 1997 1:45 pm US/Eastern: jpayne@69: jpayne@69: >>> dt.pCommonZ() jpayne@69: 'Mar. 9, 1997 1:45 pm US/Eastern' jpayne@69: jpayne@69: * ``ISO()`` returns a string with the date/time in ISO format. Note: jpayne@69: this is not ISO 8601-format! See the ISO8601 and HTML4 methods below jpayne@69: for ISO 8601-compliant output. Dates are output as: YYYY-MM-DD HH:MM:SS jpayne@69: jpayne@69: >>> dt.ISO() jpayne@69: '1997-03-09 13:45:00' jpayne@69: jpayne@69: * ``ISO8601()`` returns the object in ISO 8601-compatible format jpayne@69: containing the date, time with seconds-precision and the time zone jpayne@69: identifier - see http://www.w3.org/TR/NOTE-datetime. Dates are jpayne@69: output as: YYYY-MM-DDTHH:MM:SSTZD (T is a literal character, TZD is jpayne@69: Time Zone Designator, format +HH:MM or -HH:MM). jpayne@69: jpayne@69: The ``HTML4()`` method below offers the same formatting, but jpayne@69: converts to UTC before returning the value and sets the TZD"Z" jpayne@69: jpayne@69: >>> dt.ISO8601() jpayne@69: '1997-03-09T13:45:00-05:00' jpayne@69: jpayne@69: jpayne@69: * ``HTML4()`` returns the object in the format used in the HTML4.0 jpayne@69: specification, one of the standard forms in ISO8601. See jpayne@69: http://www.w3.org/TR/NOTE-datetime. Dates are output as: jpayne@69: YYYY-MM-DDTHH:MM:SSZ (T, Z are literal characters, the time is in jpayne@69: UTC.): jpayne@69: jpayne@69: >>> dt.HTML4() jpayne@69: '1997-03-09T18:45:00Z' jpayne@69: jpayne@69: * ``JulianDay()`` returns the Julian day according to jpayne@69: http://www.tondering.dk/claus/cal/node3.html#sec-calcjd jpayne@69: jpayne@69: >>> dt.JulianDay() jpayne@69: 2450517 jpayne@69: jpayne@69: * ``week()`` returns the week number according to ISO jpayne@69: see http://www.tondering.dk/claus/cal/node6.html#SECTION00670000000000000000 jpayne@69: jpayne@69: >>> dt.week() jpayne@69: 10 jpayne@69: jpayne@69: Deprecated API jpayne@69: ~~~~~~~~~~~~~~ jpayne@69: jpayne@69: * DayOfWeek(): see Day() jpayne@69: jpayne@69: * Day_(): see pDay() jpayne@69: jpayne@69: * Mon(): see aMonth() jpayne@69: jpayne@69: * Mon_(): see pMonth jpayne@69: jpayne@69: General Services Provided by DateTime jpayne@69: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ jpayne@69: jpayne@69: DateTimes can be repr()'ed; the result will be a string indicating how jpayne@69: to make a DateTime object like this: jpayne@69: jpayne@69: >>> repr(dt) jpayne@69: "DateTime('1997/03/09 13:45:00 US/Eastern')" jpayne@69: jpayne@69: When we convert them into a string, we get a nicer string that could jpayne@69: actually be shown to a user: jpayne@69: jpayne@69: >>> str(dt) jpayne@69: '1997/03/09 13:45:00 US/Eastern' jpayne@69: jpayne@69: The hash value of a DateTime is based on the date and time and is jpayne@69: equal for different representations of the DateTime: jpayne@69: jpayne@69: >>> hash(dt) jpayne@69: 3618678 jpayne@69: >>> hash(dt.toZone('UTC')) jpayne@69: 3618678 jpayne@69: jpayne@69: DateTime objects can be compared to other DateTime objects OR floating jpayne@69: point numbers such as the ones which are returned by the Python time jpayne@69: module by using the equalTo method. Using this API, True is returned if the jpayne@69: object represents a date/time equal to the specified DateTime or time module jpayne@69: style time: jpayne@69: jpayne@69: >>> dt.equalTo(dt) jpayne@69: True jpayne@69: >>> dt.equalTo(dt.toZone('UTC')) jpayne@69: True jpayne@69: >>> dt.equalTo(dt.timeTime()) jpayne@69: True jpayne@69: >>> dt.equalTo(DateTime()) jpayne@69: False jpayne@69: jpayne@69: Same goes for inequalities: jpayne@69: jpayne@69: >>> dt.notEqualTo(dt) jpayne@69: False jpayne@69: >>> dt.notEqualTo(dt.toZone('UTC')) jpayne@69: False jpayne@69: >>> dt.notEqualTo(dt.timeTime()) jpayne@69: False jpayne@69: >>> dt.notEqualTo(DateTime()) jpayne@69: True jpayne@69: jpayne@69: Normal equality operations only work with DateTime objects and take the jpayne@69: timezone setting into account: jpayne@69: jpayne@69: >>> dt == dt jpayne@69: True jpayne@69: >>> dt == dt.toZone('UTC') jpayne@69: False jpayne@69: >>> dt == DateTime() jpayne@69: False jpayne@69: jpayne@69: >>> dt != dt jpayne@69: False jpayne@69: >>> dt != dt.toZone('UTC') jpayne@69: True jpayne@69: >>> dt != DateTime() jpayne@69: True jpayne@69: jpayne@69: But the other comparison operations compare the referenced moment in time and jpayne@69: not the representation itself: jpayne@69: jpayne@69: >>> dt > dt jpayne@69: False jpayne@69: >>> DateTime() > dt jpayne@69: True jpayne@69: >>> dt > DateTime().timeTime() jpayne@69: False jpayne@69: >>> DateTime().timeTime() > dt jpayne@69: True jpayne@69: jpayne@69: >>> dt.greaterThan(dt) jpayne@69: False jpayne@69: >>> DateTime().greaterThan(dt) jpayne@69: True jpayne@69: >>> dt.greaterThan(DateTime().timeTime()) jpayne@69: False jpayne@69: jpayne@69: >>> dt >= dt jpayne@69: True jpayne@69: >>> DateTime() >= dt jpayne@69: True jpayne@69: >>> dt >= DateTime().timeTime() jpayne@69: False jpayne@69: >>> DateTime().timeTime() >= dt jpayne@69: True jpayne@69: jpayne@69: >>> dt.greaterThanEqualTo(dt) jpayne@69: True jpayne@69: >>> DateTime().greaterThanEqualTo(dt) jpayne@69: True jpayne@69: >>> dt.greaterThanEqualTo(DateTime().timeTime()) jpayne@69: False jpayne@69: jpayne@69: >>> dt < dt jpayne@69: False jpayne@69: >>> DateTime() < dt jpayne@69: False jpayne@69: >>> dt < DateTime().timeTime() jpayne@69: True jpayne@69: >>> DateTime().timeTime() < dt jpayne@69: False jpayne@69: jpayne@69: >>> dt.lessThan(dt) jpayne@69: False jpayne@69: >>> DateTime().lessThan(dt) jpayne@69: False jpayne@69: >>> dt.lessThan(DateTime().timeTime()) jpayne@69: True jpayne@69: jpayne@69: >>> dt <= dt jpayne@69: True jpayne@69: >>> DateTime() <= dt jpayne@69: False jpayne@69: >>> dt <= DateTime().timeTime() jpayne@69: True jpayne@69: >>> DateTime().timeTime() <= dt jpayne@69: False jpayne@69: jpayne@69: >>> dt.lessThanEqualTo(dt) jpayne@69: True jpayne@69: >>> DateTime().lessThanEqualTo(dt) jpayne@69: False jpayne@69: >>> dt.lessThanEqualTo(DateTime().timeTime()) jpayne@69: True jpayne@69: jpayne@69: Numeric Services Provided by DateTime jpayne@69: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ jpayne@69: jpayne@69: A DateTime may be added to a number and a number may be added to a jpayne@69: DateTime: jpayne@69: jpayne@69: >>> dt + 5 jpayne@69: DateTime('1997/03/14 13:45:00 US/Eastern') jpayne@69: >>> 5 + dt jpayne@69: DateTime('1997/03/14 13:45:00 US/Eastern') jpayne@69: jpayne@69: Two DateTimes cannot be added: jpayne@69: jpayne@69: >>> from DateTime.interfaces import DateTimeError jpayne@69: >>> try: jpayne@69: ... dt + dt jpayne@69: ... print('fail') jpayne@69: ... except DateTimeError: jpayne@69: ... print('ok') jpayne@69: ok jpayne@69: jpayne@69: Either a DateTime or a number may be subtracted from a DateTime, jpayne@69: however, a DateTime may not be subtracted from a number: jpayne@69: jpayne@69: >>> DateTime('1997/03/10 13:45 US/Eastern') - dt jpayne@69: 1.0 jpayne@69: >>> dt - 1 jpayne@69: DateTime('1997/03/08 13:45:00 US/Eastern') jpayne@69: >>> 1 - dt jpayne@69: Traceback (most recent call last): jpayne@69: ... jpayne@69: TypeError: unsupported operand type(s) for -: 'int' and 'DateTime' jpayne@69: jpayne@69: DateTimes can also be converted to integers (number of seconds since jpayne@69: the epoch) and floats: jpayne@69: jpayne@69: >>> int(dt) jpayne@69: 857933100 jpayne@69: >>> float(dt) jpayne@69: 857933100.0 jpayne@69: jpayne@69: jpayne@69: Changelog jpayne@69: ========= jpayne@69: jpayne@69: 5.5 (2024-03-21) jpayne@69: ---------------- jpayne@69: jpayne@69: - Change pickle format to export the microseconds as an int, to jpayne@69: solve a problem with dates after 2038. jpayne@69: (`#56 `_) jpayne@69: jpayne@69: jpayne@69: 5.4 (2023-12-15) jpayne@69: ---------------- jpayne@69: jpayne@69: - Fix ``UnknownTimeZoneError`` when unpickling ``DateTime.DateTime().asdatetime()``. jpayne@69: (`#58 `_) jpayne@69: jpayne@69: - Repair equality comparison between DateTime instances and other types. jpayne@69: (`#60 `_) jpayne@69: jpayne@69: jpayne@69: 5.3 (2023-11-14) jpayne@69: ---------------- jpayne@69: jpayne@69: - Add support for Python 3.12. jpayne@69: jpayne@69: - Add preliminary support for Python 3.13a2. jpayne@69: jpayne@69: jpayne@69: 5.2 (2023-07-19) jpayne@69: ---------------- jpayne@69: jpayne@69: - Cast int to float in compare methods. jpayne@69: - Fix compare methods between DateTime instances and None. jpayne@69: (`#52 `_) jpayne@69: jpayne@69: jpayne@69: 5.1 (2023-03-14) jpayne@69: ---------------- jpayne@69: jpayne@69: - Add missing ``python_requires`` to ``setup.py``. jpayne@69: jpayne@69: jpayne@69: 5.0 (2023-01-12) jpayne@69: ---------------- jpayne@69: jpayne@69: - Drop support for Python 2.7, 3.5, 3.6. jpayne@69: jpayne@69: jpayne@69: 4.8 (2022-12-16) jpayne@69: ---------------- jpayne@69: jpayne@69: - Fix insidious buildout configuration bug that prevented tests on Python 2.7 jpayne@69: and 3.5, and fix test code that was incompatible with Python 3.5. jpayne@69: (`#44 `_) jpayne@69: jpayne@69: - Add support for Python 3.11. jpayne@69: jpayne@69: jpayne@69: 4.7 (2022-09-14) jpayne@69: ---------------- jpayne@69: jpayne@69: - Fix rounding problem with `DateTime` addition beyond the year 2038 jpayne@69: (`#41 `_) jpayne@69: jpayne@69: jpayne@69: 4.6 (2022-09-10) jpayne@69: ---------------- jpayne@69: jpayne@69: - Fix ``__format__`` method for DateTime objects jpayne@69: (`#39 `_) jpayne@69: jpayne@69: jpayne@69: 4.5 (2022-07-04) jpayne@69: ---------------- jpayne@69: jpayne@69: - Add ``__format__`` method for DateTime objects jpayne@69: (`#35 `_) jpayne@69: jpayne@69: jpayne@69: 4.4 (2022-02-11) jpayne@69: ---------------- jpayne@69: jpayne@69: - Fix WAT definition jpayne@69: `#31 `_. jpayne@69: jpayne@69: - Add support for Python 3.8, 3.9, and 3.10. jpayne@69: jpayne@69: - Drop support for Python 3.4. jpayne@69: jpayne@69: 4.3 (2018-10-05) jpayne@69: ---------------- jpayne@69: jpayne@69: - Add support for Python 3.7. jpayne@69: jpayne@69: 4.2 (2017-04-26) jpayne@69: ---------------- jpayne@69: jpayne@69: - Add support for Python 3.6, drop support for Python 3.3. jpayne@69: jpayne@69: 4.1.1 (2016-04-30) jpayne@69: ------------------ jpayne@69: jpayne@69: - Support unpickling instances having a numeric timezone like `+0430`. jpayne@69: jpayne@69: 4.1 (2016-04-03) jpayne@69: ---------------- jpayne@69: jpayne@69: - Add support for Python 3.4 and 3.5. jpayne@69: jpayne@69: - Drop support for Python 2.6 and 3.2. jpayne@69: jpayne@69: 4.0.1 (2013-10-15) jpayne@69: ------------------ jpayne@69: jpayne@69: - Provide more backward compatible timezones. jpayne@69: [vangheem] jpayne@69: jpayne@69: 4.0 (2013-02-23) jpayne@69: ---------------- jpayne@69: jpayne@69: - Added support for Python 3.2 and 3.3 in addition to 2.6 and 2.7. jpayne@69: jpayne@69: - Removed unused legacy pytz tests and the DateTimeZone module and renamed jpayne@69: some test internals. jpayne@69: jpayne@69: 3.0.3 (2013-01-22) jpayne@69: ------------------ jpayne@69: jpayne@69: - Allow timezone argument to be a Unicode string while creating a DateTime jpayne@69: object using two arguments. jpayne@69: jpayne@69: 3.0.2 (2012-10-21) jpayne@69: ------------------ jpayne@69: jpayne@69: - LP #1045233: Respect date format setting for parsing dates like `11-01-2001`. jpayne@69: jpayne@69: 3.0.1 (2012-09-23) jpayne@69: ------------------ jpayne@69: jpayne@69: - Add `_dt_reconstructor` function introduced in DateTime 2.12.7 to provide jpayne@69: forward compatibility with pickles that might reference this function. jpayne@69: jpayne@69: 3.0 (2011-12-09) jpayne@69: ---------------- jpayne@69: jpayne@69: - No changes. jpayne@69: jpayne@69: Backwards compatibility of DateTime 3 jpayne@69: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ jpayne@69: jpayne@69: DateTime 3 changes its pickle representation. DateTime instances pickled with jpayne@69: former versions of DateTime can be read, but older DateTime versions cannot read jpayne@69: DateTime instances pickled with version 3. jpayne@69: jpayne@69: DateTime 3 changes DateTime to be a new-style class with slots instead of being jpayne@69: an old-style class. jpayne@69: jpayne@69: DateTime 3 tries to preserve microsecond resolution throughout most of its API's jpayne@69: while former versions were often only accurate to millisecond resolution. Due to jpayne@69: the representation of float values in Python versions before Python 2.7 you jpayne@69: shouldn't compare string or float representations of DateTime instances if you jpayne@69: want high accuracy. The same is true for calculated values returned by methods jpayne@69: like `timeTime()`. You get the highest accuracy of comparing DateTime values by jpayne@69: calling its `micros()` methods. DateTime is not particular well suited to be jpayne@69: used in comparing timestamps of file systems - use the time and datetime objects jpayne@69: from the Python standard library instead. jpayne@69: jpayne@69: 3.0b3 (2011-10-19) jpayne@69: ------------------ jpayne@69: jpayne@69: - Allow comparison of DateTime objects against None. jpayne@69: jpayne@69: 3.0b2 (2011-10-19) jpayne@69: ------------------ jpayne@69: jpayne@69: - Reverted the single argument `None` special case handling for unpickling and jpayne@69: continue to treat it as meaning `now`. jpayne@69: jpayne@69: 3.0b1 (2011-05-07) jpayne@69: ------------------ jpayne@69: jpayne@69: - Restored `strftimeFormatter` as a class. jpayne@69: jpayne@69: - Added tests for read-only class attributes and interface. jpayne@69: jpayne@69: 3.0a2 (2011-05-07) jpayne@69: ------------------ jpayne@69: jpayne@69: - Added back support for reading old DateTime pickles without a `_micros` value. jpayne@69: jpayne@69: - Avoid storing `_t` representing the time as a float in seconds since the jpayne@69: epoch, as we already have `_micros` doing the same as a long. Memory use is jpayne@69: down to about 300 bytes per DateTime instance. jpayne@69: jpayne@69: - Updated exception raising syntax to current style. jpayne@69: jpayne@69: - Avoid storing `_aday`, `_fday`, `_pday`, `_amon`, `_fmon`, `_pmon`, `_pmhour` jpayne@69: and `_pm` in memory for every instance but look them up dynamically based on jpayne@69: `_dayoffset`, `_month` and `_hour`. This saves another 150 bytes of memory jpayne@69: per DateTime instance. jpayne@69: jpayne@69: - Moved various internal parsing related class variables to module constants. jpayne@69: jpayne@69: - No longer provide the `DateError`, `DateTimeError`, `SyntaxError` and jpayne@69: `TimeError` exceptions as class attributes, import them from their canonical jpayne@69: `DateTime.interfaces` location instead. jpayne@69: jpayne@69: - Removed deprecated `_isDST` and `_localzone` class variables. jpayne@69: jpayne@69: - Moved pytz cache from `DateTime._tzinfo` to a module global `_TZINFO`. jpayne@69: jpayne@69: - Make DateTime a new-style class and limit its available attributes via a jpayne@69: slots definition. The pickle size increases to 110 bytes thanks to the jpayne@69: `ccopy_reg\n_reconstructor` stanza. But the memory size drops from 3kb to jpayne@69: 500 bytes for each instance. jpayne@69: jpayne@69: 3.0a1 (2011-05-06) jpayne@69: ------------------ jpayne@69: jpayne@69: - Reordered some calculations in `_calcIndependentSecondEtc` to preserve more jpayne@69: floating point precision. jpayne@69: jpayne@69: - Optimized the pickled data, by only storing a tuple of `_micros` and time jpayne@69: zone information - this reduces the pickle size from an average of 300 bytes jpayne@69: to just 60 bytes. jpayne@69: jpayne@69: - Optimized un-pickling, by avoiding the creation of an intermediate DateTime jpayne@69: value representing the current time. jpayne@69: jpayne@69: - Removed in-place migration of old DateTime pickles without a `_micros` value. jpayne@69: jpayne@69: - Removed deprecated support for using `DateTime.__cmp__`. jpayne@69: jpayne@69: - Take time zone settings into account when comparing two date times for jpayne@69: (non-) equality. jpayne@69: jpayne@69: - Fixed (possibly unused) _parse_iso8601 function. jpayne@69: jpayne@69: - Removed unused import of legacy DateTimeZone, strftime and re. jpayne@69: Remove trailing whitespace. jpayne@69: jpayne@69: - Removed reference to missing version section from buildout. jpayne@69: jpayne@69: 2.12.7 (2012-08-11) jpayne@69: ------------------- jpayne@69: jpayne@69: - Added forward compatibility with DateTime 3 pickle format. DateTime jpayne@69: instances constructed under version 3 can be read and unpickled by this jpayne@69: version. The pickled data is converted to the current versions format jpayne@69: (old-style class / no slots). Once converted it will be stored again in the jpayne@69: old format. This should allow for a transparent upgrade/downgrade path jpayne@69: between DateTime 2 and 3. jpayne@69: jpayne@69: 2.12.6 (2010-10-17) jpayne@69: ------------------- jpayne@69: jpayne@69: - Changed ``testDayOfWeek`` test to be independent of OS locale. jpayne@69: jpayne@69: 2.12.5 (2010-07-29) jpayne@69: ------------------- jpayne@69: jpayne@69: - Launchpad #143269: Corrected the documentation for year value jpayne@69: behavior when constructing a DateTime object with three numeric jpayne@69: arguments. jpayne@69: jpayne@69: - Launchpad #142521: Removed confusing special case in jpayne@69: DateTime.__str__ where DateTime instances for midnight jpayne@69: (e.g. '2010-07-27 00:00:00 US/Eastern') values would jpayne@69: render only their date and nothing else. jpayne@69: jpayne@69: 2.12.4 (2010-07-12) jpayne@69: ------------------- jpayne@69: jpayne@69: - Fixed mapping of EDT (was -> 'GMT-0400', now 'GMT-4'). jpayne@69: jpayne@69: 2.12.3 (2010-07-09) jpayne@69: ------------------- jpayne@69: jpayne@69: - Added EDT timezone support. Addresses bug #599856. jpayne@69: [vangheem] jpayne@69: jpayne@69: 2.12.2 (2010-05-05) jpayne@69: ------------------- jpayne@69: jpayne@69: - Launchpad #572715: Relaxed pin on pytz, after applying a patch from jpayne@69: Marius Gedminus which fixes the apparent API breakage. jpayne@69: jpayne@69: 2.12.1 (2010-04-30) jpayne@69: ------------------- jpayne@69: jpayne@69: - Removed an undeclared testing dependency on zope.testing.doctest in favor of jpayne@69: the standard libraries doctest module. jpayne@69: jpayne@69: - Added a maximum version requirement on pytz <= 2010b. Later versions produce jpayne@69: test failures related to timezone changes. jpayne@69: jpayne@69: 2.12.0 (2009-03-04) jpayne@69: ------------------- jpayne@69: jpayne@69: - Launchpad #290254: Forward-ported fix for '_micros'-less pickles from jpayne@69: the Zope 2.11 branch version. jpayne@69: jpayne@69: 2.11.2 (2009-02-02) jpayne@69: ------------------- jpayne@69: jpayne@69: - Include *all* pytz zone names, not just "common" ones. jpayne@69: jpayne@69: - Fix one fragile doctest, band-aid another. jpayne@69: jpayne@69: - Fix for launchpad #267545: DateTime(DateTime()) should preserve the jpayne@69: correct hour. jpayne@69: jpayne@69: 2.11.1 (2008-08-05) jpayne@69: ------------------- jpayne@69: jpayne@69: - DateTime conversion of datetime objects with non-pytz tzinfo. Timezones() jpayne@69: returns a copy of the timezone list (allows tests to run). jpayne@69: jpayne@69: - Merged the slinkp-datetime-200007 branch: fix the DateTime(anotherDateTime) jpayne@69: constructor to preserve timezones. jpayne@69: jpayne@69: 2.11.0b1 (2008-01-06) jpayne@69: --------------------- jpayne@69: jpayne@69: - Split off from the Zope2 main source code tree.