Thread: Inputting relative datetimes

Inputting relative datetimes

From
Dean Rasheed
Date:
As background, I have an app that accepts user text input and casts it
to a timestamp in order to produce reports. I use PostgreSQL's
timestamp input conversion for this, since it gives a lot of
flexibility, and can parse pretty much anything the users throw at it.

It is also handy that it recognizes special case values like "now",
"today", "tomorrow" and "yesterday". However, I can't see any way of
entering more general relative timestamps like "5 days ago" or "2
hours from now".

Obviously I can enhance my app by writing my own input function to
support relative timestamps, but I wonder if this is something that
would be more generally useful if PostgreSQL supported it natively. If
so, what should the syntax be?

My first thought was to have some general way of adding or subtracting
an interval at the end of an input timestamp, eg. by adding another
couple of special values - "plus <interval>" and "minus <interval>".
This would allow things like:

TIMESTAMPTZ 'today minus 5 days'
TIMESTAMPTZ 'now plus 2 hours'

It seems a bit clunky to have to spell out "plus" and "minus", but I
think that using the symbols + and - would be impossible to parse
because of the ambiguity with timezones.

Thoughts?
Better ideas?

Regards,
Dean


Re: Inputting relative datetimes

From
Vik Reykja
Date:
On Thu, Aug 25, 2011 at 11:39, Dean Rasheed <span dir="ltr"><<a
href="mailto:dean.a.rasheed@gmail.com">dean.a.rasheed@gmail.com</a>></span>wrote:<br /><div
class="gmail_quote"><blockquoteclass="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc
solid;padding-left:1ex;">My first thought was to have some general way of adding or subtracting<br /> an interval at
theend of an input timestamp, eg. by adding another<br /> couple of special values - "plus <interval>" and "minus
<interval>".<br/> This would allow things like:<br /><br /> TIMESTAMPTZ 'today minus 5 days'<br /> TIMESTAMPTZ
'nowplus 2 hours'<br /></blockquote></div><br />Funny you should mention intervals...<br /><br />timestamptz 'today' -
interval'5 days'<br />timestamptz 'now' + interval '2 hours'<br /> 

Re: Inputting relative datetimes

From
Dean Rasheed
Date:
On 25 August 2011 10:43, Vik Reykja <vikreykja@gmail.com> wrote:
> On Thu, Aug 25, 2011 at 11:39, Dean Rasheed <dean.a.rasheed@gmail.com>
> wrote:
>>
>> My first thought was to have some general way of adding or subtracting
>> an interval at the end of an input timestamp, eg. by adding another
>> couple of special values - "plus <interval>" and "minus <interval>".
>> This would allow things like:
>>
>> TIMESTAMPTZ 'today minus 5 days'
>> TIMESTAMPTZ 'now plus 2 hours'
>
> Funny you should mention intervals...
>
> timestamptz 'today' - interval '5 days'
> timestamptz 'now' + interval '2 hours'
>

Yes, but what I am trying to achieve is a way of entering such
relative timestamps using a single input value, so that absolute and
relative timestamps can both be bound to a SQL query using just one
variable.

Regards,
Dean


Re: Inputting relative datetimes

From
Merlin Moncure
Date:
On Thu, Aug 25, 2011 at 5:08 AM, Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
> On 25 August 2011 10:43, Vik Reykja <vikreykja@gmail.com> wrote:
>> On Thu, Aug 25, 2011 at 11:39, Dean Rasheed <dean.a.rasheed@gmail.com>
>> wrote:
>>>
>>> My first thought was to have some general way of adding or subtracting
>>> an interval at the end of an input timestamp, eg. by adding another
>>> couple of special values - "plus <interval>" and "minus <interval>".
>>> This would allow things like:
>>>
>>> TIMESTAMPTZ 'today minus 5 days'
>>> TIMESTAMPTZ 'now plus 2 hours'
>>
>> Funny you should mention intervals...
>>
>> timestamptz 'today' - interval '5 days'
>> timestamptz 'now' + interval '2 hours'
>>
>
> Yes, but what I am trying to achieve is a way of entering such
> relative timestamps using a single input value, so that absolute and
> relative timestamps can both be bound to a SQL query using just one
> variable.

not gonna happen.  as noted, intervals already solve the issue quite
well and timestamp string parsing is already complicated enough as it
is.

merlin


Re: Inputting relative datetimes

From
Josh Berkus
Date:
> Yes, but what I am trying to achieve is a way of entering such
> relative timestamps using a single input value, so that absolute and
> relative timestamps can both be bound to a SQL query using just one
> variable.

I think adding a function would be the way to go then.  Maybe extending
to_timestamp with a "relative" keyword.

-- 
Josh Berkus
PostgreSQL Experts Inc.
http://pgexperts.com


Re: Inputting relative datetimes

From
Jim Nasby
Date:
On Aug 25, 2011, at 5:08 AM, Dean Rasheed wrote:
>> Funny you should mention intervals...
>>
>> timestamptz 'today' - interval '5 days'
>> timestamptz 'now' + interval '2 hours'
>>
>
> Yes, but what I am trying to achieve is a way of entering such
> relative timestamps using a single input value, so that absolute and
> relative timestamps can both be bound to a SQL query using just one
> variable.


Even if the community doesn't want to add this to core, I think it would be a great add-on to put on PGXN. If you don't
feelup to writing it themselves, perhaps you would pay one of the consulting companies to do it for them? 
--
Jim C. Nasby, Database Architect                   jim@nasby.net
512.569.9461 (cell)                         http://jim.nasby.net




Re: Inputting relative datetimes

From
Robert Haas
Date:
On Fri, Aug 26, 2011 at 4:32 PM, Jim Nasby <jim@nasby.net> wrote:
> On Aug 25, 2011, at 5:08 AM, Dean Rasheed wrote:
>>> Funny you should mention intervals...
>>>
>>> timestamptz 'today' - interval '5 days'
>>> timestamptz 'now' + interval '2 hours'
>>>
>>
>> Yes, but what I am trying to achieve is a way of entering such
>> relative timestamps using a single input value, so that absolute and
>> relative timestamps can both be bound to a SQL query using just one
>> variable.
>
> Even if the community doesn't want to add this to core, I think it would be a great add-on to put on PGXN. If you
don'tfeel up to writing it themselves, perhaps you would pay one of the consulting companies to do it for them?
 

Frankly, our current date parsing code is pretty darn strange and
flaky.  If nobody's found the energy to rationalize that, what are the
chances that we can add a whole bunch more functionality without also
adding a whole bunch more bugs?  For examples of the sorts of things
we haven't gotten around to fixing, see:

http://archives.postgresql.org/pgsql-hackers/2011-03/msg01295.php

Another problem here is that it seems possible, even likely, that
everyone will have their own particular flavor of what they'd like to
see accepted: two weeks ago, a week ago Tuesday, next Saturday, last
Friday, two weeks from Saturday, Christmas plus three fortnights...
if it weren't already spaghetti code...  give it time.  I'm not
necessarily opposed to the idea (especially as a contrib module), but
I'm a little nervous that we might be overestimating the extent to
which Dean's needs are universal.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


Re: Inputting relative datetimes

From
Dean Rasheed
Date:
On 27 August 2011 02:32, Robert Haas <robertmhaas@gmail.com> wrote:
> Frankly, our current date parsing code is pretty darn strange and
> flaky...

So Robert and Merlin both expressed concerns that the existing
datetime string parsing code is so complicated that adding to it would
likely just introduce more bugs.

My first thought was 'how hard can it be?' - famous last words :-)

Anyway I knocked up the attached POC patch implementing my originally
proposed syntax. I haven't tested it much, so it may well have bugs,
but the separation of the new code seems pretty clean, so it shouldn't
break any existing parsing logic.

Here are a few examples of what it allows:

SELECT str, str::timestamptz result FROM (VALUES
 ('2011-08-27'),
 ('today'),
 ('now'),
 ('today minus 5 days'),
 ('now plus 2 hours'),
 ('tomorrow plus 1 month'),
 ('minus 30 minutes'),
 ('25/12/2011 plus 6 weeks')
) AS x(str);

           str           |            result
-------------------------+-------------------------------
 2011-08-27              | 2011-08-27 00:00:00+01
 today                   | 2011-08-27 00:00:00+01
 now                     | 2011-08-27 12:11:46.245659+01
 today minus 5 days      | 2011-08-22 00:00:00+01
 now plus 2 hours        | 2011-08-27 14:11:46.245659+01
 tomorrow plus 1 month   | 2011-09-28 00:00:00+01
 minus 30 minutes        | 2011-08-27 11:41:46.245659+01
 25/12/2011 plus 6 weeks | 2012-02-05 00:00:00+00
(8 rows)

(I decided not to implement 'Christmas plus three fortnights' ;-)

I don't have a feel for how widely useful this is, and I'm not
particularly wedded to this syntax, but if nothing else it has been a
fun exercise figuring out how the datetime string parsing code works.

Regards,
Dean

Attachment

Re: Inputting relative datetimes

From
Dean Rasheed
Date:
On 27 August 2011 12:29, Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
> ... if nothing else it has been a
> fun exercise figuring out how the datetime string parsing code works.
>

While looking through the current code, I spotted the following oddity:

select timestamp 'yesterday 10:30';     timestamp
---------------------2011-08-26 10:30:00

which is what you'd expect, however:

select timestamp '10:30 yesterday';     timestamp
---------------------2011-08-26 00:00:00

Similarly "today" and "tomorrow" reset any time fields so far, but
ISTM that they should really be preserving the hour, min, sec fields
decoded so far.

Regards,
Dean


Re: Inputting relative datetimes

From
Peter Eisentraut
Date:
On lör, 2011-08-27 at 12:29 +0100, Dean Rasheed wrote:
> So Robert and Merlin both expressed concerns that the existing
> datetime string parsing code is so complicated that adding to it would
> likely just introduce more bugs.
> 
> My first thought was 'how hard can it be?' - famous last words :-)

Maybe you can find an existing Perl or Python module that has already
implemented this.  Then the solution might be 5 lines of wrapping this
into a PostgreSQL function.




Re: Inputting relative datetimes

From
Jeff MacDonald
Date:
Greetings,

On Thursday, August 25, 2011 05:39:09 AM Dean Rasheed wrote:
> As background, I have an app that accepts user text input and casts it
> to a timestamp in order to produce reports. I use PostgreSQL's
> timestamp input conversion for this, since it gives a lot of
> flexibility, and can parse pretty much anything the users throw at it.
> 
> It is also handy that it recognizes special case values like "now",
> "today", "tomorrow" and "yesterday". However, I can't see any way of
> entering more general relative timestamps like "5 days ago" or "2
> hours from now".
> 

Years ago I wrapped 'getdate.y' from the CVS source code and made it into a 
python extension. It handles "+2 hours" or "next week", etc. I don't know much 
of anything about making pg contrib modules, but it should not be hard to do. 
The way it works is you pass in a string and it returns the unix timestamp.

[...snipped...]
> 
> Thoughts?
> Better ideas?
> 
> Regards,
> Dean

Regards,
J


Re: Inputting relative datetimes

From
Dean Rasheed
Date:
On 27 August 2011 14:14, Peter Eisentraut <peter_e@gmx.net> wrote:
> On lör, 2011-08-27 at 12:29 +0100, Dean Rasheed wrote:
>> So Robert and Merlin both expressed concerns that the existing
>> datetime string parsing code is so complicated that adding to it would
>> likely just introduce more bugs.
>>
>> My first thought was 'how hard can it be?' - famous last words :-)
>
> Maybe you can find an existing Perl or Python module that has already
> implemented this.  Then the solution might be 5 lines of wrapping this
> into a PostgreSQL function.
>

Ah now that's an interesting idea.

Python's dateutil module seems to come highly recommended, although I
don't find this too encouraging:

>>> dateutil.parser.parse('today', fuzzy=True)
datetime.datetime(2011, 8, 27, 0, 0)
>>> dateutil.parser.parse('tomorrow', fuzzy=True)
datetime.datetime(2011, 8, 27, 0, 0)
>>> dateutil.parser.parse('foobar', fuzzy=True)
datetime.datetime(2011, 8, 27, 0, 0)

Still, there might be something better out there...

Cheers,
Dean


Re: Inputting relative datetimes

From
Dean Rasheed
Date:
On 27 August 2011 14:29, Jeff MacDonald <jam@zoidtechnologies.com> wrote:
> Greetings,
>
> On Thursday, August 25, 2011 05:39:09 AM Dean Rasheed wrote:
>> As background, I have an app that accepts user text input and casts it
>> to a timestamp in order to produce reports. I use PostgreSQL's
>> timestamp input conversion for this, since it gives a lot of
>> flexibility, and can parse pretty much anything the users throw at it.
>>
>> It is also handy that it recognizes special case values like "now",
>> "today", "tomorrow" and "yesterday". However, I can't see any way of
>> entering more general relative timestamps like "5 days ago" or "2
>> hours from now".
>>
>
> Years ago I wrapped 'getdate.y' from the CVS source code and made it into a
> python extension. It handles "+2 hours" or "next week", etc. I don't know much
> of anything about making pg contrib modules, but it should not be hard to do.
> The way it works is you pass in a string and it returns the unix timestamp.
>
> [...snipped...]

That sounds like a pretty good approach, and a contrib module might
well be the way to go.

I'm not sure how best to handle timezones though, since it's
hard-coded list probably won't match the timezones PostgreSQL knows
about. Maybe that doesn't matter, I'm not sure.

Regards,
Dean


Re: Inputting relative datetimes

From
Jeff MacDonald
Date:
Greetings,

On Saturday, August 27, 2011 11:36:13 AM Dean Rasheed wrote:
> 
> I'm not sure how best to handle timezones though, since it's
> hard-coded list probably won't match the timezones PostgreSQL knows
> about. Maybe that doesn't matter, I'm not sure.
> 

It'll matter when the expression has a result that crosses the DST date. Does 
Postgres have a library that could be used by the parser?

> Regards,
> Dean

Regards,
Jeff


Re: Inputting relative datetimes

From
Robert Haas
Date:
On Sat, Aug 27, 2011 at 7:43 AM, Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
> On 27 August 2011 12:29, Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
>> ... if nothing else it has been a
>> fun exercise figuring out how the datetime string parsing code works.
>
> While looking through the current code, I spotted the following oddity:
>
> select timestamp 'yesterday 10:30';
>      timestamp
> ---------------------
>  2011-08-26 10:30:00
>
> which is what you'd expect, however:
>
> select timestamp '10:30 yesterday';
>      timestamp
> ---------------------
>  2011-08-26 00:00:00
>
> Similarly "today" and "tomorrow" reset any time fields so far, but
> ISTM that they should really be preserving the hour, min, sec fields
> decoded so far.

Sounds right to me.  Want to send a patch?

BTW, this is exactly the sort of thing that makes me a bit skeptical
about further extending this...

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


Re: Inputting relative datetimes

From
Dean Rasheed
Date:
On 28 August 2011 00:39, Robert Haas <robertmhaas@gmail.com> wrote:
> On Sat, Aug 27, 2011 at 7:43 AM, Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
>> On 27 August 2011 12:29, Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
>>> ... if nothing else it has been a
>>> fun exercise figuring out how the datetime string parsing code works.
>>
>> While looking through the current code, I spotted the following oddity:
>>
>> select timestamp 'yesterday 10:30';
>>      timestamp
>> ---------------------
>>  2011-08-26 10:30:00
>>
>> which is what you'd expect, however:
>>
>> select timestamp '10:30 yesterday';
>>      timestamp
>> ---------------------
>>  2011-08-26 00:00:00
>>
>> Similarly "today" and "tomorrow" reset any time fields so far, but
>> ISTM that they should really be preserving the hour, min, sec fields
>> decoded so far.
>
> Sounds right to me.  Want to send a patch?
>

The attached patch makes "today", "tomorrow" and "yesterday" only set
the year, month and day fields. All the other fields are already
initialised to 0 at the start, and may be set non-zero before or after
encountering these special date values. The result should now be
independent of the order of the fields.

Regards,
Dean

Attachment

Re: Inputting relative datetimes

From
Dean Rasheed
Date:
On 28 August 2011 00:00, Jeff MacDonald <jam@zoidtechnologies.com> wrote:
> Greetings,
>
> On Saturday, August 27, 2011 11:36:13 AM Dean Rasheed wrote:
>>
>> I'm not sure how best to handle timezones though, since it's
>> hard-coded list probably won't match the timezones PostgreSQL knows
>> about. Maybe that doesn't matter, I'm not sure.
>>
>
> It'll matter when the expression has a result that crosses the DST date. Does
> Postgres have a library that could be used by the parser?
>

On further examination of this and other datetime parsing code, I am
coming to the conclusion that for absolute timestamps the PostgreSQL
code is (IMO) the best and most flexible in terms of accepting a
variety of commons formats.

While getdate.y and others offer better support for relative
timestamps, it seems to come at the cost of poorer support for
absolute timestamps, which for me is a deal-breaker. There are also
other incompatibilities, such as different handling of "today", which
is just likely to lead to confusion.

It may not be worth the effort of trying to get a patch into core
PostgreSQL for this, but given the already excellent absolute
timestamp and interval support, I'm thinking that maybe the best
answer is to just write a userland function that breaks an input
string up into timestamp and interval parts and returns the resulting
timestamp.

Regards,
Dean


Re: Inputting relative datetimes

From
Robert Haas
Date:
On Sun, Aug 28, 2011 at 5:39 AM, Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
> On 28 August 2011 00:39, Robert Haas <robertmhaas@gmail.com> wrote:
>> On Sat, Aug 27, 2011 at 7:43 AM, Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
>>> On 27 August 2011 12:29, Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
>>>> ... if nothing else it has been a
>>>> fun exercise figuring out how the datetime string parsing code works.
>>>
>>> While looking through the current code, I spotted the following oddity:
>>>
>>> select timestamp 'yesterday 10:30';
>>>      timestamp
>>> ---------------------
>>>  2011-08-26 10:30:00
>>>
>>> which is what you'd expect, however:
>>>
>>> select timestamp '10:30 yesterday';
>>>      timestamp
>>> ---------------------
>>>  2011-08-26 00:00:00
>>>
>>> Similarly "today" and "tomorrow" reset any time fields so far, but
>>> ISTM that they should really be preserving the hour, min, sec fields
>>> decoded so far.
>>
>> Sounds right to me.  Want to send a patch?
>
> The attached patch makes "today", "tomorrow" and "yesterday" only set
> the year, month and day fields. All the other fields are already
> initialised to 0 at the start, and may be set non-zero before or after
> encountering these special date values. The result should now be
> independent of the order of the fields.

OK, committed.  Perhaps it should be back-patched, but since this was
only discovered during code-reading and not in the wild, I didn't
bother.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


Re: Inputting relative datetimes

From
Tom Lane
Date:
Robert Haas <robertmhaas@gmail.com> writes:
> On Sun, Aug 28, 2011 at 5:39 AM, Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
>> The attached patch makes "today", "tomorrow" and "yesterday" only set
>> the year, month and day fields. All the other fields are already
>> initialised to 0 at the start, and may be set non-zero before or after
>> encountering these special date values. The result should now be
>> independent of the order of the fields.

> OK, committed.  Perhaps it should be back-patched,

No, I don't think so.  This is an incompatible behavioral change with a
small-but-not-zero probability of breaking existing applications.
        regards, tom lane


Re: Inputting relative datetimes

From
Robert Haas
Date:
On Tue, Aug 30, 2011 at 11:52 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Robert Haas <robertmhaas@gmail.com> writes:
>> On Sun, Aug 28, 2011 at 5:39 AM, Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
>>> The attached patch makes "today", "tomorrow" and "yesterday" only set
>>> the year, month and day fields. All the other fields are already
>>> initialised to 0 at the start, and may be set non-zero before or after
>>> encountering these special date values. The result should now be
>>> independent of the order of the fields.
>
>> OK, committed.  Perhaps it should be back-patched,
>
> No, I don't think so.  This is an incompatible behavioral change with a
> small-but-not-zero probability of breaking existing applications.

Well, I'm fine with not back-patching it, but think the existing
behavior is flat wrong.  Having '04:00:00 yesterday' return midnight
yesterday is pretty well unjustifiable.  An error would be reasonable,
and DWIM is reasonable, but anything else is the wrong answer.  How
much worse would it have to be to qualify as a bug?  What if we didn't
the hour, minute, and second at all, and returned a value based on
whatever garbage was left over in the relevant memory location?  What
if we returned 40000 BC?

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


Re: Inputting relative datetimes

From
Tom Lane
Date:
Robert Haas <robertmhaas@gmail.com> writes:
> Well, I'm fine with not back-patching it, but think the existing
> behavior is flat wrong.

I'm not arguing that this way isn't better, just that it's different.
There have been zero user complaints about this behavior since Tom
Lockhart put it in, more than ten years ago.  That sort of militates
against a hard-line "it's flat wrong" stance.

But more to the point, since there wasn't an error before and there
isn't an error now, this is just a silent behavioral change, and we
avoid doing those in released branches.  People don't want to have to
retest their applications against minor releases.
        regards, tom lane


Re: Inputting relative datetimes

From
Dean Rasheed
Date:
On 30 August 2011 16:40, Robert Haas <robertmhaas@gmail.com> wrote:
> OK, committed.

Thanks.

I'm fine with not back-patching it, on the grounds given.

Cheers,
Dean