0

I am currently developing an application in which a user fills out forms to submit upcoming activities (which will later be automatically scheduled, haven't got to that yet). So far I have been using the standard datetime module for validation on form inputs to check that valid datetimes are being inputed, for example:

import datetime
import tkinter as tk
from tkinter import messagebox as tkMessageBox

#Loads of tkinter stuff leading to variables year, month, day, hour, minute

try:
    start_date_time = datetime.datetime(year,month,day,hour,minute)
except ValueError as inst:
    tkMessageBox.showerror("Invalid input",inst)

This has been very successful. My problem now is that I want to validate that start_date_time is in the future. I was hoping that I would be able to do this by manipulating datetime.datetime.min and datetime.datetime.max in order to make the existing code validate to see if an input is in the future (and not unreasonably far in the future, too).

This is how I have tried to achieve this:

now = datetime.datetime.now()
datetime.datetime.min = now

But this raises the following TypeError:

Traceback (most recent call last):
  File "J:\COMP4 Project\GUI.py", line 13, in <module>
    datetime.datetime.min = now
TypeError: can't set attributes of built-in/extension type 'datetime.datetime'

My question is: Is there a work around so that the values of datetime.datetime.min and datetime.datetime.max can be changed or must I write code to check each datetime to be validated is greater than now?

Rob Murray
  • 1,773
  • 6
  • 20
  • 32
  • 2
    Seriously, what's the problem with `start_date_time > now`? – karlson Jan 17 '16 at 13:09
  • @karlson Nothing is _wrong_ as such with that, I want to know if there is a work around so that I don't have to write loads of lines of `start_date_time > now`, as in the actual application there are loads of situations where I need to do this. – Rob Murray Jan 17 '16 at 13:11
  • @R.Murray, well, you always can set up a variable like this: `data_ok=start_date_time>now` and then check whether it's true or not: `if data_ok: print "great!"` – ForceBru Jan 17 '16 at 13:13
  • No, you can't do that, but you could write a `validate_date` function and keep that logic in there. – jonrsharpe Jan 17 '16 at 13:14
  • 1
    And what would you gain from monkey patching `datetime.min` and `datetime.max`? This won't make you happy. Write functions to not repeat yourself. – karlson Jan 17 '16 at 13:14
  • I appreciate this might not be the right thing to do, I was just asking. BUT is it _possible_? @karlson – Rob Murray Jan 17 '16 at 13:16
  • "If the implementation is hard to explain, it's a bad idea." - [PEP-20](https://www.python.org/dev/peps/pep-0020/) – msw Jan 17 '16 at 13:58

2 Answers2

2

Until I hear otherwise, setting the value of datetime.datetime.min and datetime.datetime.max is not possible, though datetime.MINYEAR and datetime.MAXYEAR can be changed, which then affects datetime.datetime.min and datetime.datetime.max. The best way to carry out validation on datetime objects, such that a check is carried out to check an activity is in the future taking in to account months, days, hours and minutes, in my situation is by using a function. For example:

def validateFuture(x):
    now = datetime.datetime.now()
    if x > now:
        return True
    else:
        return False

(where x is a datetime.datetime object such as start_date_time from the question)

Rob Murray
  • 1,773
  • 6
  • 20
  • 32
  • this code may break during DST transitions (local time may jump back). See [Find if 24 hrs have passed between datetimes - Python](http://stackoverflow.com/a/26313848/4279) – jfs Jan 20 '16 at 21:06
2

You could always subclass datetime.datetime and implement the check yourself:

import datetime

class MyDatetime(datetime.datetime):
    def __init__(self, *args, **kwargs):
        super().__init__()
        if self < datetime.datetime.now():
            raise ValueError("Date must be in the future")

MyDatetime(2017,10,10)  # Ok

MyDatetime(2010,10,10)  # Not ok

But seriously, don't do this. Just check start_date_time > now in a validation function, as you have written in your own answer.

karlson
  • 5,325
  • 3
  • 30
  • 62