#!/usr/bin/env python
"""
Prints sequence of YYYY-MM-DD dates over the specified range.
(Like `seq' or `gseq' but for dates.)
Inclusive of both StartDate and EndDate.
Dates can be underspecified.  Any of these are fine:
  YYYY-MM-DD
  YYYY-MM
  YYYY
  YYYYMMDD
  YYYYMM

Examples
  dateseq 2010-10             # all 31 days of october 2010
  dateseq 2010                # all 365 days of 2010
  dateseq 2010-10 2011-03     # 2010-10-01 through 2011-03-31
  dateseq 201010 201103       # same thing

Underspecified StartDate uses the left-most day of the range.
Underspecified EndDate uses the right-most day of the range.
If EndDate is missing, use StartDate.  This only makes sense for underspecified
datetimes (I think), you get the sequence over that year or month.
"""

import sys, re
from datetime import datetime, timedelta

if '--test' in sys.argv:
    tests = """
    dateseq 2009
    dateseq 200911 200912
    dateseq 2009-01 2009-02
    dateseq 2009-01-05 2009-01-05
    dateseq 2009-01
    dateseq 2008-12 2009-01
    """
    import os
    lines = tests.strip().split("\n")
    for cmd in lines:
        print "\n***", cmd
        os.system(cmd + " | summary")
    sys.exit()

import argparse
class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter):
    pass
p = argparse.ArgumentParser(description=__doc__.strip(), formatter_class=CustomFormatter)
p.add_argument("start_date")
p.add_argument("end_date",nargs='?')
p.add_argument("--test",action='store_true')
p.add_argument("--format", default="%Y-%m-%d", help="strftime formatting of output")
args = p.parse_args()

start_date = args.start_date
end_date = args.end_date or start_date

def parse_datetime(s, mode):
  if re.search(r'^\d\d\d\d-\d\d-\d\d$', s):
    return datetime.strptime(s,'%Y-%m-%d')
  elif re.search('^\d{8}$', s):
    # YYYYMMDD
    return parse_datetime('%s-%s-%s' % (s[:4], s[4:6], s[6:8]), mode)
  elif re.search('^\d{6}$', s):
    # YYYYMM
    return parse_datetime('%s-%s' % (s[:4], s[4:6]), mode)
  elif re.search(r'^\d\d\d\d-\d\d$', s):
    y,m = s.split('-')
    y = int(y)
    m = int(m)
    if mode=='LEFT':
      return datetime(y,m,1)
    elif mode=='RIGHT':
      y,m = (y,m+1) if m<12 else (y+1,1)
      return datetime(y,m,1) - timedelta(days=1)
    else: assert False, "bad mode"
  elif re.search(r'^\d\d\d\d$', s):
    y = int(s)
    if mode=='LEFT':
      return datetime(y,1,1)
    elif mode=='RIGHT':
      return datetime(y+1,1,1) - timedelta(days=1)

  else: assert False, "couldn't parse %s" % repr(s)


start_date = parse_datetime(start_date, 'LEFT')
end_date = parse_datetime(end_date, 'RIGHT')

#print>>sys.stderr, start_date, end_date

assert start_date <= end_date

d = start_date
while d <= end_date:
  print d.strftime(args.format)
  d = d + timedelta(days=1)


