class_docstr: A span of time between two ``datetime`` or ``adatetime`` objects.
      
docstr: Returns an unambiguous version of this object.
  
  >>> start = adatetime(year=2009, month=2)
  >>> end = adatetime(year=2009, month=10)
  >>> ts = timespan(start, end)
  >>> ts
  timespan(adatetime(2009, 2, None, None, None, None, None), adatetime(2009, 10, None, None, None, None, None))
  >>> td.disambiguated(datetime.now())
  timespan(datetime(2009, 2, 28, 0, 0, 0, 0), datetime(2009, 10, 31, 23, 59 ,59, 999999)
docstr_tok: ["Returns","an","unambiguous","version","of","this","object",".",">",">",">","start","=","adatetime","(","year=2009",",","month=2",")",">",">",">","end","=","adatetime","(","year=2009",",","month=10",")",">",">",">","ts","=","timespan","(","start",",","end",")",">",">",">","ts","timespan","(","adatetime","(","2009",",","2",",","None",",","None",",","None",",","None",",","None",")",",","adatetime","(","2009",",","10",",","None",",","None",",","None",",","None",",","None",")",")",">",">",">","td.disambiguated","(","datetime.now","(",")",")","timespan","(","datetime","(","2009",",","2",",","28",",","0",",","0",",","0",",","0",")",",","datetime","(","2009",",","10",",","31",",","23",",","59",",59",",","999999",")"]
code: def disambiguated(self, basedate, debug=0):
      """Returns an unambiguous version of this object.
  
      >>> start = adatetime(year=2009, month=2)
      >>> end = adatetime(year=2009, month=10)
      >>> ts = timespan(start, end)
      >>> ts
      timespan(adatetime(2009, 2, None, None, None, None, None), adatetime(2009, 10, None, None, None, None, None))
      >>> td.disambiguated(datetime.now())
      timespan(datetime(2009, 2, 28, 0, 0, 0, 0), datetime(2009, 10, 31, 23, 59 ,59, 999999)
      """
  
      # - If year is in start but not end, use basedate.year for end
      # -- If year is in start but not end, but startdate is > basedate,
      #   use "next <monthname>" to get end month/year
      # - If year is in end but not start, copy year from end to start
      # - Support "next february", "last april", etc.
  
      start, end = copy.copy(self.start), copy.copy(self.end)
      start_year_was_amb = start.year is None
      end_year_was_amb = end.year is None
  
      if has_no_date(start) and has_no_date(end):
          # The start and end points are just times, so use the basedate
          # for the date information.
          by, bm, bd = basedate.year, basedate.month, basedate.day
          start = start.replace(year=by, month=bm, day=bd)
          end = end.replace(year=by, month=bm, day=bd)
      else:
          # If one side has a year and the other doesn't, the decision
          # of what year to assign to the ambiguous side is kind of
          # arbitrary. I've used a heuristic here based on how the range
          # "reads", but it may only be reasonable in English. And maybe
          # even just to me.
  
          if start.year is None and end.year is None:
              # No year on either side, use the basedate
              start.year = end.year = basedate.year
          elif start.year is None:
              # No year in the start, use the year from the end
              start.year = end.year
          elif end.year is None:
              end.year = max(start.year, basedate.year)
  
      if start.year == end.year:
          # Once again, if one side has a month and day but the other side
          # doesn't, the disambiguation is arbitrary. Does "3 am to 5 am
          # tomorrow" mean 3 AM today to 5 AM tomorrow, or 3am tomorrow to
          # 5 am tomorrow? What I picked is similar to the year: if the
          # end has a month+day and the start doesn't, copy the month+day
          # from the end to the start UNLESS that would make the end come
          # before the start on that day, in which case use the basedate
          # instead. If the start has a month+day and the end doesn't, use
          # the basedate.
          start_dm = not (start.month is None and start.day is None)
          end_dm = not (end.month is None and end.day is None)
          if end_dm and not start_dm:
              if start.floor().time() > end.ceil().time():
                  start.month = basedate.month
                  start.day = basedate.day
              else:
                  start.month = end.month
                  start.day = end.day
          elif start_dm and not end_dm:
              end.month = basedate.month
              end.day = basedate.day
  
      if floor(start).date() > ceil(end).date():
          # If the disambiguated dates are out of order:
          # - If no start year was given, reduce the start year to put the
          #   start before the end
          # - If no end year was given, increase the end year to put the end
          #   after the start
          # - If a year was specified for both, just swap the start and end
          if start_year_was_amb:
              start.year = end.year - 1
          elif end_year_was_amb:
              end.year = start.year + 1
          else:
              start, end = end, start
  
      start = floor(start)
      end = ceil(end)
  
      if start.date() == end.date() and start.time() > end.time():
          # If the start and end are on the same day, but the start time
          # is after the end time, move the end time to the next day
          end += timedelta(days=1)
  
      return timespan(start, end)
  
imports: import calendar
  import copy
  from datetime import date, datetime, timedelta
  from whoosh.compat import iteritems
label_desc: Use image node_id 4 for calling the timespan obj's underlying member method code with example usage: obj.disambiguated(basedate, debug) and returns: timespan