Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

mktime, how to handle dates before 01-01-1970 ?

1,539 views
Skip to first unread message

Stef Mientki

unread,
Oct 5, 2009, 7:54:18 PM10/5/09
to pytho...@python.org
hello,

I want to handle datetime vars in a general way, so I use the default
time-format,
so I can use the standard cinversion procedures.
Time format is the time difference since 1-1-1970.

So how do I handle dates before 1-1-1970 ?

I'ld expect times before 1-1-1970, simply to become negative numbers
(I'm interested in the age of living people, so that would suffice).

Is there a general solution, (other library)
or would it be better to handle all dates in the Delphi format (number
of days since 1-1-1900

thanks,
Stef Mientki

Gabriel Genellina

unread,
Oct 5, 2009, 8:35:21 PM10/5/09
to pytho...@python.org
En Mon, 05 Oct 2009 20:54:18 -0300, Stef Mientki <stef.m...@gmail.com>
escribi�:

> I want to handle datetime vars in a general way, so I use the default
> time-format,
> so I can use the standard cinversion procedures.
> Time format is the time difference since 1-1-1970.
>
> So how do I handle dates before 1-1-1970 ?

Use the datetime module and manage the dates as actual datetime objects,
not as formatted strings.

py> import datetime
py> birthdate = datetime.datetime(1914, 7, 23)
py> birthdate
datetime.datetime(1914, 7, 23, 0, 0)
py> now = datetime.datetime.now()
py> now - birthdate
datetime.timedelta(34773, 77146, 765000)
py> _.days // 365
95


py> datetime.datetime(1931, 8, 23)
datetime.datetime(1931, 8, 23, 0, 0)
py> datetime.datetime(1851, 6, 12)
datetime.datetime(1851, 6, 12, 0, 0)
py> datetime.datetime(1492, 10, 12)
datetime.datetime(1492, 10, 12, 0, 0)
py> a = datetime.datetime(1492, 10, 12)
py> b = datetime.datetime(2009, 10, 5)
py> (b - a) // 365
datetime.timedelta(517, 27932, 54794)
py> b = datetime.datetime.now()
py> _.days
34773
py> _.days // 365
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute 'days'
py> now - birthdate
datetime.timedelta(34773, 77146, 765000)

> I'ld expect times before 1-1-1970, simply to become negative numbers
> (I'm interested in the age of living people, so that would suffice).
>
> Is there a general solution, (other library)
> or would it be better to handle all dates in the Delphi format (number
> of days since 1-1-1900

py> birthdate.toordinal()
698912

(number of days since 1 AD, approximately)

--
Gabriel Genellina

Ben Finney

unread,
Oct 5, 2009, 9:06:53 PM10/5/09
to
Stef Mientki <stef.m...@gmail.com> writes:

> I'ld expect times before 1-1-1970, simply to become negative numbers
> (I'm interested in the age of living people, so that would suffice).
>
> Is there a general solution, (other library) or would it be better to
> handle all dates in the Delphi format (number of days since 1-1-1900

There are many epochs that have been used in computing
<URL:http://en.wikipedia.org/wiki/Epoch_(reference_date)#Notable_epoch_dates_in_computing>,
all of which have their problems. Switching from the Unix epoch to some
other involves data conversion, and (as you point out) raises concerns
about library support.

If you're committed to changing the epoch anyway, I would recommend
using <URL:http://en.wikipedia.org/wiki/Astronomical_year_numbering>
(epoch at 4004 BCE) since it is widely used to unify dates referring to
human history.

--
\ “The surest way to corrupt a youth is to instruct him to hold |
`\ in higher esteem those who think alike than those who think |
_o__) differently.” —Friedrich Nietzsche |
Ben Finney

Ben Finney

unread,
Oct 5, 2009, 9:12:45 PM10/5/09
to
Ben Finney <ben+p...@benfinney.id.au> writes:

> There are many epochs that have been used in computing
> <URL:http://en.wikipedia.org/wiki/Epoch_(reference_date)#Notable_epoch_dates_in_computing>,
> all of which have their problems. Switching from the Unix epoch to some
> other involves data conversion, and (as you point out) raises concerns
> about library support.

Hmm, none of this addressed your question about what *data type* to use.
For that, the answer is: use the standard-library ‘datetime’ module's
types (‘date’, ‘timestamp’, etc.) in your code for representing the
actual values.

The advice for date and time values is similar to the advice for text
values: convert input to ‘datetime’ types as soon as possible, and
render output as late as possible; do all processing on the ‘datetime’
types to ensure preservation of information.

--
\ “I filled my humidifier with wax. Now my room is all shiny.” |
`\ —Steven Wright |
_o__) |
Ben Finney

Stef Mientki

unread,
Oct 6, 2009, 4:10:57 PM10/6/09
to pytho...@python.org
Stephen Hansen wrote:
> On Mon, Oct 5, 2009 at 4:54 PM, Stef Mientki <stef.m...@gmail.com
> <mailto:stef.m...@gmail.com>> wrote:
>
> hello,

>
> I want to handle datetime vars in a general way, so I use the
> default time-format,
> so I can use the standard cinversion procedures.
>
>
> Personally, I love mx.DateTime; its the best date/time library around.
> But, Python's built in datetime isn't too bad and is similar and
> built-in if you don't want to use a third-party library.
thanks guys,
mx works a bit better ....
>
> But:
>
> >>> birthday = mx.DateTime.Date(1960,3,3)
> >>> birthday
> <mx.DateTime.DateTime object for '1960-03-03 00:00:00.00' at 6211e0>
> >>> age = mx.DateTime.now() - birthday
> >>> print "Age in days", age.days
> 18113.722499758693
> >>> print "Age in years", age.days / 365
> 49.626636985640253
>
> I really can't quite fathom why you'd want to use something so
> low-level as time.mktime... or just about anything in the time module :)
I didn't know anything better,
but (forgive me if I'm wrong) I find mx almost as low-level :
>>> mx.DateTime.strptime('01-01-53',"%d-%m-%y")
<mx.DateTime.DateTime object for '2053-01-01 00:00:00.00' at 1cddc60>
while all we human know ..

I agree it's better not to work with string dates, but that's the way
how we human write things down ;-)
So I must use at least something like strptime.

cheers,
Stef

> If you want to handle dates in a general way, I'd use one of the
> general-purpose date/time handling libraries. They're far more capable
> and easier to use.
>
> HTH,
>
> --S
>
>

Christian Heimes

unread,
Oct 6, 2009, 5:11:44 PM10/6/09
to pytho...@python.org
Ben Finney wrote:
> If you're committed to changing the epoch anyway, I would recommend
> using <URL:http://en.wikipedia.org/wiki/Astronomical_year_numbering>
> (epoch at 4004 BCE) since it is widely used to unify dates referring to
> human history.

I prefer JDN or MJD (http://en.wikipedia.org/wiki/JDN) for dates long
before or after the unix epoch. The conversion from JDN as float to a
datetime object is trivial.

Christian

M.-A. Lemburg

unread,
Oct 7, 2009, 8:13:08 AM10/7/09
to pytho...@python.org
Christian Heimes wrote:

> Ben Finney wrote:
>> If you're committed to changing the epoch anyway, I would recommend
>> using <URL:http://en.wikipedia.org/wiki/Astronomical_year_numbering>
>> (epoch at 4004 BCE) since it is widely used to unify dates referring to
>> human history.
>
> I prefer JDN or MJD (http://en.wikipedia.org/wiki/JDN) for dates long
> before or after the unix epoch. The conversion from JDN as float to a
> datetime object is trivial.

FWIW, mxDateTime can help you with all of those:

>>> import mx.DateTime
>>> mx.DateTime.DateTimeFrom('1.1.4004 BCE')
<mx.DateTime.DateTime object for '-4003-01-01 00:00:00.00' at 2b534a46a2f0>
>>> mx.DateTime.DateTimeFrom('1.1.4004 BCE').jdn
258994.5
>>> mx.DateTime.DateTimeFromJDN(258994.5)
<mx.DateTime.DateTime object for '-4003-01-01 00:00:00.00' at 2b534aeb72f0>
>>> mx.DateTime.DateTimeFrom('1.1.4004 BCE').mjd
-2141006.0
>>> mx.DateTime.DateTimeFromMJD(-2141006.0)
<mx.DateTime.DateTime object for '-4003-01-01 00:00:00.00' at 2b534a46a2f0>

The supported date range is limited by the number of days
that fit into a C long. Should be enough for most use cases :-)

--
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source (#1, Oct 07 2009)
>>> Python/Zope Consulting and Support ... http://www.egenix.com/
>>> mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/
>>> mxODBC, mxDateTime, mxTextTools ... http://python.egenix.com/
________________________________________________________________________

::: Try our new mxODBC.Connect Python Database Interface for free ! ::::


eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48
D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
Registered at Amtsgericht Duesseldorf: HRB 46611
http://www.egenix.com/company/contact/

Christian Heimes

unread,
Oct 7, 2009, 9:02:51 AM10/7/09
to pytho...@python.org
M.-A. Lemburg schrieb:

> Christian Heimes wrote:
>> Ben Finney wrote:
>>> If you're committed to changing the epoch anyway, I would recommend
>>> using <URL:http://en.wikipedia.org/wiki/Astronomical_year_numbering>
>>> (epoch at 4004 BCE) since it is widely used to unify dates referring to
>>> human history.
>> I prefer JDN or MJD (http://en.wikipedia.org/wiki/JDN) for dates long
>> before or after the unix epoch. The conversion from JDN as float to a
>> datetime object is trivial.
>
> FWIW, mxDateTime can help you with all of those:
>
>>>> import mx.DateTime
>>>> mx.DateTime.DateTimeFrom('1.1.4004 BCE')
> <mx.DateTime.DateTime object for '-4003-01-01 00:00:00.00' at 2b534a46a2f0>
>>>> mx.DateTime.DateTimeFrom('1.1.4004 BCE').jdn
> 258994.5
>>>> mx.DateTime.DateTimeFromJDN(258994.5)
> <mx.DateTime.DateTime object for '-4003-01-01 00:00:00.00' at 2b534aeb72f0>
>>>> mx.DateTime.DateTimeFrom('1.1.4004 BCE').mjd
> -2141006.0
>>>> mx.DateTime.DateTimeFromMJD(-2141006.0)
> <mx.DateTime.DateTime object for '-4003-01-01 00:00:00.00' at 2b534a46a2f0>
>
> The supported date range is limited by the number of days
> that fit into a C long. Should be enough for most use cases :-)

Nice ... :) I didn't know that mxDateTime has support for Julian Date.

Christian

M.-A. Lemburg

unread,
Oct 7, 2009, 10:47:52 AM10/7/09
to Christian Heimes, pytho...@python.org
Christian Heimes wrote:
> M.-A. Lemburg schrieb:
>> Christian Heimes wrote:
>>> Ben Finney wrote:
>>>> If you're committed to changing the epoch anyway, I would recommend
>>>> using <URL:http://en.wikipedia.org/wiki/Astronomical_year_numbering>
>>>> (epoch at 4004 BCE) since it is widely used to unify dates referring to
>>>> human history.
>>> I prefer JDN or MJD (http://en.wikipedia.org/wiki/JDN) for dates long
>>> before or after the unix epoch. The conversion from JDN as float to a
>>> datetime object is trivial.
>>
>> FWIW, mxDateTime can help you with all of those:
>>
>>>>> import mx.DateTime
>>>>> mx.DateTime.DateTimeFrom('1.1.4004 BCE')
>> <mx.DateTime.DateTime object for '-4003-01-01 00:00:00.00' at 2b534a46a2f0>
>>>>> mx.DateTime.DateTimeFrom('1.1.4004 BCE').jdn
>> 258994.5
>>>>> mx.DateTime.DateTimeFromJDN(258994.5)
>> <mx.DateTime.DateTime object for '-4003-01-01 00:00:00.00' at 2b534aeb72f0>
>>>>> mx.DateTime.DateTimeFrom('1.1.4004 BCE').mjd
>> -2141006.0
>>>>> mx.DateTime.DateTimeFromMJD(-2141006.0)
>> <mx.DateTime.DateTime object for '-4003-01-01 00:00:00.00' at 2b534a46a2f0>
>>
>> The supported date range is limited by the number of days
>> that fit into a C long. Should be enough for most use cases :-)
>
> Nice ... :) I didn't know that mxDateTime has support for Julian Date.

It also implements the TJD that's sometimes used in the US (the NIST
definition of it):

>>> mx.DateTime.DateTimeFrom('1.1.4004 BCE').tjd
-1006.0
>>> mx.DateTime.DateTimeFrom('1.1.4004 BCE').tjd_myriad
26
>>> mx.DateTime.DateTimeFromTJD(-1006.0, 26)
<mx.DateTime.DateTime object for '-4003-01-01 00:00:00.00' at 2b81d4a58558>

And has support for the Julian calendar:

>>> mx.DateTime.JulianDateTime(1752, 9, 2).Gregorian()
<mx.DateTime.DateTime object for '1752-09-13 00:00:00.00' at 2b81d4a6eb88>

which is sometimes handy for historical dates:

http://en.wikipedia.org/wiki/Julian_calendar

Stef Mientki

unread,
Oct 8, 2009, 4:05:40 PM10/8/09
to pytho...@python.org
Stephen Hansen wrote:
> <snip>
> Personally, while /users/ may write a date in a lazy way like
> "01-01-53", I'd never store that and would avoid having them enter
> them directly. At the UI level I'd validate and normalize it to a
> standard format before storing it.
>
yes I agree, but the data is coming from all kind of programs,
some more than 10 years old.
> E.g. instead of users entering someone's birthday into a control, I'd
> use a calendar control, and store it with (in wx terms)
> date.FormatISODate(). Or use date.toString(ISODate) in QT terms (ish).
I don't know your age,
but with my age it takes hours to look up my birthday on a windows
calender control ;-)

cheers,
Stef

John Yeung

unread,
Oct 8, 2009, 5:08:21 PM10/8/09
to

I think the choice of epoch is not a big deal, once you pick one far
enough back. Ben Finney's suggestion to use 4004 BCE is not
appreciably different (computationally) from JDN. (Though I will say
that the Wikipedia link he provided doesn't mention 4004 BCE, and if
anything suggests using 1 CE as the epoch.)

If there is any difficulty, it would be determining whether historical
records used (for example) the Julian calendar or Gregorian. This
doesn't seem to be a factor for the OP's use case, so my
recommendation would be to just pick whatever's convenient (either
because some library or program uses it, or because it makes intuitive
sense to the programmer).

John

John Yeung

unread,
Oct 8, 2009, 5:36:14 PM10/8/09
to
On Oct 6, 4:10 pm, Stef Mientki <stef.mien...@gmail.com> wrote:
>
> thanks guys,
> mx works a bit better  ....

Another popular Python date library is dateutil:

http://labix.org/python-dateutil

It gives a certain amount of credit to mxDateTime (praising it but not
being very clear how they are related; there is some mention of "using
the specification" of mxDateTime).

I would say mxDateTime and dateutil are the two heavyweights in this
arena. As you would expect, they have a lot of overlapping
functionality and which one is used is often just a matter of taste,
or whichever one you happened to find first.

One thing that dateutil provides that mxDateTime doesn't is support
for "lay person" month operations. That is, as far as I can tell,
mxDateTime tries not to dirty itself with the messy business of month
arithmetic, whereas dateutil rolls up its sleeves and takes an honest
stab at it. If you are writing a calendar/appointment application, or
other end-user-facing program, I would expect dateutil to be a little
more helpful.

John

Ben Finney

unread,
Oct 8, 2009, 6:36:31 PM10/8/09
to
John Yeung <gallium....@gmail.com> writes:

> I think the choice of epoch is not a big deal, once you pick one far
> enough back. Ben Finney's suggestion to use 4004 BCE is not
> appreciably different (computationally) from JDN. (Though I will say
> that the Wikipedia link he provided doesn't mention 4004 BCE, and if
> anything suggests using 1 CE as the epoch.)

My apologies, I gave the wrong year. I was intending to refer to the
<URL:http://en.wikipedia.org/wiki/Julian_date> system, which begins at
the year −4712 (4713 BCE).

This has the advantages of:

* clearly covering spans of human history more recent than ancient
civilisations

* having a long-recognised standard specification

* being commonly used in computing (for astronomy and other scientific
computing applications)

* making arithmetic on dates simple (it uses a year zero, making the
time line an uninterrupted number line)

--
\ “When we talk to God, we're praying. When God talks to us, |
`\ we're schizophrenic.” —Jane Wagner, via Lily Tomlin, 1985 |
_o__) |
Ben Finney

M.-A. Lemburg

unread,
Oct 9, 2009, 6:10:59 AM10/9/09
to John Yeung, pytho...@python.org
John Yeung wrote:
> On Oct 6, 4:10 pm, Stef Mientki <stef.mien...@gmail.com> wrote:
>>
>> thanks guys,
>> mx works a bit better ....
>
> Another popular Python date library is dateutil:
>
> http://labix.org/python-dateutil
>
> It gives a certain amount of credit to mxDateTime (praising it but not
> being very clear how they are related; there is some mention of "using
> the specification" of mxDateTime).

History goes a bit like this:

mxDateTime was the first Python library to implement native
date/time types for Python. I started the project in 1997.

Back then I had a good look around at the various date/time
libs and then decided to take a little more academic approach
to the whole thing. The result was that you only need two basic
types in mxDateTime: the DateTime object, which refers to a point
in time, and the DateTimeDelta object, which allows measuring
the time span between two such points. Note the absence of
a Date object. These would be date/time range objects since they
apply to the timespan of a full day with a time reference point
at midnight. I decided to leave such ranges for a later stage
in development - and have so far, never needed them :-)

A bit later in 1998, I also added the RelativeDateTime object,
which allows doing date/time calculations based on relative terms,
e.g. x minus one year (which could mean 356 or 366 days
depending on the year), first of next month (which could
mean anything from 1-31 days), last of next month, Tuesday
in 3 weeks, last Monday next month, etc.

And again a bit later in 2000, I added the RelativeDateTimeDiff
object which works a bit like an age function in that it tries to
determine the RelativeDateTime value which has to be applied
to a DateTime object in order to reach another one, say
from your birthday to today. The result reads is more user-
friendly than a bare DateTimeDelta, e.g. you get 40 years,
6 months, 3 days instead of 14796 days.

In 2002 Zope Corp initiated the development of the datetime
module, which borrowed a lot of design and API ideas from
mxDateTime.

However, it did not provide a date/time string parser and also
misses out on lots of the other good stuff you can find in
mxDateTime.

Gustavo Niemeyer started to work on a date/time parser based
on the datetime module - that's the python-dateutil library.
He also added a relative date/time object which was one of the
bits Zope Corp left out in the datetime module from mxDateTime
and added some other things that are not currently part of
mxDateTime: recurring events and time zones.

mxDateTime continues to be actively developed - mostly driven
by eGenix' own needs and experience we find in projects. Whenever
we need something new, we can just add it to mxDateTime and since
its release cycle is not bound to Python's, such enhancement
are more readily available to others as well.

Overall, my impression is that the datetime module was designed
on the drawing board without actually touching real life
usage scenarios.

We've just done a project that used the datetime module for
date/time related things instead of mxDateTime and
found that while the implementation is similar to mxDateTime
(naturally, see above), many useful features you find in mxDateTime
are not available on the datetime objects.

For future releases, we'll make the interaction between the
two implementations more user friendly, e.g. it should be
possible to pass a datetime object to mx.DateTime.DateTimeFrom()
and call a method on DateTime objects to get a datetime
module object with the same values.

> I would say mxDateTime and dateutil are the two heavyweights in this
> arena. As you would expect, they have a lot of overlapping
> functionality and which one is used is often just a matter of taste,
> or whichever one you happened to find first.
>
> One thing that dateutil provides that mxDateTime doesn't is support
> for "lay person" month operations. That is, as far as I can tell,
> mxDateTime tries not to dirty itself with the messy business of month
> arithmetic, whereas dateutil rolls up its sleeves and takes an honest
> stab at it. If you are writing a calendar/appointment application, or
> other end-user-facing program, I would expect dateutil to be a little
> more helpful.

Month arithmetic is a bit of a mess, since it's not clear how
to map e.g. Jan 31 + one month.

mxDateTime does support month arithmetic via the RelativeDateTime
object, but I'm not all that happy with the solution to the above
problem. The alternatives are basically deciding between loosing
data or raising an exception - both aren't really all that nice.

Perhaps I'll just add a parameter to allow customization of the
behavior depending on application needs.

--
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source (#1, Oct 09 2009)

Tim Chase

unread,
Oct 9, 2009, 8:39:43 AM10/9/09
to M.-A. Lemburg, John Yeung, pytho...@python.org
> Month arithmetic is a bit of a mess, since it's not clear how
> to map e.g. Jan 31 + one month.

"Jan 31 + one month" usually means "add one to the month value
and then keep backing off the day if you get an exception making
the date", so you'd get Feb 31, exception, Feb 30, exception, Feb
29, possibly an exception, and possibly/finally Feb 28th. This
makes pretty intuitive sense to most folks and is usually what's
meant.

I've found that issues and confusion stem more from the
non-commutative reality that "Jan 31 + (1 month) + (-1 month) !=
Jan 31 + (-1 month) + (1 month)" or the non-associative "Jan 31 +
(1 month + 1 month) != (Jan 31 + 1 month) + 1 month" :-/

So yes, messy it is!

-tkc

Rhodri James

unread,
Oct 11, 2009, 8:33:29 AM10/11/09
to pytho...@python.org

I'd hazard a guess that what we're actually seeing is people mentally
rebasing their indices, i.e. counting from the end of the month rather
than the start, which makes "the last day of January" and "January 31"
not the same thing really. Unfortunately we're very fuzzy about when
we do things like this, which makes it hard on a poor programmer.

--
Rhodri James *-* Wildebeest Herder to the Masses

MRAB

unread,
Oct 11, 2009, 11:55:15 AM10/11/09
to pytho...@python.org
And when someone says "January 30", do they really mean the day before
the last day of the month? Where would it end? :-)

greg

unread,
Oct 12, 2009, 5:10:34 AM10/12/09
to
MRAB wrote:

> And when someone says "January 30", do they really mean the day before
> the last day of the month?

No, no, that's January -2, a *completely* different thing!

--
Greg

Piet van Oostrum

unread,
Oct 12, 2009, 7:27:00 AM10/12/09
to
>>>>> greg <gr...@cosc.canterbury.ac.nz> (g) wrote:

>g> MRAB wrote:
>>> And when someone says "January 30", do they really mean the day before
>>> the last day of the month?

>g> No, no, that's January -2, a *completely* different thing!

But for someone else it would be February -2.
--
Piet van Oostrum <pi...@vanoostrum.org>
WWW: http://pietvanoostrum.com/
PGP key: [8DAE142BE17999C4]

Chris Rebert

unread,
Oct 12, 2009, 7:59:27 AM10/12/09
to Piet van Oostrum, pytho...@python.org
On Mon, Oct 12, 2009 at 4:27 AM, Piet van Oostrum <pi...@cs.uu.nl> wrote:
>>>>>> greg <gr...@cosc.canterbury.ac.nz> (g) wrote:
>
>>g> MRAB wrote:
>>>> And when someone says "January 30", do they really mean the day before
>>>> the last day of the month?
>
>>g> No, no, that's January -2, a *completely* different thing!
>
> But for someone else it would be February -2.

And for still others, it's the last $DAYOFWEEK of the month, which
just happened to fall on the 30th.

Cheers,
Chris
--
http://blog.rebertia.com

MRAB

unread,
Oct 12, 2009, 9:56:56 AM10/12/09
to pytho...@python.org
Piet van Oostrum wrote:
>>>>>> greg <gr...@cosc.canterbury.ac.nz> (g) wrote:
>
>> g> MRAB wrote:
>>>> And when someone says "January 30", do they really mean the day before
>>>> the last day of the month?
>
>> g> No, no, that's January -2, a *completely* different thing!
>
> But for someone else it would be February -2.

When is February 0? :-)

M.-A. Lemburg

unread,
Oct 12, 2009, 2:00:09 PM10/12/09
to Tim Chase, John Yeung, pytho...@python.org
Tim Chase wrote:
>> Month arithmetic is a bit of a mess, since it's not clear how
>> to map e.g. Jan 31 + one month.
>
> "Jan 31 + one month" usually means "add one to the month value and then
> keep backing off the day if you get an exception making the date", so
> you'd get Feb 31, exception, Feb 30, exception, Feb 29, possibly an
> exception, and possibly/finally Feb 28th. This makes pretty intuitive
> sense to most folks and is usually what's meant.

Well, yes, but that's just one way to solve the problem. I guess
I'll just add all possible solutions and then let the user decide
what's best in some way.

> I've found that issues and confusion stem more from the non-commutative
> reality that "Jan 31 + (1 month) + (-1 month) != Jan 31 + (-1 month) +
> (1 month)" or the non-associative "Jan 31 + (1 month + 1 month) != (Jan
> 31 + 1 month) + 1 month" :-/

That's why mxDateTime actually returning a day in March...

>>> mx.DateTime.DateTime(2009, 1, 31) + mx.DateTime.RelativeDateTime(months=+1)
<mx.DateTime.DateTime object for '2009-03-03 00:00:00.00' at 2ba43f93ebe0>

That's intuitive for mathematicians only, though ;-)

> So yes, messy it is!

Indeed.

--
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source (#1, Oct 12 2009)

M.-A. Lemburg

unread,
Oct 12, 2009, 2:02:28 PM10/12/09
to Rhodri James, pytho...@python.org
Rhodri James wrote:
> On Fri, 09 Oct 2009 13:39:43 +0100, Tim Chase
> <pytho...@tim.thechases.com> wrote:
>
>>> Month arithmetic is a bit of a mess, since it's not clear how
>>> to map e.g. Jan 31 + one month.
>>
>> "Jan 31 + one month" usually means "add one to the month value and
>> then keep backing off the day if you get an exception making the
>> date", so you'd get Feb 31, exception, Feb 30, exception, Feb 29,
>> possibly an exception, and possibly/finally Feb 28th. This makes
>> pretty intuitive sense to most folks and is usually what's meant.
>>
>> I've found that issues and confusion stem more from the
>> non-commutative reality that "Jan 31 + (1 month) + (-1 month) != Jan
>> 31 + (-1 month) + (1 month)" or the non-associative "Jan 31 + (1 month
>> + 1 month) != (Jan 31 + 1 month) + 1 month" :-/
>
> I'd hazard a guess that what we're actually seeing is people mentally
> rebasing their indices, i.e. counting from the end of the month rather
> than the start, which makes "the last day of January" and "January 31"
> not the same thing really. Unfortunately we're very fuzzy about when
> we do things like this, which makes it hard on a poor programmer.

Ah, for that we have RelativeDateTime:

>>> # "next month, last day of the month"
>>> mx.DateTime.DateTime(2009, 1, 31) + mx.DateTime.RelativeDateTime(months=+1, day=-1)
<mx.DateTime.DateTime object for '2009-02-28 00:00:00.00' at 2ba43f95c088>

M.-A. Lemburg

unread,
Oct 12, 2009, 2:34:33 PM10/12/09
to Chris Rebert, Piet van Oostrum, pytho...@python.org
Chris Rebert wrote:
> On Mon, Oct 12, 2009 at 4:27 AM, Piet van Oostrum <pi...@cs.uu.nl> wrote:
>>>>>>> greg <gr...@cosc.canterbury.ac.nz> (g) wrote:
>>
>>> g> MRAB wrote:
>>>>> And when someone says "January 30", do they really mean the day before
>>>>> the last day of the month?
>>
>>> g> No, no, that's January -2, a *completely* different thing!
>>
>> But for someone else it would be February -2.
>
> And for still others, it's the last $DAYOFWEEK of the month, which
> just happened to fall on the 30th.

That's a little more complicated:

>>> mx.DateTime.DateTime(2009, 1, 31).day_of_week
5
>>> # which is a ...
>>> mx.DateTime.Weekday[mx.DateTime.DateTime(2009, 1, 31).day_of_week]
'Saturday'

Now:

>>> # "next month, last Saturday"
>>> mx.DateTime.DateTime(2009, 1, 31) + mx.DateTime.RelativeDateTime(months=+1, day=1, weekday=(5, -1))
<mx.DateTime.DateTime object for '2009-02-28 00:00:00.00' at 2ba43f93ebe0>

0 new messages