# Random date gen class. Returns a tuple of a start date and end date

Just interested in any comments about the way the code is written. I am very new to python and programming. I did think about a func with a generator, but thought this approach was better.

from datetime import date
from datetime import timedelta

import calendar
import random

class rand_dates(object):
'''
returns a date range as tuple of a random start date in the current year and an end date + random.randint(term) param.
the end date can exceed the current year.
my usage: i want a random reservation date for a hotel stay.
A base year can also be passed as a param if another year is required other than the current year
'''

def __init__(self, term = 5, year=None):
self.term = term
self.year = year

def __iter__(self):
return self

def next(self):
td = date.today()
if self.year == None:
y = td.year
else:
y = self.year

m = random.randint(1,12)
d_in_month = calendar.monthrange(y,m)[1]
d = random.randint(1,d_in_month)
sd = date(y,m,d)
ed= sd + timedelta(days=random.randint(1,self.term))
return (sd,ed)

• Could you provide more background information on your code to help with the reviewing process? Context is everything. – Mast Apr 30 '15 at 9:20

You thought about using a generator… and why did you reject the idea? If you have an object that does nothing other than iterating, then you might as well make it a generator — that's exactly what they are for.

The code is generally sound. In my opinion, it could flow better if you defined the variables in a more logical order: (random year, random month, random day), followed by (random span), then packaging the results.

The meaning of the term parameter is unclear. I would prefer a more explicit name. The default value, 5, is unexpected to me. Choose either:

• A "sensible" default of 1 day, because that is a natural lower limit for a hotel stay (unless you run one of those sleazy hotels that rents rooms by the hour)
• A default value of 0 days, because 0 is the additive identity
• No default at all: make it a required parameter

In any case, it's probably a good idea to handle max_days=0 correctly without crashing.

The docstring is a bit cumbersome, and slightly self-contradictory when it comes to explaining the year parameter.

import calendar
from datetime import date, timedelta
import random

def rand_dates(max_days=1, year=None):
'''
Returns a date range as (start_date, end_date) tuple.

The start date is a random date in the specified year (defaulting
to the current year).

The end date is a random date between 1 and max_days (inclusive) after
the start date.

Example usage: Picking random check-in and check-out dates for a hotel stay.
'''
while True:
y = year or date.today().year
m = random.randint(1, 12)
d = random.randint(1, calendar.monthrange(y, m)[1])
days = random.randint(1, max_days) if max_days > 0 else 0
start_date = date(y, m, d)
yield start_date, start_date + timedelta(days=days)

• Thanks 200_success, your points are well taken and I will adjust based on your comments. Easy to slip into this code is for myself mode, better to get into the habit of writing it so it's clear to anyone. – IanJ Apr 30 '15 at 10:06
• Regarding the generator, I thought this didn't make sense. I may call the next function one time or in a for loop. So given there is no definitive end, it didn't make sense to me to have a stack or state stored somewhere. Well that was my logic anyway. – IanJ Apr 30 '15 at 10:11
• @IanJ that logic doesn't make sense - do you think that the class instance isn't storing state? – jonrsharpe Apr 30 '15 at 10:13
• @jonrsharpe, surly a generator is storing a lot more state info than an iterator does. Look, I am new. But seems to me that when you yield, more is being saved. In this case, I didn't see the need to yield as no local vars or state required on calls – IanJ Apr 30 '15 at 10:18
• @IanJ a generator is (or, strictly, creates) an iterator! See e.g. docs.python.org/2/tutorial/classes.html#generators. Generally, if you're only using a class to iterate over, a generator is the better option (see e.g. youtube.com/watch?v=o9pEzgHorH0 for guidelines on when to avoid a class). – jonrsharpe Apr 30 '15 at 10:27