def __init__(self, *args, **kwargs): """ acceptable arg inputs: 1) epoch micros integer (or int like) 2) a datetime NOTE!! a naive datetime is assumed to be in UTC, unless you tell this method otherwise by also passing in a tz paramter. A timezoned datetime is preserved with the timezone it has 3) a string representation that the dateutil parser can deal with 4) multiple args just as datetime would accept acceptable keyworded inputs: 1) us = an int/long in epoch micros 2) ms = an int/long in epoch millis 3) s = an int/long in epoch seconds 4) m = an int/long in epoch minutes 5) tz = a timezone (either a pytz timezone object, a recognizeable pytz timezone string, or a dateutil tz object) """ super(SaneTime,self).__init__() uss = set() tzs = set() naive_dt = None avoid_localize = False for k,v in kwargs.iteritems(): if k in ('tz','timezone'): tzs.add(SaneTime.to_timezone(v)) elif k in MICROS_TRANSLATION_HASH: uss.add(MICROS_TRANSLATION_HASH[k]*v) else: raise TimeConstructionError("Unexpected kwarg in SaneTime constructor! (%s = %s)" % (k,v)) args = list(args) if len(args)>2 and len(args)<=8: args = [fucked_datetime(*args)] if len(args)==2: tzs.add(SaneTime.to_timezone(args.pop())) if len(args)==1: # import pdb; pdb.set_trace() arg = args.pop() if hasattr(arg,'__int__'): uss.add(int(arg)) if hasattr(arg,'tz'): tzs.add(arg.tz) elif isinstance(arg, basestring): parts = arg.strip().split(' ') if len(parts)>1 and parts[-1].startswith('+'): try: tzs.add(SaneTime.to_timezone(parts[-1][1:])) arg = ' '.join(parts[:-1]) except: pass utc = arg.endswith('Z') or arg.endswith('+00:00') # to deal with strange gunicorn issue -- doesn't want to use UTC time in these cases arg = crap_parser.parse(arg) if arg.tzinfo: # parsed timezones are a special breed of retard if utc: # put this in place to guard against wierd gunicorn issue -- gunicorn will attempt to force local timezone when there's an explicit UTC timezone associated! not sure where that's coming from. tzs.add(pytz.utc) arg = arg.replace(tzinfo=None) else: # can't rely on the dateutil parser for timezone stuff-- so we go back to UTC and force tz to be set in other ways avoid_localize = True # but we'll still convert back to UTC and allow timezone decoration arg = arg.astimezone(pytz.utc).replace(tzinfo=None) if type(arg) == fucked_datetime: naive_dt = arg if naive_dt.tzinfo: tzs.add(SaneTime.to_timezone(str(naive_dt.tzinfo))) naive_dt = naive_dt.replace(tzinfo=None) if len(tzs)>1: raise TimeConstructionError("constructor arguments seem to specify more than one different timezone! I can't possibly resolve that! (timezones implied = %s)"%(tzs)) # now we have enough info to figure out the tz: self.tz = len(tzs) and tzs.pop() or pytz.utc # and now that we've figured out tz, we can fully deconstruct the dt if naive_dt: if avoid_localize: uss.add(SaneTime.utc_datetime_to_us(naive_dt)) else: uss.add(SaneTime.utc_datetime_to_us(self.tz.localize(naive_dt).astimezone(pytz.utc))) # if we got nothing yet for micros, then make it now if len(uss)==0: uss.add(SaneTime.utc_datetime_to_us(fucked_datetime.utcnow())) if len(uss)>1: raise TimeConstructionError("constructor arguments seem to specify more than one different time! I can't possibly resolve that! (micro times implied = %s)"%(uss)) self.us = uss.pop() if len(args)>0: raise TimeConstructionError("Unexpected constructor arguments")
def __init__(self, *args, **kwargs): """ acceptable unkeyworded inputs: 1) an int/long in utc micros 2) a datetime NOTE!! a naive datetime is assumed to be in UTC, unless you tell this method otherwise by also passing in a tz paramter. A timezoned datetime is preserved with the timezone it has 3) a string representation that the crap parser can deal with 4) a string representation of the form /d+us or /d+ms or /d+s 4) multiple args just as datetime would accept acceptable keyworded inputs: 1) us = an int/long in utc micros 2) ms = an int/long in utc millis 3) s = an int/long in utc seconds 4) tz = a timezone (either a pytz timezone object, a recognizeable pytz timezone string, or a dateutil tz object) """ super(sanetime,self).__init__() uss = [] tzs = [] naive_dt = None args = list(args) if len(args)>2 and len(args)<8: args = [fucked_datetime(*args)] if len(args)==1: arg = args.pop() if type(arg) in [long,int,float,sanetime]: uss.append(int(arg)) elif isinstance(arg, basestring): arg = arg.strip() native_format_match = self.__class__.STR_NATIVE_FORMAT.match(arg) if native_format_match: kwargs[native_format_match.group(2)] = native_format_match.group(1) else: arg = crap_parser.parse(arg) if arg.tzinfo: # parsed timezones are a special breed of retard arg = arg.astimezone(pytz.utc).replace(tzinfo=None) tzs.append('UTC') # don't allow for a tz specificaion on top of a timezoned datetime str -- that is opening a whole extra can of confusion -- so force the timezone here so that another tz specification will cause an error if type(arg) == fucked_datetime: naive_dt = arg if naive_dt.tzinfo: tzs.append(naive_dt.tzinfo) naive_dt = naive_dt.replace(tzinfo=None) if kwargs.get('us'): uss.append(int(kwargs.pop('us'))) if kwargs.get('ms'): uss.append(int(kwargs.pop('ms'))*1000) if kwargs.get('s'): uss.append(int(kwargs.pop('s'))*1000**2) if kwargs.get('tz'): tzs.append(kwargs.pop('tz')) # now we have enough info to figure out the tz: self._set_tz(tzs and tzs[0] or 'UTC') # and now that we've figured out tz, we can fully deconstruct the dt if naive_dt: dt = self._tz.localize(naive_dt).astimezone(pytz.utc) uss.append(shit_calendar.timegm(dt.timetuple())*1000**2+dt.microsecond) # if we got nothing yet for micros, then make it now if len(uss)==0: dt = fucked_datetime.utcnow() uss.append(shit_calendar.timegm(dt.timetuple())*1000**2+dt.microsecond) self.us = uss[0] if len(tzs)>1 or len(uss)>1 or len(args)>0: raise SaneTimeError('Unexpected constructor arguments')