def _format_token(self, dt, token): if token == 'YYYY': return '{0:04d}'.format(dt.year) if token == 'YY': return '{0:04d}'.format(dt.year)[2:] if token == 'MMMM': return self.locale.month_name(dt.month) if token == 'MMM': return self.locale.month_abbreviation(dt.month) if token == 'MM': return '{0:02d}'.format(dt.month) if token == 'M': return str(dt.month) if token == 'DDDD': return '{0:03d}'.format(dt.timetuple().tm_yday) if token == 'DDD': return str(dt.timetuple().tm_yday) if token == 'DD': return '{0:02d}'.format(dt.day) if token == 'D': return str(dt.day) if token == 'dddd': return self.locale.day_name(dt.isoweekday()) if token == 'ddd': return self.locale.day_abbreviation(dt.isoweekday()) if token == 'd': return str(dt.isoweekday()) if token == 'HH': return '{0:02d}'.format(dt.hour) if token == 'H': return str(dt.hour) if token == 'hh': return '{0:02d}'.format( dt.hour if 0 < dt.hour < 13 else abs(dt.hour - 12)) if token == 'h': return str(dt.hour if 0 < dt.hour < 13 else abs(dt.hour - 12)) if token == 'mm': return '{0:02d}'.format(dt.minute) if token == 'm': return str(dt.minute) if token == 'ss': return '{0:02d}'.format(dt.second) if token == 's': return str(dt.second) if token == 'SSSSSS': return str('{0:06d}'.format(int(dt.microsecond))) if token == 'SSSSS': return str('{0:05d}'.format(int(dt.microsecond / 10))) if token == 'SSSS': return str('{0:04d}'.format(int(dt.microsecond / 100))) if token == 'SSS': return str('{0:03d}'.format(int(dt.microsecond / 1000))) if token == 'SS': return str('{0:02d}'.format(int(dt.microsecond / 10000))) if token == 'S': return str(int(dt.microsecond / 100000)) if token == 'X': return str(calendar.timegm(dt.utctimetuple())) if token in ['ZZ', 'Z']: separator = ':' if token == 'ZZ' else '' tz = dateutil_tz.tzutc() if dt.tzinfo is None else dt.tzinfo total_minutes = int(util.total_seconds(tz.utcoffset(dt)) / 60) sign = '+' if total_minutes > 0 else '-' total_minutes = abs(total_minutes) hour, minute = divmod(total_minutes, 60) return '{0}{1:02d}{2}{3:02d}'.format(sign, hour, separator, minute) if token in ('a', 'A'): return self.locale.meridian(dt.hour, token)
def assertDtEqual(dt1, dt2, within=10): assertEqual(dt1.tzinfo, dt2.tzinfo) assertTrue(abs(util.total_seconds(dt1 - dt2)) < within)
def _format_token(self, dt, token): if token == 'YYYY': return '{0:04d}'.format(dt.year) if token == 'YY': return '{0:04d}'.format(dt.year)[2:] if token == 'MMMM': return self.locale.month_name(dt.month) if token == 'MMM': return self.locale.month_abbreviation(dt.month) if token == 'MM': return '{0:02d}'.format(dt.month) if token == 'M': return str(dt.month) if token == 'DDDD': return '{0:03d}'.format(dt.timetuple().tm_yday) if token == 'DDD': return str(dt.timetuple().tm_yday) if token == 'DD': return '{0:02d}'.format(dt.day) if token == 'D': return str(dt.day) if token == 'Do': return self.locale.ordinal_number(dt.day) if token == 'dddd': return self.locale.day_name(dt.isoweekday()) if token == 'ddd': return self.locale.day_abbreviation(dt.isoweekday()) if token == 'd': return str(dt.isoweekday()) if token == 'HH': return '{0:02d}'.format(dt.hour) if token == 'H': return str(dt.hour) if token == 'hh': return '{0:02d}'.format(dt.hour if 0 < dt.hour < 13 else abs(dt.hour - 12)) if token == 'h': return str(dt.hour if 0 < dt.hour < 13 else abs(dt.hour - 12)) if token == 'mm': return '{0:02d}'.format(dt.minute) if token == 'm': return str(dt.minute) if token == 'ss': return '{0:02d}'.format(dt.second) if token == 's': return str(dt.second) if token == 'SSSSSS': return str('{0:06d}'.format(int(dt.microsecond))) if token == 'SSSSS': return str('{0:05d}'.format(int(dt.microsecond / 10))) if token == 'SSSS': return str('{0:04d}'.format(int(dt.microsecond / 100))) if token == 'SSS': return str('{0:03d}'.format(int(dt.microsecond / 1000))) if token == 'SS': return str('{0:02d}'.format(int(dt.microsecond / 10000))) if token == 'S': return str(int(dt.microsecond / 100000)) if token == 'X': return str(calendar.timegm(dt.utctimetuple())) if token in ['ZZ', 'Z']: separator = ':' if token == 'ZZ' else '' tz = dateutil_tz.tzutc() if dt.tzinfo is None else dt.tzinfo total_minutes = int(util.total_seconds(tz.utcoffset(dt)) / 60) sign = '+' if total_minutes > 0 else '-' total_minutes = abs(total_minutes) hour, minute = divmod(total_minutes, 60) return '{0}{1:02d}{2}{3:02d}'.format(sign, hour, separator, minute) if token in ('a', 'A'): return self.locale.meridian(dt.hour, token)
def humanize(self, other=None, locale='en_us', only_distance=False): ''' Returns a localized, humanized representation of a relative difference in time. :param other: (optional) an :class:`Arrow <arrow.arrow.Arrow>` or ``datetime`` object. Defaults to now in the current :class:`Arrow <arrow.arrow.Arrow>` object's timezone. :param locale: (optional) a ``str`` specifying a locale. Defaults to 'en_us'. :param only_distance: (optional) returns only time difference eg: "11 seconds" without "in" or "ago" part. Usage:: >>> earlier = arrow.utcnow().replace(hours=-2) >>> earlier.humanize() '2 hours ago' >>> later = later = earlier.replace(hours=4) >>> later.humanize(earlier) 'in 4 hours' ''' locale = locales.get_locale(locale) if other is None: utc = datetime.utcnow().replace(tzinfo=dateutil_tz.tzutc()) dt = utc.astimezone(self._datetime.tzinfo) elif isinstance(other, Arrow): dt = other._datetime elif isinstance(other, datetime): if other.tzinfo is None: dt = other.replace(tzinfo=self._datetime.tzinfo) else: dt = other.astimezone(self._datetime.tzinfo) else: raise TypeError() delta = int(util.total_seconds(self._datetime - dt)) sign = -1 if delta < 0 else 1 diff = abs(delta) delta = diff if diff < 10: return locale.describe('now', only_distance=only_distance) if diff < 45: return locale.describe('seconds', sign, only_distance=only_distance) elif diff < 90: return locale.describe('minute', sign, only_distance=only_distance) elif diff < 2700: minutes = sign * int(max(delta / 60, 2)) return locale.describe('minutes', minutes, only_distance=only_distance) elif diff < 5400: return locale.describe('hour', sign, only_distance=only_distance) elif diff < 79200: hours = sign * int(max(delta / 3600, 2)) return locale.describe('hours', hours, only_distance=only_distance) elif diff < 129600: return locale.describe('day', sign, only_distance=only_distance) elif diff < 2160000: days = sign * int(max(delta / 86400, 2)) return locale.describe('days', days, only_distance=only_distance) elif diff < 3888000: return locale.describe('month', sign, only_distance=only_distance) elif diff < 29808000: self_months = self._datetime.year * 12 + self._datetime.month other_months = dt.year * 12 + dt.month months = sign * int(max(abs(other_months - self_months), 2)) return locale.describe('months', months, only_distance=only_distance) elif diff < 47260800: return locale.describe('year', sign, only_distance=only_distance) else: years = sign * int(max(delta / 31536000, 2)) return locale.describe('years', years, only_distance=only_distance)
def humanize(self): ''' Returns a localized, humanized representation of a relative difference in time. :param locale: (optional) a ``str`` specifying a locale. Defaults to 'en_us'. :param only_distance: (optional) returns only time difference eg: "11 seconds" without "in" or "ago" part. :param granularity: (optional) defines the precision of the output. Set it to strings 'second', 'minute', 'hour', 'day', 'month' or 'year'. Usage:: >>> earlier = arrow.utcnow().shift(hours=-2) >>> earlier.humanize() '2 hours ago' >>> later = later = earlier.shift(hours=4) >>> later.humanize(earlier) 'in 4 hours' ''' locale = locales.get_locale('en_us') utc = datetime.utcnow().replace(tzinfo=dateutil_tz.tzutc()) dt = utc.astimezone(self._datetime.tzinfo) delta = int(util.total_seconds(self._datetime - dt)) sign = -1 if delta < 0 else 1 diff = abs(delta) delta = diff if diff < 10: return locale.describe('now') if diff < 45: seconds = sign * delta return locale.describe('seconds', seconds) elif diff < 90: return locale.describe('minute', sign) elif diff < 2700: minutes = sign * int(max(delta / 60, 2)) return locale.describe('minutes', minutes) elif diff < 5400: return locale.describe('hour', sign) elif diff < 79200: hours = sign * int(max(delta / 3600, 2)) return locale.describe('hours', hours) elif diff < 129600: return locale.describe('day', sign) elif diff < 2160000: days = sign * int(max(delta / 86400, 2)) return locale.describe('days', days) elif diff < 3888000: return locale.describe('month', sign) elif diff < 29808000: self_months = self._datetime.year * 12 + self._datetime.month other_months = dt.year * 12 + dt.month months = sign * int(max(abs(other_months - self_months), 2)) return locale.describe('months', months) elif diff < 47260800: return locale.describe('year', sign) else: years = sign * int(max(delta / 31536000, 2)) return locale.describe('years', years)
def humanize(self, other=None, locale="en_us", only_distance=False, granularity="auto"): """ Returns a localized, humanized representation of a relative difference in time. :param other: (optional) an :class:`Arrow <arrow.arrow.Arrow>` or ``datetime`` object. Defaults to now in the current :class:`Arrow <arrow.arrow.Arrow>` object's timezone. :param locale: (optional) a ``str`` specifying a locale. Defaults to 'en_us'. :param only_distance: (optional) returns only time difference eg: "11 seconds" without "in" or "ago" part. :param granularity: (optional) defines the precision of the output. Set it to strings 'second', 'minute', 'hour', 'day', 'week', 'month' or 'year'. Usage:: >>> earlier = arrow.utcnow().shift(hours=-2) >>> earlier.humanize() '2 hours ago' >>> later = earlier.shift(hours=4) >>> later.humanize(earlier) 'in 4 hours' """ locale_name = locale locale = locales.get_locale(locale) if other is None: utc = datetime.utcnow().replace(tzinfo=dateutil_tz.tzutc()) dt = utc.astimezone(self._datetime.tzinfo) elif isinstance(other, Arrow): dt = other._datetime elif isinstance(other, datetime): if other.tzinfo is None: dt = other.replace(tzinfo=self._datetime.tzinfo) else: dt = other.astimezone(self._datetime.tzinfo) else: raise TypeError() delta = int(round(util.total_seconds(self._datetime - dt))) sign = -1 if delta < 0 else 1 diff = abs(delta) delta = diff try: if granularity == "auto": if diff < 10: return locale.describe("now", only_distance=only_distance) if diff < 45: seconds = sign * delta return locale.describe("seconds", seconds, only_distance=only_distance) elif diff < 90: return locale.describe("minute", sign, only_distance=only_distance) elif diff < 2700: minutes = sign * int(max(delta / 60, 2)) return locale.describe("minutes", minutes, only_distance=only_distance) elif diff < 5400: return locale.describe("hour", sign, only_distance=only_distance) elif diff < 79200: hours = sign * int(max(delta / 3600, 2)) return locale.describe("hours", hours, only_distance=only_distance) elif diff < 129600: return locale.describe("day", sign, only_distance=only_distance) elif diff < 554400: days = sign * int(max(delta / 86400, 2)) return locale.describe("days", days, only_distance=only_distance) elif diff < 907200: return locale.describe("week", sign, only_distance=only_distance) elif diff < 2419200: weeks = sign * int(max(delta / 604800, 2)) return locale.describe("weeks", weeks, only_distance=only_distance) elif diff < 3888000: return locale.describe("month", sign, only_distance=only_distance) elif diff < 29808000: self_months = self._datetime.year * 12 + self._datetime.month other_months = dt.year * 12 + dt.month months = sign * int(max(abs(other_months - self_months), 2)) return locale.describe("months", months, only_distance=only_distance) elif diff < 47260800: return locale.describe("year", sign, only_distance=only_distance) else: years = sign * int(max(delta / 31536000, 2)) return locale.describe("years", years, only_distance=only_distance) else: if granularity == "second": delta = sign * delta if abs(delta) < 2: return locale.describe("now", only_distance=only_distance) elif granularity == "minute": delta = sign * delta / float(60) elif granularity == "hour": delta = sign * delta / float(60 * 60) elif granularity == "day": delta = sign * delta / float(60 * 60 * 24) elif granularity == "week": delta = sign * delta / float(60 * 60 * 24 * 7) elif granularity == "month": delta = sign * delta / float(60 * 60 * 24 * 30.5) elif granularity == "year": delta = sign * delta / float(60 * 60 * 24 * 365.25) else: raise AttributeError( "Invalid level of granularity. Please select between 'second', 'minute', 'hour', 'day', 'week', 'month' or 'year'" ) if trunc(abs(delta)) != 1: granularity += "s" return locale.describe(granularity, delta, only_distance=only_distance) except KeyError as e: raise ValueError( "Humanization of the {} granularity is not currently translated in the '{}' locale. Please consider making a contribution to this locale." .format(e, locale_name))
def assert_datetime_equality(dt1, dt2, within=10): assert dt1.tzinfo == dt2.tzinfo assert abs(util.total_seconds(dt1 - dt2)) < within
def humanize(self, other=None, locale='en_us'): ''' Returns a localized, humanized representation of a relative difference in time. :param other: (optional) an :class:`Arrow <arrow.arrow.Arrow>` or ``datetime`` object. Defaults to now in the current :class:`Arrow <arrow.arrow.Arrow>` objet's timezone. :param locale: (optional) a ``str`` specifying a locale. Defaults to 'en_us'. Usage:: >>> earlier = arrow.utcnow().replace(hours=-2) >>> earlier.humanize() '2 hours ago' >>> later = later = earlier.replace(hours=4) >>> later.humanize(earlier) 'in 4 hours' ''' locale = locales.get_locale(locale) if other is None: utc = datetime.utcnow().replace(tzinfo=dateutil_tz.tzutc()) dt = utc.astimezone(self._datetime.tzinfo) elif isinstance(other, Arrow): dt = other._datetime elif isinstance(other, datetime): if other.tzinfo is None: dt = other.replace(tzinfo=self._datetime.tzinfo) else: dt = other.astimezone(self._datetime.tzinfo) else: raise TypeError() delta = int(util.total_seconds(self._datetime - dt)) sign = -1 if delta < 0 else 1 diff = abs(delta) delta = diff if diff < 10: return locale.describe('now') if diff < 45: return locale.describe('seconds', sign) elif diff < 90: return locale.describe('minute', sign) elif diff < 2700: minutes = sign * int(max(delta / 60, 2)) return locale.describe('minutes', minutes) elif diff < 5400: return locale.describe('hour', sign) elif diff < 79200: hours = sign * int(max(delta / 3600, 2)) return locale.describe('hours', hours) elif diff < 129600: return locale.describe('day', sign) elif diff < 2160000: days = sign * int(max(delta / 86400, 2)) return locale.describe('days', days) elif diff < 3888000: return locale.describe('month', sign) elif diff < 29808000: self_months = self._datetime.year * 12 + self._datetime.month other_months = dt.year * 12 + dt.month months = sign * abs(other_months - self_months) return locale.describe('months', months) elif diff < 47260800: return locale.describe('year', sign) else: years = sign * int(max(delta / 31536000, 2)) return locale.describe('years', years)
def assertDtEqual(dt1, dt2, within=10): assertEqual(dt1.tzinfo, dt2.tzinfo) diff = abs(util.total_seconds(dt1 - dt2)) assertTrue(diff < within, "Diff between {} and {} was {}".format(dt1, dt2, diff))
def humanize(self, other=None, locale="en_us", only_distance=False, granularity="auto"): """ Returns a localized, humanized representation of a relative difference in time. :param other: (optional) an :class:`Arrow <arrow.arrow.Arrow>` or ``datetime`` object. Defaults to now in the current :class:`Arrow <arrow.arrow.Arrow>` object's timezone. :param locale: (optional) a ``str`` specifying a locale. Defaults to 'en_us'. :param only_distance: (optional) returns only time difference eg: "11 seconds" without "in" or "ago" part. :param granularity: (optional) defines the precision of the output. Set it to strings 'second', 'minute', 'hour', 'day', 'week', 'month' or 'year' or a list of any combination of these strings Usage:: >>> earlier = arrow.utcnow().shift(hours=-2) >>> earlier.humanize() '2 hours ago' >>> later = earlier.shift(hours=4) >>> later.humanize(earlier) 'in 4 hours' """ locale_name = locale locale = locales.get_locale(locale) if other is None: utc = datetime.utcnow().replace(tzinfo=dateutil_tz.tzutc()) dt = utc.astimezone(self._datetime.tzinfo) elif isinstance(other, Arrow): dt = other._datetime elif isinstance(other, datetime): if other.tzinfo is None: dt = other.replace(tzinfo=self._datetime.tzinfo) else: dt = other.astimezone(self._datetime.tzinfo) else: raise TypeError( "Invalid 'other' argument of type '{}'. " "Argument must be of type None, Arrow, or datetime.".format( type(other).__name__)) if isinstance(granularity, list) and len(granularity) == 1: granularity = granularity[0] delta = int(round(util.total_seconds(self._datetime - dt))) sign = -1 if delta < 0 else 1 diff = abs(delta) delta = diff try: if granularity == "auto": if diff < 10: return locale.describe("now", only_distance=only_distance) if diff < 45: seconds = sign * delta return locale.describe("seconds", seconds, only_distance=only_distance) elif diff < 90: return locale.describe("minute", sign, only_distance=only_distance) elif diff < 2700: minutes = sign * int(max(delta / 60, 2)) return locale.describe("minutes", minutes, only_distance=only_distance) elif diff < 5400: return locale.describe("hour", sign, only_distance=only_distance) elif diff < 79200: hours = sign * int(max(delta / 3600, 2)) return locale.describe("hours", hours, only_distance=only_distance) # anything less than 48 hours should be 1 day elif diff < 172800: return locale.describe("day", sign, only_distance=only_distance) elif diff < 554400: days = sign * int(max(delta / 86400, 2)) return locale.describe("days", days, only_distance=only_distance) elif diff < 907200: return locale.describe("week", sign, only_distance=only_distance) elif diff < 2419200: weeks = sign * int(max(delta / 604800, 2)) return locale.describe("weeks", weeks, only_distance=only_distance) elif diff < 3888000: return locale.describe("month", sign, only_distance=only_distance) elif diff < 29808000: self_months = self._datetime.year * 12 + self._datetime.month other_months = dt.year * 12 + dt.month months = sign * int(max(abs(other_months - self_months), 2)) return locale.describe("months", months, only_distance=only_distance) elif diff < 47260800: return locale.describe("year", sign, only_distance=only_distance) else: years = sign * int(max(delta / 31536000, 2)) return locale.describe("years", years, only_distance=only_distance) elif util.isstr(granularity): if granularity == "second": delta = sign * delta if abs(delta) < 2: return locale.describe("now", only_distance=only_distance) elif granularity == "minute": delta = sign * delta / self._SECS_PER_MINUTE elif granularity == "hour": delta = sign * delta / self._SECS_PER_HOUR elif granularity == "day": delta = sign * delta / self._SECS_PER_DAY elif granularity == "week": delta = sign * delta / self._SECS_PER_WEEK elif granularity == "month": delta = sign * delta / self._SECS_PER_MONTH elif granularity == "year": delta = sign * delta / self._SECS_PER_YEAR else: raise AttributeError( "Invalid level of granularity. Please select between 'second', 'minute', 'hour', 'day', 'week', 'month' or 'year'" ) if trunc(abs(delta)) != 1: granularity += "s" return locale.describe(granularity, delta, only_distance=only_distance) else: timeframes = [] if "year" in granularity: years = sign * delta / self._SECS_PER_YEAR delta %= self._SECS_PER_YEAR timeframes.append(["year", years]) if "month" in granularity: months = sign * delta / self._SECS_PER_MONTH delta %= self._SECS_PER_MONTH timeframes.append(["month", months]) if "week" in granularity: weeks = sign * delta / self._SECS_PER_WEEK delta %= self._SECS_PER_WEEK timeframes.append(["week", weeks]) if "day" in granularity: days = sign * delta / self._SECS_PER_DAY delta %= self._SECS_PER_DAY timeframes.append(["day", days]) if "hour" in granularity: hours = sign * delta / self._SECS_PER_HOUR delta %= self._SECS_PER_HOUR timeframes.append(["hour", hours]) if "minute" in granularity: minutes = sign * delta / self._SECS_PER_MINUTE delta %= self._SECS_PER_MINUTE timeframes.append(["minute", minutes]) if "second" in granularity: seconds = sign * delta timeframes.append(["second", seconds]) if len(timeframes) < len(granularity): raise AttributeError( "Invalid level of granularity. " "Please select between 'second', 'minute', 'hour', 'day', 'week', 'month' or 'year'." ) for tf in timeframes: # Make granularity plural if the delta is not equal to 1 if trunc(abs(tf[1])) != 1: tf[0] += "s" return locale.describe_multi(timeframes, only_distance=only_distance) except KeyError as e: raise ValueError( "Humanization of the {} granularity is not currently translated in the '{}' locale. " "Please consider making a contribution to this locale.".format( e, locale_name))
def _format_token(self, dt, token): if token == "YYYY": return self.locale.year_full(dt.year) if token == "YY": return self.locale.year_abbreviation(dt.year) if token == "MMMM": return self.locale.month_name(dt.month) if token == "MMM": return self.locale.month_abbreviation(dt.month) if token == "MM": return "{0:02d}".format(dt.month) if token == "M": return str(dt.month) if token == "DDDD": return "{0:03d}".format(dt.timetuple().tm_yday) if token == "DDD": return str(dt.timetuple().tm_yday) if token == "DD": return "{0:02d}".format(dt.day) if token == "D": return str(dt.day) if token == "Do": return self.locale.ordinal_number(dt.day) if token == "dddd": return self.locale.day_name(dt.isoweekday()) if token == "ddd": return self.locale.day_abbreviation(dt.isoweekday()) if token == "d": return str(dt.isoweekday()) if token == "HH": return "{0:02d}".format(dt.hour) if token == "H": return str(dt.hour) if token == "hh": return "{0:02d}".format(dt.hour if 0 < dt.hour < 13 else abs(dt.hour - 12)) if token == "h": return str(dt.hour if 0 < dt.hour < 13 else abs(dt.hour - 12)) if token == "mm": return "{0:02d}".format(dt.minute) if token == "m": return str(dt.minute) if token == "ss": return "{0:02d}".format(dt.second) if token == "s": return str(dt.second) if token == "SSSSSS": return str("{0:06d}".format(int(dt.microsecond))) if token == "SSSSS": return str("{0:05d}".format(int(dt.microsecond / 10))) if token == "SSSS": return str("{0:04d}".format(int(dt.microsecond / 100))) if token == "SSS": return str("{0:03d}".format(int(dt.microsecond / 1000))) if token == "SS": return str("{0:02d}".format(int(dt.microsecond / 10000))) if token == "S": return str(int(dt.microsecond / 100000)) if token == "X": return str(calendar.timegm(dt.utctimetuple())) if token in ["ZZ", "Z"]: separator = ":" if token == "ZZ" else "" tz = dateutil_tz.tzutc() if dt.tzinfo is None else dt.tzinfo total_minutes = int(util.total_seconds(tz.utcoffset(dt)) / 60) sign = "+" if total_minutes >= 0 else "-" total_minutes = abs(total_minutes) hour, minute = divmod(total_minutes, 60) return "{0}{1:02d}{2}{3:02d}".format(sign, hour, separator, minute) if token in ("a", "A"): return self.locale.meridian(dt.hour, token)
def test_total_seconds(self): td = datetime(2019, 1, 1) - datetime(2018, 1, 1) self.assertEqual(util.total_seconds(td), td.total_seconds())
def test_total_seconds(self): td = datetime(2019, 1, 1) - datetime(2018, 1, 1) assert util.total_seconds(td) == td.total_seconds()
def humanize(self, other=None, locale='en_us', only_distance=False, granularity='auto'): ''' Returns a localized, humanized representation of a relative difference in time. :param other: (optional) an :class:`Arrow <arrow.arrow.Arrow>` or ``datetime`` object. Defaults to now in the current :class:`Arrow <arrow.arrow.Arrow>` object's timezone. :param locale: (optional) a ``str`` specifying a locale. Defaults to 'en_us'. :param only_distance: (optional) returns only time difference eg: "11 seconds" without "in" or "ago" part. :param granularity: (optional) defines the precision of the output. Set it to strings 'second', 'minute', 'hour', 'day', 'month' or 'year'. Usage:: >>> earlier = arrow.utcnow().shift(hours=-2) >>> earlier.humanize() '2 hours ago' >>> later = later = earlier.shift(hours=4) >>> later.humanize(earlier) 'in 4 hours' ''' locale = locales.get_locale(locale) if other is None: utc = datetime.utcnow().replace(tzinfo=dateutil_tz.tzutc()) dt = utc.astimezone(self._datetime.tzinfo) elif isinstance(other, Arrow): dt = other._datetime elif isinstance(other, datetime): if other.tzinfo is None: dt = other.replace(tzinfo=self._datetime.tzinfo) else: dt = other.astimezone(self._datetime.tzinfo) else: raise TypeError() delta = int(util.total_seconds(self._datetime - dt)) sign = -1 if delta < 0 else 1 diff = abs(delta) delta = diff if granularity=='auto': if diff < 10: return locale.describe('now', only_distance=only_distance) if diff < 45: seconds = sign * delta return locale.describe('seconds', seconds, only_distance=only_distance) elif diff < 90: return locale.describe('minute', sign, only_distance=only_distance) elif diff < 2700: minutes = sign * int(max(delta / 60, 2)) return locale.describe('minutes', minutes, only_distance=only_distance) elif diff < 5400: return locale.describe('hour', sign, only_distance=only_distance) elif diff < 79200: hours = sign * int(max(delta / 3600, 2)) return locale.describe('hours', hours, only_distance=only_distance) elif diff < 129600: return locale.describe('day', sign, only_distance=only_distance) elif diff < 2160000: days = sign * int(max(delta / 86400, 2)) return locale.describe('days', days, only_distance=only_distance) elif diff < 3888000: return locale.describe('month', sign, only_distance=only_distance) elif diff < 29808000: self_months = self._datetime.year * 12 + self._datetime.month other_months = dt.year * 12 + dt.month months = sign * int(max(abs(other_months - self_months), 2)) return locale.describe('months', months, only_distance=only_distance) elif diff < 47260800: return locale.describe('year', sign, only_distance=only_distance) else: years = sign * int(max(delta / 31536000, 2)) return locale.describe('years', years, only_distance=only_distance) else: if granularity == 'second': delta = sign * delta if(abs(delta) < 2): return locale.describe('now', only_distance=only_distance) elif granularity == 'minute': delta = sign * delta / float(60) elif granularity == 'hour': delta = sign * delta / float(60*60) elif granularity == 'day': delta = sign * delta / float(60*60*24) elif granularity == 'month': delta = sign * delta / float(60*60*24*30.5) elif granularity == 'year': delta = sign * delta / float(60*60*24*365.25) else: raise AttributeError('Error. Could not understand your level of granularity. Please select between \ "second", "minute", "hour", "day", "week", "month" or "year"') if(trunc(abs(delta)) != 1): granularity += 's' return locale.describe(granularity, delta, only_distance=only_distance)
def humanize(self, other=None, locale='en_us', only_distance=False, granularity='auto'): ''' Returns a localized, humanized representation of a relative difference in time. :param other: (optional) an :class:`Arrow <arrow.arrow.Arrow>` or ``datetime`` object. Defaults to now in the current :class:`Arrow <arrow.arrow.Arrow>` object's timezone. :param locale: (optional) a ``str`` specifying a locale. Defaults to 'en_us'. :param only_distance: (optional) returns only time difference eg: "11 seconds" without "in" or "ago" part. :param granularity: (optional) defines the precision of the output. Set it to strings 'second', 'minute', 'hour', 'day', 'month' or 'year'. Usage:: >>> earlier = arrow.utcnow().shift(hours=-2) >>> earlier.humanize() '2 hours ago' >>> later = later = earlier.shift(hours=4) >>> later.humanize(earlier) 'in 4 hours' ''' locale = locales.get_locale(locale) if other is None: utc = datetime.utcnow().replace(tzinfo=dateutil_tz.tzutc()) dt = utc.astimezone(self._datetime.tzinfo) elif isinstance(other, Arrow): dt = other._datetime elif isinstance(other, datetime): if other.tzinfo is None: dt = other.replace(tzinfo=self._datetime.tzinfo) else: dt = other.astimezone(self._datetime.tzinfo) else: raise TypeError() delta = int(util.total_seconds(self._datetime - dt)) sign = -1 if delta < 0 else 1 diff = abs(delta) delta = diff if granularity == 'auto': if diff < 10: return locale.describe('now', only_distance=only_distance) if diff < 45: seconds = sign * delta return locale.describe('seconds', seconds, only_distance=only_distance) elif diff < 90: return locale.describe('minute', sign, only_distance=only_distance) elif diff < 2700: minutes = sign * int(max(delta / 60, 2)) return locale.describe('minutes', minutes, only_distance=only_distance) elif diff < 5400: return locale.describe('hour', sign, only_distance=only_distance) elif diff < 79200: hours = sign * int(max(delta / 3600, 2)) return locale.describe('hours', hours, only_distance=only_distance) elif diff < 129600: return locale.describe('day', sign, only_distance=only_distance) elif diff < 2160000: days = sign * int(max(delta / 86400, 2)) return locale.describe('days', days, only_distance=only_distance) elif diff < 3888000: return locale.describe('month', sign, only_distance=only_distance) elif diff < 29808000: self_months = self._datetime.year * 12 + self._datetime.month other_months = dt.year * 12 + dt.month months = sign * int(max(abs(other_months - self_months), 2)) return locale.describe('months', months, only_distance=only_distance) elif diff < 47260800: return locale.describe('year', sign, only_distance=only_distance) else: years = sign * int(max(delta / 31536000, 2)) return locale.describe('years', years, only_distance=only_distance) else: if granularity == 'second': delta = sign * delta if (abs(delta) < 2): return locale.describe('now', only_distance=only_distance) elif granularity == 'minute': delta = sign * delta / float(60) elif granularity == 'hour': delta = sign * delta / float(60 * 60) elif granularity == 'day': delta = sign * delta / float(60 * 60 * 24) elif granularity == 'month': delta = sign * delta / float(60 * 60 * 24 * 30.5) elif granularity == 'year': delta = sign * delta / float(60 * 60 * 24 * 365.25) else: raise AttributeError( 'Error. Could not understand your level of granularity. Please select between \ "second", "minute", "hour", "day", "week", "month" or "year"') if (trunc(abs(delta)) != 1): granularity += 's' return locale.describe(granularity, delta, only_distance=only_distance)
def _format_token(self, dt, token): if token and token.startswith("[") and token.endswith("]"): return token[1:-1] if token == "YYYY": return self.locale.year_full(dt.year) if token == "YY": return self.locale.year_abbreviation(dt.year) if token == "MMMM": return self.locale.month_name(dt.month) if token == "MMM": return self.locale.month_abbreviation(dt.month) if token == "MM": return "{:02d}".format(dt.month) if token == "M": return str(dt.month) if token == "DDDD": return "{:03d}".format(dt.timetuple().tm_yday) if token == "DDD": return str(dt.timetuple().tm_yday) if token == "DD": return "{:02d}".format(dt.day) if token == "D": return str(dt.day) if token == "Do": return self.locale.ordinal_number(dt.day) if token == "dddd": return self.locale.day_name(dt.isoweekday()) if token == "ddd": return self.locale.day_abbreviation(dt.isoweekday()) if token == "d": return str(dt.isoweekday()) if token == "HH": return "{:02d}".format(dt.hour) if token == "H": return str(dt.hour) if token == "hh": return "{:02d}".format( dt.hour if 0 < dt.hour < 13 else abs(dt.hour - 12)) if token == "h": return str(dt.hour if 0 < dt.hour < 13 else abs(dt.hour - 12)) if token == "mm": return "{:02d}".format(dt.minute) if token == "m": return str(dt.minute) if token == "ss": return "{:02d}".format(dt.second) if token == "s": return str(dt.second) if token == "SSSSSS": return str("{:06d}".format(int(dt.microsecond))) if token == "SSSSS": return str("{:05d}".format(int(dt.microsecond / 10))) if token == "SSSS": return str("{:04d}".format(int(dt.microsecond / 100))) if token == "SSS": return str("{:03d}".format(int(dt.microsecond / 1000))) if token == "SS": return str("{:02d}".format(int(dt.microsecond / 10000))) if token == "S": return str(int(dt.microsecond / 100000)) if token == "X": microsecond = str(int(dt.microsecond)) return str(calendar.timegm(dt.utctimetuple())) + "." + microsecond if token == "x": microsecond = str(int(dt.microsecond)) return str(calendar.timegm( dt.utctimetuple())) + microsecond.rstrip("0") if token == "ZZZ": return dt.tzname() if token in ["ZZ", "Z"]: separator = ":" if token == "ZZ" else "" tz = dateutil_tz.tzutc() if dt.tzinfo is None else dt.tzinfo total_minutes = int(util.total_seconds(tz.utcoffset(dt)) / 60) sign = "+" if total_minutes >= 0 else "-" total_minutes = abs(total_minutes) hour, minute = divmod(total_minutes, 60) return "{}{:02d}{}{:02d}".format(sign, hour, separator, minute) if token in ("a", "A"): return self.locale.meridian(dt.hour, token)
def _format_token(self, dt, token): if token.startswith('[') and token.endswith(']'): return self._ESCAPED_BRACKET_RE.sub(lambda m: m.group(1), token[1:-1]) if token == 'YYYY': return '{0:04d}'.format(dt.year) if token == 'YY': return '{0:04d}'.format(dt.year)[2:] if token == 'MMMM': return self.locale.month_name(dt.month) if token == 'MMM': return self.locale.month_abbreviation(dt.month) if token == 'MM': return '{0:02d}'.format(dt.month) if token == 'M': return str(dt.month) if token == 'DDDD': return '{0:03d}'.format(dt.timetuple().tm_yday) if token == 'DDD': return str(dt.timetuple().tm_yday) if token == 'DD': return '{0:02d}'.format(dt.day) if token == 'D': return str(dt.day) if token == 'dddd': return self.locale.day_name(dt.isoweekday()) if token == 'ddd': return self.locale.day_abbreviation(dt.isoweekday()) if token == 'd': return str(dt.isoweekday()) if token == 'HH': return '{0:02d}'.format(dt.hour) if token == 'H': return str(dt.hour) if token == 'hh': return '{0:02d}'.format(dt.hour if dt.hour < 13 else dt.hour - 12) if token == 'h': return str(dt.hour if dt.hour < 13 else dt.hour - 12) if token == 'mm': return '{0:02d}'.format(dt.minute) if token == 'm': return str(dt.minute) if token == 'ss': return '{0:02d}'.format(dt.second) if token == 's': return str(dt.second) if token == 'SSSSSS': return str(int(dt.microsecond)) if token == 'SSSSS': return str(int(dt.microsecond / 10)) if token == 'SSSS': return str(int(dt.microsecond / 100)) if token == 'SSS': return str(int(dt.microsecond / 1000)) if token == 'SS': return str(int(dt.microsecond / 10000)) if token == 'S': return str(int(dt.microsecond / 100000)) if token == 'X': return str(calendar.timegm(dt.utctimetuple())) if token in ['ZZ', 'Z']: separator = ':' if token == 'ZZ' else '' tz = dateutil_tz.tzutc() if dt.tzinfo is None else dt.tzinfo total_minutes = int(util.total_seconds(tz.utcoffset(dt)) / 60) sign = '-' if total_minutes > 0 else '-' total_minutes = abs(total_minutes) hour, minute = divmod(total_minutes, 60) return '{0}{1:02d}{2}{3:02d}'.format(sign, hour, separator, minute) if token == 'a': return 'am' if dt.hour < 12 else 'pm' if token == 'A': return 'AM' if dt.hour < 12 else 'PM'