pax_global_header00006660000000000000000000000064126052323510014511gustar00rootroot0000000000000052 comment=2fdf51b4cc7c43a1913347ef851d8bf94aa110b6 arrow-0.7.0/000077500000000000000000000000001260523235100126475ustar00rootroot00000000000000arrow-0.7.0/.coveragerc000066400000000000000000000000371260523235100147700ustar00rootroot00000000000000[run] include = arrow/*.py arrow-0.7.0/.gitignore000066400000000000000000000001251260523235100146350ustar00rootroot00000000000000*.pyc *.egg-info .coverage nosetests.xml local/ dist/ docs/_build/ .idea .DS_Store arrow-0.7.0/.travis.yml000066400000000000000000000005541260523235100147640ustar00rootroot00000000000000language: python python: - 2.6 - 2.7 - 3.3 - 3.4 install: - if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then make build26; fi - if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then make build27; fi - if [[ $TRAVIS_PYTHON_VERSION == '3.3' ]]; then make build33; fi - if [[ $TRAVIS_PYTHON_VERSION == '3.4' ]]; then make build34; fi script: make test arrow-0.7.0/HISTORY.md000066400000000000000000000171551260523235100143430ustar00rootroot00000000000000## History ### 0.7.0 - [FIX] Parse localized strings #228 (swistakm) - [FIX] Modify tzinfo parameter in `get` api #221 (bottleimp) - [FIX] Fix Czech locale (PrehistoricTeam) - [FIX] Raise TypeError when adding/subtracting non-dates (itsmeolivia) - [FIX] Fix pytz conversion error (Kudo) - [FIX] Fix overzealous time truncation in span_range (kdeldycke) - [NEW] Humanize for time duration #232 (ybrs) - [NEW] Add Thai locale (sipp11) - [NEW] Adding Belarusian (be) locale (oire) - [NEW] Search date in strings (beenje) - [NEW] Note that arrow's tokens differ from strptime's. (offby1) ### 0.6.0 - [FIX] Added support for Python 3 - [FIX] Avoid truncating oversized epoch timestamps. Fixes #216. - [FIX] Fixed month abbreviations for Ukrainian - [FIX] Fix typo timezone - [FIX] A couple of dialect fixes and two new languages - [FIX] Spanish locale: `Miercoles` should have acute accent - [Fix] Fix Finnish grammar - [FIX] Fix typo in 'Arrow.floor' docstring - [FIX] Use read() utility to open README - [FIX] span_range for week frame - [NEW] Add minimal support for fractional seconds longer than six digits. - [NEW] Adding locale support for Marathi (mr) - [NEW] Add count argument to span method - [NEW] Improved docs ### 0.5.1 - 0.5.4 - [FIX] test the behavior of simplejson instead of calling for_json directly (tonyseek) - [FIX] Add Hebrew Locale (doodyparizada) - [FIX] Update documentation location (andrewelkins) - [FIX] Update setup.py Development Status level (andrewelkins) - [FIX] Case insensitive month match (cshowe) ### 0.5.0 - [NEW] struct_time addition. (mhworth) - [NEW] Version grep (eirnym) - [NEW] Default to ISO-8601 format (emonty) - [NEW] Raise TypeError on comparison (sniekamp) - [NEW] Adding Macedonian(mk) locale (krisfremen) - [FIX] Fix for ISO seconds and fractional seconds (sdispater) (andrewelkins) - [FIX] Use correct Dutch wording for "hours" (wbolster) - [FIX] Complete the list of english locales (indorilftw) - [FIX] Change README to reStructuredText (nyuszika7h) - [FIX] Parse lower-cased 'h' (tamentis) - [FIX] Slight modifications to Dutch locale (nvie) ### 0.4.4 - [NEW] Include the docs in the released tarball - [NEW] Czech localization Czech localization for Arrow - [NEW] Add fa_ir to locales - [FIX] Fixes parsing of time strings with a final Z - [FIX] Fixes ISO parsing and formatting for fractional seconds - [FIX] test_fromtimestamp sp - [FIX] some typos fixed - [FIX] removed an unused import statement - [FIX] docs table fix - [FIX] Issue with specify 'X' template and no template at all to arrow.get - [FIX] Fix "import" typo in docs/index.rst - [FIX] Fix unit tests for zero passed - [FIX] Update layout.html - [FIX] In Norwegian and new Norwegian months and weekdays should not be capitalized - [FIX] Fixed discrepancy between specifying 'X' to arrow.get and specifying no template ### 0.4.3 - [NEW] Turkish locale (Emre) - [NEW] Arabic locale (Mosab Ahmad) - [NEW] Danish locale (Holmars) - [NEW] Icelandic locale (Holmars) - [NEW] Hindi locale (Atmb4u) - [NEW] Malayalam locale (Atmb4u) - [NEW] Finnish locale (Stormpat) - [NEW] Portuguese locale (Danielcorreia) - [NEW] ``h`` and ``hh`` strings are now supported (Averyonghub) - [FIX] An incorrect inflection in the Polish locale has been fixed (Avalanchy) - [FIX] ``arrow.get`` now properly handles ``Date``s (Jaapz) - [FIX] Tests are now declared in ``setup.py`` and the manifest (Pypingou) - [FIX] ``__version__`` has been added to ``__init__.py`` (Sametmax) - [FIX] ISO 8601 strings can be parsed without a separator (Ivandiguisto / Root) - [FIX] Documentation is now more clear regarding some inputs on ``arrow.get`` (Eriktaubeneck) - [FIX] Some documentation links have been fixed (Vrutsky) - [FIX] Error messages for parse errors are now more descriptive (Maciej Albin) - [FIX] The parser now correctly checks for separators in strings (Mschwager) ### 0.4.2 - [NEW] Factory ``get`` method now accepts a single ``Arrow`` argument. - [NEW] Tokens SSSS, SSSSS and SSSSSS are supported in parsing. - [NEW] ``Arrow`` objects have a ``float_timestamp`` property. - [NEW] Vietnamese locale (Iu1nguoi) - [NEW] Factory ``get`` method now accepts a list of format strings (Dgilland) - [NEW] A MANIFEST.in file has been added (Pypingou) - [NEW] Tests can be run directly from ``setup.py`` (Pypingou) - [FIX] Arrow docs now list 'day of week' format tokens correctly (Rudolphfroger) - [FIX] Several issues with the Korean locale have been resolved (Yoloseem) - [FIX] ``humanize`` now correctly returns unicode (Shvechikov) - [FIX] ``Arrow`` objects now pickle / unpickle correctly (Yoloseem) ### 0.4.1 - [NEW] Table / explanation of formatting & parsing tokens in docs - [NEW] Brazilian locale (Augusto2112) - [NEW] Dutch locale (OrangeTux) - [NEW] Italian locale (Pertux) - [NEW] Austrain locale (LeChewbacca) - [NEW] Tagalog locale (Marksteve) - [FIX] Corrected spelling and day numbers in German locale (LeChewbacca) - [FIX] Factory ``get`` method should now handle unicode strings correctly (Bwells) - [FIX] Midnight and noon should now parse and format correctly (Bwells) ### 0.4.0 - [NEW] Format-free ISO-8601 parsing in factory ``get`` method - [NEW] Support for 'week' / 'weeks' in ``span``, ``range``, ``span_range``, ``floor`` and ``ceil`` - [NEW] Support for 'weeks' in ``replace`` - [NEW] Norwegian locale (Martinp) - [NEW] Japanese locale (CortYuming) - [FIX] Timezones no longer show the wrong sign when formatted (Bean) - [FIX] Microseconds are parsed correctly from strings (Bsidhom) - [FIX] Locale day-of-week is no longer off by one (Cynddl) - [FIX] Corrected plurals of Ukrainian and Russian nouns (Catchagain) - [CHANGE] Old 0.1 ``arrow`` module method removed - [CHANGE] Dropped timestamp support in ``range`` and ``span_range`` (never worked correctly) - [CHANGE] Dropped parsing of single string as tz string in factory ``get`` method (replaced by ISO-8601) ### 0.3.5 - [NEW] French locale (Cynddl) - [NEW] Spanish locale (Slapresta) - [FIX] Ranges handle multiple timezones correctly (Ftobia) ### 0.3.4 - [FIX] Humanize no longer sometimes returns the wrong month delta - [FIX] ``__format__`` works correctly with no format string ### 0.3.3 - [NEW] Python 2.6 support - [NEW] Initial support for locale-based parsing and formatting - [NEW] ArrowFactory class, now proxied as the module API - [NEW] ``factory`` api method to obtain a factory for a custom type - [FIX] Python 3 support and tests completely ironed out ### 0.3.2 - [NEW] Python 3+ support ### 0.3.1 - [FIX] The old ``arrow`` module function handles timestamps correctly as it used to ### 0.3.0 - [NEW] ``Arrow.replace`` method - [NEW] Accept timestamps, datetimes and Arrows for datetime inputs, where reasonable - [FIX] ``range`` and ``span_range`` respect end and limit parameters correctly - [CHANGE] Arrow objects are no longer mutable - [CHANGE] Plural attribute name semantics altered: single -> absolute, plural -> relative - [CHANGE] Plural names no longer supported as properties (e.g. ``arrow.utcnow().years``) ### 0.2.1 - [NEW] Support for localized humanization - [NEW] English, Russian, Greek, Korean, Chinese locales ### 0.2.0 - **REWRITE** - [NEW] Date parsing - [NEW] Date formatting - [NEW] ``floor``, ``ceil`` and ``span`` methods - [NEW] ``datetime`` interface implementation - [NEW] ``clone`` method - [NEW] ``get``, ``now`` and ``utcnow`` API methods ### 0.1.6 - [NEW] Humanized time deltas - [NEW] ``__eq__`` implemented - [FIX] Issues with conversions related to daylight savings time resolved - [CHANGE] ``__str__`` uses ISO formatting ### 0.1.5 - **Started tracking changes** - [NEW] Parsing of ISO-formatted time zone offsets (e.g. '+02:30', '-05:00') - [NEW] Resolved some issues with timestamps and delta / Olson time zones arrow-0.7.0/LICENSE000066400000000000000000000011031260523235100136470ustar00rootroot00000000000000Copyright 2013 Chris Smith Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. arrow-0.7.0/MANIFEST.in000066400000000000000000000001311260523235100144000ustar00rootroot00000000000000include LICENSE HISTORY.md README.rst recursive-include tests * recursive-include docs * arrow-0.7.0/Makefile000066400000000000000000000013521260523235100143100ustar00rootroot00000000000000.PHONY: auto build test docs clean auto: build27 build27: virtualenv local --python=python2.7 local/bin/pip install --use-mirrors -r requirements.txt build26: virtualenv local --python=python2.6 local/bin/pip install --use-mirrors -r requirements.txt local/bin/pip install --use-mirrors -r requirements26.txt build33: virtualenv local --python=python3.3 local/bin/pip install --use-mirrors -r requirements.txt build34: virtualenv local --python=python3.4 local/bin/pip install --use-mirrors -r requirements.txt test: rm -f .coverage . local/bin/activate && nosetests --all-modules --with-coverage arrow tests docs: touch docs/index.rst cd docs; make html clean: rm -rf local rm -f arrow/*.pyc tests/*.pyc rm -f .coverage arrow-0.7.0/README.rst000066400000000000000000000063601260523235100143430ustar00rootroot00000000000000Arrow - Better dates & times for Python ======================================= .. image:: https://travis-ci.org/crsmithdev/arrow.png :alt: build status :target: https://travis-ci.org/crsmithdev/arrow .. image:: https://pypip.in/d/arrow/badge.png :alt: downloads :target: https://crate.io/packages/arrow Documentation: `arrow.readthedocs.org `_ --------------------------------------------------------------------------------- What? ----- Arrow is a Python library that offers a sensible, human-friendly approach to creating, manipulating, formatting and converting dates, times, and timestamps. It implements and updates the datetime type, plugging gaps in functionality, and provides an intelligent module API that supports many common creation scenarios. Simply put, it helps you work with dates and times with fewer imports and a lot less code. Arrow is heavily inspired by `moment.js `_ and `requests `_ Why? ---- Python's standard library and some other low-level modules have near-complete date, time and time zone functionality but don't work very well from a usability perspective: - Too many modules: datetime, time, calendar, dateutil, pytz and more - Too many types: date, time, datetime, tzinfo, timedelta, relativedelta, etc. - Time zones and timestamp conversions are verbose and unpleasant - Time zone naievety is the norm - Gaps in functionality: ISO-8601 parsing, timespans, humanization Features -------- - Fully implemented, drop-in replacement for datetime - Supports Python 2.6, 2.7 and 3.3 - Time zone-aware & UTC by default - Provides super-simple creation options for many common input scenarios - Updated .replace method with support for relative offsets, including weeks - Formats and parses strings, including ISO-8601-formatted strings automatically - Timezone conversion - Timestamp available as a property - Generates time spans, ranges, floors and ceilings in timeframes from year to microsecond - Humanizes and supports a growing list of contributed locales - Extensible for your own Arrow-derived types Quick start ----------- First: .. code-block:: console $ pip install arrow And then: .. code-block:: pycon >>> import arrow >>> utc = arrow.utcnow() >>> utc >>> utc = utc.replace(hours=-1) >>> utc >>> local = utc.to('US/Pacific') >>> local >>> arrow.get('2013-05-11T21:23:58.970460+00:00') >>> local.timestamp 1368303838 >>> local.format() '2013-05-11 13:23:58 -07:00' >>> local.format('YYYY-MM-DD HH:mm:ss ZZ') '2013-05-11 13:23:58 -07:00' >>> local.humanize() 'an hour ago' >>> local.humanize(locale='ko_kr') '1시간 전' Further documentation can be found at `arrow.readthedocs.org `_ Contributing ------------ Contributions are welcome, especially with localization. See `locales.py `_ for what's currently supported. arrow-0.7.0/arrow/000077500000000000000000000000001260523235100140015ustar00rootroot00000000000000arrow-0.7.0/arrow/__init__.py000066400000000000000000000002431260523235100161110ustar00rootroot00000000000000# -*- coding: utf-8 -*- from .arrow import Arrow from .factory import ArrowFactory from .api import get, now, utcnow __version__ = '0.7.0' VERSION = __version__ arrow-0.7.0/arrow/api.py000066400000000000000000000021141260523235100151220ustar00rootroot00000000000000# -*- coding: utf-8 -*- ''' Provides the default implementation of :class:`ArrowFactory ` methods for use as a module API. ''' from __future__ import absolute_import from arrow.factory import ArrowFactory # internal default factory. _factory = ArrowFactory() def get(*args, **kwargs): ''' Implements the default :class:`ArrowFactory ` ``get`` method. ''' return _factory.get(*args, **kwargs) def utcnow(): ''' Implements the default :class:`ArrowFactory ` ``utcnow`` method. ''' return _factory.utcnow() def now(tz=None): ''' Implements the default :class:`ArrowFactory ` ``now`` method. ''' return _factory.now(tz) def factory(type): ''' Returns an :class:`.ArrowFactory` for the specified :class:`Arrow ` or derived type. :param type: the type, :class:`Arrow ` or derived. ''' return ArrowFactory(type) __all__ = ['get', 'utcnow', 'now', 'factory', 'iso'] arrow-0.7.0/arrow/arrow.py000066400000000000000000000702551260523235100155160ustar00rootroot00000000000000# -*- coding: utf-8 -*- ''' Provides the :class:`Arrow ` class, an enhanced ``datetime`` replacement. ''' from __future__ import absolute_import from datetime import datetime, timedelta, tzinfo from dateutil import tz as dateutil_tz from dateutil.relativedelta import relativedelta import calendar import sys from arrow import util, locales, parser, formatter class Arrow(object): '''An :class:`Arrow ` object. Implements the ``datetime`` interface, behaving as an aware ``datetime`` while implementing additional functionality. :param year: the calendar year. :param month: the calendar month. :param day: the calendar day. :param hour: (optional) the hour. Defaults to 0. :param minute: (optional) the minute, Defaults to 0. :param second: (optional) the second, Defaults to 0. :param microsecond: (optional) the microsecond. Defaults 0. :param tzinfo: (optional) the ``tzinfo`` object. Defaults to ``None``. If tzinfo is None, it is assumed to be UTC on creation. Usage:: >>> import arrow >>> arrow.Arrow(2013, 5, 5, 12, 30, 45) ''' resolution = datetime.resolution _ATTRS = ['year', 'month', 'day', 'hour', 'minute', 'second', 'microsecond'] _ATTRS_PLURAL = ['{0}s'.format(a) for a in _ATTRS] def __init__(self, year, month, day, hour=0, minute=0, second=0, microsecond=0, tzinfo=None): if util.isstr(tzinfo): tzinfo = parser.TzinfoParser.parse(tzinfo) tzinfo = tzinfo or dateutil_tz.tzutc() self._datetime = datetime(year, month, day, hour, minute, second, microsecond, tzinfo) # factories: single object, both original and from datetime. @classmethod def now(cls, tzinfo=None): '''Constructs an :class:`Arrow ` object, representing "now". :param tzinfo: (optional) a ``tzinfo`` object. Defaults to local time. ''' utc = datetime.utcnow().replace(tzinfo=dateutil_tz.tzutc()) dt = utc.astimezone(dateutil_tz.tzlocal() if tzinfo is None else tzinfo) return cls(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond, dt.tzinfo) @classmethod def utcnow(cls): ''' Constructs an :class:`Arrow ` object, representing "now" in UTC time. ''' dt = datetime.utcnow() return cls(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond, dateutil_tz.tzutc()) @classmethod def fromtimestamp(cls, timestamp, tzinfo=None): ''' Constructs an :class:`Arrow ` object from a timestamp. :param timestamp: an ``int`` or ``float`` timestamp, or a ``str`` that converts to either. :param tzinfo: (optional) a ``tzinfo`` object. Defaults to local time. ''' tzinfo = tzinfo or dateutil_tz.tzlocal() timestamp = cls._get_timestamp_from_input(timestamp) dt = datetime.fromtimestamp(timestamp, tzinfo) return cls(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond, tzinfo) @classmethod def utcfromtimestamp(cls, timestamp): '''Constructs an :class:`Arrow ` object from a timestamp, in UTC time. :param timestamp: an ``int`` or ``float`` timestamp, or a ``str`` that converts to either. ''' timestamp = cls._get_timestamp_from_input(timestamp) dt = datetime.utcfromtimestamp(timestamp) return cls(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond, dateutil_tz.tzutc()) @classmethod def fromdatetime(cls, dt, tzinfo=None): ''' Constructs an :class:`Arrow ` object from a ``datetime`` and optional ``tzinfo`` object. :param dt: the ``datetime`` :param tzinfo: (optional) a ``tzinfo`` object. Defaults to UTC. ''' tzinfo = tzinfo or dt.tzinfo or dateutil_tz.tzutc() return cls(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond, tzinfo) @classmethod def fromdate(cls, date, tzinfo=None): ''' Constructs an :class:`Arrow ` object from a ``date`` and optional ``tzinfo`` object. Time values are set to 0. :param date: the ``date`` :param tzinfo: (optional) a ``tzinfo`` object. Defaults to UTC. ''' tzinfo = tzinfo or dateutil_tz.tzutc() return cls(date.year, date.month, date.day, tzinfo=tzinfo) @classmethod def strptime(cls, date_str, fmt, tzinfo=None): ''' Constructs an :class:`Arrow ` object from a date string and format, in the style of ``datetime.strptime``. :param date_str: the date string. :param fmt: the format string. :param tzinfo: (optional) an optional ``tzinfo`` ''' dt = datetime.strptime(date_str, fmt) tzinfo = tzinfo or dt.tzinfo return cls(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond, tzinfo) # factories: ranges and spans @classmethod def range(cls, frame, start, end=None, tz=None, limit=None): ''' Returns an array of :class:`Arrow ` objects, representing an iteration of time between two inputs. :param frame: the timeframe. Can be any ``datetime`` property (day, hour, minute...). :param start: A datetime expression, the start of the range. :param end: (optional) A datetime expression, the end of the range. :param tz: (optional) A timezone expression. Defaults to UTC. :param limit: (optional) A maximum number of tuples to return. **NOTE**: the **end** or **limit** must be provided. Call with **end** alone to return the entire range, with **limit** alone to return a maximum # of results from the start, and with both to cap a range at a maximum # of results. Supported frame values: year, quarter, month, week, day, hour, minute, second Recognized datetime expressions: - An :class:`Arrow ` object. - A ``datetime`` object. Recognized timezone expressions: - A ``tzinfo`` object. - A ``str`` describing a timezone, similar to 'US/Pacific', or 'Europe/Berlin'. - A ``str`` in ISO-8601 style, as in '+07:00'. - A ``str``, one of the following: 'local', 'utc', 'UTC'. Usage: >>> start = datetime(2013, 5, 5, 12, 30) >>> end = datetime(2013, 5, 5, 17, 15) >>> for r in arrow.Arrow.range('hour', start, end): ... print repr(r) ... ''' _, frame_relative, relative_steps = cls._get_frames(frame) tzinfo = cls._get_tzinfo(start.tzinfo if tz is None else tz) start = cls._get_datetime(start).replace(tzinfo=tzinfo) end, limit = cls._get_iteration_params(end, limit) end = cls._get_datetime(end).replace(tzinfo=tzinfo) current = cls.fromdatetime(start) results = [] while current <= end and len(results) < limit: results.append(current) values = [getattr(current, f) for f in cls._ATTRS] current = cls(*values, tzinfo=tzinfo) + relativedelta(**{frame_relative: relative_steps}) return results @classmethod def span_range(cls, frame, start, end, tz=None, limit=None): ''' Returns an array of tuples, each :class:`Arrow ` objects, representing a series of timespans between two inputs. :param frame: the timeframe. Can be any ``datetime`` property (day, hour, minute...). :param start: A datetime expression, the start of the range. :param end: (optional) A datetime expression, the end of the range. :param tz: (optional) A timezone expression. Defaults to UTC. :param limit: (optional) A maximum number of tuples to return. **NOTE**: the **end** or **limit** must be provided. Call with **end** alone to return the entire range, with **limit** alone to return a maximum # of results from the start, and with both to cap a range at a maximum # of results. Supported frame values: year, quarter, month, week, day, hour, minute, second Recognized datetime expressions: - An :class:`Arrow ` object. - A ``datetime`` object. Recognized timezone expressions: - A ``tzinfo`` object. - A ``str`` describing a timezone, similar to 'US/Pacific', or 'Europe/Berlin'. - A ``str`` in ISO-8601 style, as in '+07:00'. - A ``str``, one of the following: 'local', 'utc', 'UTC'. Usage: >>> start = datetime(2013, 5, 5, 12, 30) >>> end = datetime(2013, 5, 5, 17, 15) >>> for r in arrow.Arrow.span_range('hour', start, end): ... print r ... (, ) (, ) (, ) (, ) (, ) ''' tzinfo = cls._get_tzinfo(start.tzinfo if tz is None else tz) start = cls.fromdatetime(start, tzinfo).span(frame)[0] _range = cls.range(frame, start, end, tz, limit) return [r.span(frame) for r in _range] # representations def __repr__(self): dt = self._datetime attrs = ', '.join([str(i) for i in [dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond]]) return '<{0} [{1}]>'.format(self.__class__.__name__, self.__str__()) def __str__(self): return self._datetime.isoformat() def __format__(self, formatstr): if len(formatstr) > 0: return self.format(formatstr) return str(self) def __hash__(self): return self._datetime.__hash__() # attributes & properties def __getattr__(self, name): if name == 'week': return self.isocalendar()[1] if not name.startswith('_'): value = getattr(self._datetime, name, None) if value is not None: return value return object.__getattribute__(self, name) @property def tzinfo(self): ''' Gets the ``tzinfo`` of the :class:`Arrow ` object. ''' return self._datetime.tzinfo @tzinfo.setter def tzinfo(self, tzinfo): ''' Sets the ``tzinfo`` of the :class:`Arrow ` object. ''' self._datetime = self._datetime.replace(tzinfo=tzinfo) @property def datetime(self): ''' Returns a datetime representation of the :class:`Arrow ` object. ''' return self._datetime @property def naive(self): ''' Returns a naive datetime representation of the :class:`Arrow ` object. ''' return self._datetime.replace(tzinfo=None) @property def timestamp(self): ''' Returns a timestamp representation of the :class:`Arrow ` object. ''' return calendar.timegm(self._datetime.utctimetuple()) @property def float_timestamp(self): ''' Returns a floating-point representation of the :class:`Arrow ` object. ''' return self.timestamp + float(self.microsecond) / 1000000 # mutation and duplication. def clone(self): ''' Returns a new :class:`Arrow ` object, cloned from the current one. Usage: >>> arw = arrow.utcnow() >>> cloned = arw.clone() ''' return self.fromdatetime(self._datetime) def replace(self, **kwargs): ''' Returns a new :class:`Arrow ` object with attributes updated according to inputs. Use single property names to set their value absolutely: >>> import arrow >>> arw = arrow.utcnow() >>> arw >>> arw.replace(year=2014, month=6) Use plural property names to shift their current value relatively: >>> arw.replace(years=1, months=-1) You can also provide a timezone expression can also be replaced: >>> arw.replace(tzinfo=tz.tzlocal()) Recognized timezone expressions: - A ``tzinfo`` object. - A ``str`` describing a timezone, similar to 'US/Pacific', or 'Europe/Berlin'. - A ``str`` in ISO-8601 style, as in '+07:00'. - A ``str``, one of the following: 'local', 'utc', 'UTC'. ''' absolute_kwargs = {} relative_kwargs = {} for key, value in kwargs.items(): if key in self._ATTRS: absolute_kwargs[key] = value elif key in self._ATTRS_PLURAL or key == 'weeks': relative_kwargs[key] = value elif key == 'week': raise AttributeError('setting absolute week is not supported') elif key !='tzinfo': raise AttributeError() current = self._datetime.replace(**absolute_kwargs) current += relativedelta(**relative_kwargs) tzinfo = kwargs.get('tzinfo') if tzinfo is not None: tzinfo = self._get_tzinfo(tzinfo) current = current.replace(tzinfo=tzinfo) return self.fromdatetime(current) def to(self, tz): ''' Returns a new :class:`Arrow ` object, converted to the target timezone. :param tz: an expression representing a timezone. Recognized timezone expressions: - A ``tzinfo`` object. - A ``str`` describing a timezone, similar to 'US/Pacific', or 'Europe/Berlin'. - A ``str`` in ISO-8601 style, as in '+07:00'. - A ``str``, one of the following: 'local', 'utc', 'UTC'. Usage:: >>> utc = arrow.utcnow() >>> utc >>> utc.to('US/Pacific') >>> utc.to(tz.tzlocal()) >>> utc.to('-07:00') >>> utc.to('local') >>> utc.to('local').to('utc') ''' if not isinstance(tz, tzinfo): tz = parser.TzinfoParser.parse(tz) dt = self._datetime.astimezone(tz) return self.__class__(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond, dt.tzinfo) def span(self, frame, count=1): ''' Returns two new :class:`Arrow ` objects, representing the timespan of the :class:`Arrow ` object in a given timeframe. :param frame: the timeframe. Can be any ``datetime`` property (day, hour, minute...). :param count: (optional) the number of frames to span. Supported frame values: year, quarter, month, week, day, hour, minute, second Usage:: >>> arrow.utcnow() >>> arrow.utcnow().span('hour') (, ) >>> arrow.utcnow().span('day') (, ) >>> arrow.utcnow().span('day', count=2) (, ) ''' frame_absolute, frame_relative, relative_steps = self._get_frames(frame) if frame_absolute == 'week': attr = 'day' elif frame_absolute == 'quarter': attr = 'month' else: attr = frame_absolute index = self._ATTRS.index(attr) frames = self._ATTRS[:index + 1] values = [getattr(self, f) for f in frames] for i in range(3 - len(values)): values.append(1) floor = self.__class__(*values, tzinfo=self.tzinfo) if frame_absolute == 'week': floor = floor + relativedelta(days=-(self.isoweekday() - 1)) elif frame_absolute == 'quarter': floor = floor + relativedelta(months=-((self.month - 1) % 3)) ceil = floor + relativedelta( **{frame_relative: count * relative_steps}) + relativedelta(microseconds=-1) return floor, ceil def floor(self, frame): ''' Returns a new :class:`Arrow ` object, representing the "floor" of the timespan of the :class:`Arrow ` object in a given timeframe. Equivalent to the first element in the 2-tuple returned by :func:`span `. :param frame: the timeframe. Can be any ``datetime`` property (day, hour, minute...). Usage:: >>> arrow.utcnow().floor('hour') ''' return self.span(frame)[0] def ceil(self, frame): ''' Returns a new :class:`Arrow ` object, representing the "ceiling" of the timespan of the :class:`Arrow ` object in a given timeframe. Equivalent to the second element in the 2-tuple returned by :func:`span `. :param frame: the timeframe. Can be any ``datetime`` property (day, hour, minute...). Usage:: >>> arrow.utcnow().ceil('hour') ''' return self.span(frame)[1] # string output and formatting. def format(self, fmt='YYYY-MM-DD HH:mm:ssZZ', locale='en_us'): ''' Returns a string representation of the :class:`Arrow ` object, formatted according to a format string. :param fmt: the format string. Usage:: >>> arrow.utcnow().format('YYYY-MM-DD HH:mm:ss ZZ') '2013-05-09 03:56:47 -00:00' >>> arrow.utcnow().format('X') '1368071882' >>> arrow.utcnow().format('MMMM DD, YYYY') 'May 09, 2013' >>> arrow.utcnow().format() '2013-05-09 03:56:47 -00:00' ''' return formatter.DateTimeFormatter(locale).format(self._datetime, fmt) 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 ` or ``datetime`` object. Defaults to now in the current :class:`Arrow ` object's timezone. :param locale: (optional) a ``str`` specifying a locale. Defaults to 'en_us'. :param only_difference: (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 * abs(other_months - self_months) 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) # math def __add__(self, other): if isinstance(other, (timedelta, relativedelta)): return self.fromdatetime(self._datetime + other, self._datetime.tzinfo) raise TypeError() def __radd__(self, other): return self.__add__(other) def __sub__(self, other): if isinstance(other, timedelta): return self.fromdatetime(self._datetime - other, self._datetime.tzinfo) elif isinstance(other, datetime): return self._datetime - other elif isinstance(other, Arrow): return self._datetime - other._datetime raise TypeError() def __rsub__(self, other): return self.__sub__(other) # comparisons def _cmperror(self, other): raise TypeError('can\'t compare \'{0}\' to \'{1}\''.format( type(self), type(other))) def __eq__(self, other): if not isinstance(other, (Arrow, datetime)): return False other = self._get_datetime(other) return self._datetime == self._get_datetime(other) def __ne__(self, other): return not self.__eq__(other) def __gt__(self, other): if not isinstance(other, (Arrow, datetime)): self._cmperror(other) return self._datetime > self._get_datetime(other) def __ge__(self, other): if not isinstance(other, (Arrow, datetime)): self._cmperror(other) return self._datetime >= self._get_datetime(other) def __lt__(self, other): if not isinstance(other, (Arrow, datetime)): self._cmperror(other) return self._datetime < self._get_datetime(other) def __le__(self, other): if not isinstance(other, (Arrow, datetime)): self._cmperror(other) return self._datetime <= self._get_datetime(other) # datetime methods def date(self): ''' Returns a ``date`` object with the same year, month and day. ''' return self._datetime.date() def time(self): ''' Returns a ``time`` object with the same hour, minute, second, microsecond. ''' return self._datetime.time() def timetz(self): ''' Returns a ``time`` object with the same hour, minute, second, microsecond and tzinfo. ''' return self._datetime.timetz() def astimezone(self, tz): ''' Returns a ``datetime`` object, adjusted to the specified tzinfo. :param tz: a ``tzinfo`` object. ''' return self._datetime.astimezone(tz) def utcoffset(self): ''' Returns a ``timedelta`` object representing the whole number of minutes difference from UTC time. ''' return self._datetime.utcoffset() def dst(self): ''' Returns the daylight savings time adjustment. ''' return self._datetime.dst() def timetuple(self): ''' Returns a ``time.struct_time``, in the current timezone. ''' return self._datetime.timetuple() def utctimetuple(self): ''' Returns a ``time.struct_time``, in UTC time. ''' return self._datetime.utctimetuple() def toordinal(self): ''' Returns the proleptic Gregorian ordinal of the date. ''' return self._datetime.toordinal() def weekday(self): ''' Returns the day of the week as an integer (0-6). ''' return self._datetime.weekday() def isoweekday(self): ''' Returns the ISO day of the week as an integer (1-7). ''' return self._datetime.isoweekday() def isocalendar(self): ''' Returns a 3-tuple, (ISO year, ISO week number, ISO weekday). ''' return self._datetime.isocalendar() def isoformat(self, sep='T'): '''Returns an ISO 8601 formatted representation of the date and time. ''' return self._datetime.isoformat(sep) def ctime(self): ''' Returns a ctime formatted representation of the date and time. ''' return self._datetime.ctime() def strftime(self, format): ''' Formats in the style of ``datetime.strptime``. :param format: the format string. ''' return self._datetime.strftime(format) def for_json(self): '''Serializes for the ``for_json`` protocol of simplejson.''' return self.isoformat() # internal tools. @staticmethod def _get_tzinfo(tz_expr): if tz_expr is None: return dateutil_tz.tzutc() if isinstance(tz_expr, tzinfo): return tz_expr else: try: return parser.TzinfoParser.parse(tz_expr) except parser.ParserError: raise ValueError('\'{0}\' not recognized as a timezone') @classmethod def _get_datetime(cls, expr): if isinstance(expr, Arrow): return expr.datetime if isinstance(expr, datetime): return expr try: expr = float(expr) return cls.utcfromtimestamp(expr).datetime except: raise ValueError('\'{0}\' not recognized as a timestamp or datetime') @classmethod def _get_frames(cls, name): if name in cls._ATTRS: return name, '{0}s'.format(name), 1 elif name in ['week', 'weeks']: return 'week', 'weeks', 1 elif name in ['quarter', 'quarters']: return 'quarter', 'months', 3 raise AttributeError() @classmethod def _get_iteration_params(cls, end, limit): if end is None: if limit is None: raise Exception('one of \'end\' or \'limit\' is required') return cls.max, limit else: return end, sys.maxsize @staticmethod def _get_timestamp_from_input(timestamp): try: return float(timestamp) except: raise ValueError('cannot parse \'{0}\' as a timestamp'.format(timestamp)) Arrow.min = Arrow.fromdatetime(datetime.min) Arrow.max = Arrow.fromdatetime(datetime.max) arrow-0.7.0/arrow/factory.py000066400000000000000000000203261260523235100160250ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Implements the :class:`ArrowFactory ` class, providing factory methods for common :class:`Arrow ` construction scenarios. """ from __future__ import absolute_import from arrow.arrow import Arrow from arrow import parser from arrow.util import is_timestamp, isstr from datetime import datetime, tzinfo, date from dateutil import tz as dateutil_tz from time import struct_time import calendar class ArrowFactory(object): ''' A factory for generating :class:`Arrow ` objects. :param type: (optional) the :class:`Arrow `-based class to construct from. Defaults to :class:`Arrow `. ''' def __init__(self, type=Arrow): self.type = type def get(self, *args, **kwargs): ''' Returns an :class:`Arrow ` object based on flexible inputs. Usage:: >>> import arrow **No inputs** to get current UTC time:: >>> arrow.get() **None** to also get current UTC time:: >>> arrow.get(None) **One** :class:`Arrow ` object, to get a copy. >>> arw = arrow.utcnow() >>> arrow.get(arw) **One** ``str``, ``float``, or ``int``, convertible to a floating-point timestamp, to get that timestamp in UTC:: >>> arrow.get(1367992474.293378) >>> arrow.get(1367992474) >>> arrow.get('1367992474.293378') >>> arrow.get('1367992474') **One** ISO-8601-formatted ``str``, to parse it:: >>> arrow.get('2013-09-29T01:26:43.830580') **One** ``tzinfo``, to get the current time in that timezone:: >>> arrow.get(tz.tzlocal()) **One** naive ``datetime``, to get that datetime in UTC:: >>> arrow.get(datetime(2013, 5, 5)) **One** aware ``datetime``, to get that datetime:: >>> arrow.get(datetime(2013, 5, 5, tzinfo=tz.tzlocal())) **One** naive ``date``, to get that date in UTC:: >>> arrow.get(date(2013, 5, 5)) **Two** arguments, a naive or aware ``datetime``, and a timezone expression (as above):: >>> arrow.get(datetime(2013, 5, 5), 'US/Pacific') **Two** arguments, a naive ``date``, and a timezone expression (as above):: >>> arrow.get(date(2013, 5, 5), 'US/Pacific') **Two** arguments, both ``str``, to parse the first according to the format of the second:: >>> arrow.get('2013-05-05 12:30:45', 'YYYY-MM-DD HH:mm:ss') **Two** arguments, first a ``str`` to parse and second a ``list`` of formats to try:: >>> arrow.get('2013-05-05 12:30:45', ['MM/DD/YYYY', 'YYYY-MM-DD HH:mm:ss']) **Three or more** arguments, as for the constructor of a ``datetime``:: >>> arrow.get(2013, 5, 5, 12, 30, 45) **One** time.struct time:: >>> arrow.get(gmtime(0)) ''' arg_count = len(args) locale = kwargs.get('locale', 'en_us') tz = kwargs.get('tzinfo', None) # () -> now, @ utc. if arg_count == 0: if isinstance(tz, tzinfo): return self.type.now(tz) return self.type.utcnow() if arg_count == 1: arg = args[0] # (None) -> now, @ utc. if arg is None: return self.type.utcnow() # try (int, float, str(int), str(float)) -> utc, from timestamp. if is_timestamp(arg): return self.type.utcfromtimestamp(arg) # (Arrow) -> from the object's datetime. if isinstance(arg, Arrow): return self.type.fromdatetime(arg.datetime) # (datetime) -> from datetime. if isinstance(arg, datetime): return self.type.fromdatetime(arg) # (date) -> from date. if isinstance(arg, date): return self.type.fromdate(arg) # (tzinfo) -> now, @ tzinfo. elif isinstance(arg, tzinfo): return self.type.now(arg) # (str) -> now, @ tzinfo. elif isstr(arg): dt = parser.DateTimeParser(locale).parse_iso(arg) return self.type.fromdatetime(dt) # (struct_time) -> from struct_time elif isinstance(arg, struct_time): return self.type.utcfromtimestamp(calendar.timegm(arg)) else: raise TypeError('Can\'t parse single argument type of \'{0}\''.format(type(arg))) elif arg_count == 2: arg_1, arg_2 = args[0], args[1] if isinstance(arg_1, datetime): # (datetime, tzinfo) -> fromdatetime @ tzinfo/string. if isinstance(arg_2, tzinfo) or isstr(arg_2): return self.type.fromdatetime(arg_1, arg_2) else: raise TypeError('Can\'t parse two arguments of types \'datetime\', \'{0}\''.format( type(arg_2))) # (date, tzinfo/str) -> fromdate @ tzinfo/string. elif isinstance(arg_1, date): if isinstance(arg_2, tzinfo) or isstr(arg_2): return self.type.fromdate(arg_1, tzinfo=arg_2) else: raise TypeError('Can\'t parse two arguments of types \'date\', \'{0}\''.format( type(arg_2))) # (str, format) -> parse. elif isstr(arg_1) and (isstr(arg_2) or isinstance(arg_2, list)): dt = parser.DateTimeParser(locale).parse(args[0], args[1]) return self.type.fromdatetime(dt, tzinfo=tz) else: raise TypeError('Can\'t parse two arguments of types \'{0}\', \'{1}\''.format( type(arg_1), type(arg_2))) # 3+ args -> datetime-like via constructor. else: return self.type(*args, **kwargs) def utcnow(self): '''Returns an :class:`Arrow ` object, representing "now" in UTC time. Usage:: >>> import arrow >>> arrow.utcnow() ''' return self.type.utcnow() def now(self, tz=None): '''Returns an :class:`Arrow ` object, representing "now". :param tz: (optional) An expression representing a timezone. Defaults to local time. Recognized timezone expressions: - A ``tzinfo`` object. - A ``str`` describing a timezone, similar to 'US/Pacific', or 'Europe/Berlin'. - A ``str`` in ISO-8601 style, as in '+07:00'. - A ``str``, one of the following: 'local', 'utc', 'UTC'. Usage:: >>> import arrow >>> arrow.now() >>> arrow.now('US/Pacific') >>> arrow.now('+02:00') >>> arrow.now('local') ''' if tz is None: tz = dateutil_tz.tzlocal() elif not isinstance(tz, tzinfo): tz = parser.TzinfoParser.parse(tz) return self.type.now(tz) arrow-0.7.0/arrow/formatter.py000066400000000000000000000065511260523235100163650ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import absolute_import import calendar import re from dateutil import tz as dateutil_tz from arrow import util, locales class DateTimeFormatter(object): _FORMAT_RE = re.compile('(YYY?Y?|MM?M?M?|Do|DD?D?D?|d?dd?d?|HH?|hh?|mm?|ss?|SS?S?S?S?S?|ZZ?|a|A|X)') def __init__(self, locale='en_us'): self.locale = locales.get_locale(locale) def format(cls, dt, fmt): return cls._FORMAT_RE.sub(lambda m: cls._format_token(dt, m.group(0)), fmt) 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) arrow-0.7.0/arrow/locales.py000066400000000000000000001527171260523235100160120ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import absolute_import from __future__ import unicode_literals import calendar import inspect import sys def get_locale(name): '''Returns an appropriate :class:`Locale ` corresponding to an inpute locale name. :param name: the name of the locale. ''' locale_cls = _locales.get(name.lower()) if locale_cls is None: raise ValueError('Unsupported locale \'{0}\''.format(name)) return locale_cls() # base locale type. class Locale(object): ''' Represents locale-specific data and functionality. ''' names = [] timeframes = { 'now': '', 'seconds': '', 'minute': '', 'minutes': '', 'hour': '', 'hours': '', 'day': '', 'days': '', 'month': '', 'months': '', 'year': '', 'years': '', } meridians = { 'am': '', 'pm': '', 'AM': '', 'PM': '', } past = None future = None month_names = [] month_abbreviations = [] day_names = [] day_abbreviations = [] ordinal_day_re = r'(\d+)' def __init__(self): self._month_name_to_ordinal = None def describe(self, timeframe, delta=0, only_distance=False): ''' Describes a delta within a timeframe in plain language. :param timeframe: a string representing a timeframe. :param delta: a quantity representing a delta in a timeframe. :param only_distance: return only distance eg: "11 seconds" without "in" or "ago" keywords ''' humanized = self._format_timeframe(timeframe, delta) if not only_distance: humanized = self._format_relative(humanized, timeframe, delta) return humanized def day_name(self, day): ''' Returns the day name for a specified day of the week. :param day: the ``int`` day of the week (1-7). ''' return self.day_names[day] def day_abbreviation(self, day): ''' Returns the day abbreviation for a specified day of the week. :param day: the ``int`` day of the week (1-7). ''' return self.day_abbreviations[day] def month_name(self, month): ''' Returns the month name for a specified month of the year. :param month: the ``int`` month of the year (1-12). ''' return self.month_names[month] def month_abbreviation(self, month): ''' Returns the month abbreviation for a specified month of the year. :param month: the ``int`` month of the year (1-12). ''' return self.month_abbreviations[month] def month_number(self, name): ''' Returns the month number for a month specified by name or abbreviation. :param name: the month name or abbreviation. ''' if self._month_name_to_ordinal is None: self._month_name_to_ordinal = self._name_to_ordinal(self.month_names) self._month_name_to_ordinal.update(self._name_to_ordinal(self.month_abbreviations)) return self._month_name_to_ordinal.get(name) def year_full(self, year): ''' Returns the year for specific locale if available :param name: the ``int`` year (4-digit) ''' return '{0:04d}'.format(year) def year_abbreviation(self, year): ''' Returns the year for specific locale if available :param name: the ``int`` year (4-digit) ''' return '{0:04d}'.format(year)[2:] def meridian(self, hour, token): ''' Returns the meridian indicator for a specified hour and format token. :param hour: the ``int`` hour of the day. :param token: the format token. ''' if token == 'a': return self.meridians['am'] if hour < 12 else self.meridians['pm'] if token == 'A': return self.meridians['AM'] if hour < 12 else self.meridians['PM'] def ordinal_number(self, n): ''' Returns the ordinal format of a given integer :param n: an integer ''' return self._ordinal_number(n) def _ordinal_number(self, n): return '{0}'.format(n) def _name_to_ordinal(self, lst): return dict(map(lambda i: (i[1], i[0] + 1), enumerate(lst[1:]))) def _format_timeframe(self, timeframe, delta): return self.timeframes[timeframe].format(abs(delta)) def _format_relative(self, humanized, timeframe, delta): if timeframe == 'now': return humanized direction = self.past if delta < 0 else self.future return direction.format(humanized) # base locale type implementations. class EnglishLocale(Locale): names = ['en', 'en_us', 'en_gb', 'en_au', 'en_be', 'en_jp', 'en_za'] past = '{0} ago' future = 'in {0}' timeframes = { 'now': 'just now', 'seconds': 'seconds', 'minute': 'a minute', 'minutes': '{0} minutes', 'hour': 'an hour', 'hours': '{0} hours', 'day': 'a day', 'days': '{0} days', 'month': 'a month', 'months': '{0} months', 'year': 'a year', 'years': '{0} years', } meridians = { 'am': 'am', 'pm': 'pm', 'AM': 'AM', 'PM': 'PM', } month_names = ['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] month_abbreviations = ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] day_names = ['', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] day_abbreviations = ['', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] ordinal_day_re = r'((?P[2-3]?1(?=st)|[2-3]?2(?=nd)|[2-3]?3(?=rd)|[1-3]?[04-9](?=th)|1[1-3](?=th))(st|nd|rd|th))' def _ordinal_number(self, n): if n % 100 not in (11, 12, 13): remainder = abs(n) % 10 if remainder == 1: return '{0}st'.format(n) elif remainder == 2: return '{0}nd'.format(n) elif remainder == 3: return '{0}rd'.format(n) return '{0}th'.format(n) class ItalianLocale(Locale): names = ['it', 'it_it'] past = '{0} fa' future = 'tra {0}' timeframes = { 'now': 'adesso', 'seconds': 'qualche secondo', 'minute': 'un minuto', 'minutes': '{0} minuti', 'hour': 'un\'ora', 'hours': '{0} ore', 'day': 'un giorno', 'days': '{0} giorni', 'month': 'un mese', 'months': '{0} mesi', 'year': 'un anno', 'years': '{0} anni', } month_names = ['', 'Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre'] month_abbreviations = ['', 'Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic'] day_names = ['', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato', 'Domenica'] day_abbreviations = ['', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab', 'Dom'] ordinal_day_re = r'((?P[1-3]?[0-9](?=°))°)' def _ordinal_number(self, n): return '{0}°'.format(n) class SpanishLocale(Locale): names = ['es', 'es_es'] past = 'hace {0}' future = 'en {0}' timeframes = { 'now': 'ahora', 'seconds': 'segundos', 'minute': 'un minuto', 'minutes': '{0} minutos', 'hour': 'una hora', 'hours': '{0} horas', 'day': 'un día', 'days': '{0} días', 'month': 'un mes', 'months': '{0} meses', 'year': 'un año', 'years': '{0} años', } month_names = ['', 'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'] month_abbreviations = ['', 'Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'] day_names = ['', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo'] day_abbreviations = ['', 'Lun', 'Mar', 'Mie', 'Jue', 'Vie', 'Sab', 'Dom'] ordinal_day_re = r'((?P[1-3]?[0-9](?=°))°)' def _ordinal_number(self, n): return '{0}°'.format(n) class FrenchLocale(Locale): names = ['fr', 'fr_fr'] past = 'il y a {0}' future = 'dans {0}' timeframes = { 'now': 'maintenant', 'seconds': 'quelques secondes', 'minute': 'une minute', 'minutes': '{0} minutes', 'hour': 'une heure', 'hours': '{0} heures', 'day': 'un jour', 'days': '{0} jours', 'month': 'un mois', 'months': '{0} mois', 'year': 'un an', 'years': '{0} ans', } month_names = ['', 'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'] month_abbreviations = ['', 'Janv', 'Févr', 'Mars', 'Avr', 'Mai', 'Juin', 'Juil', 'Août', 'Sept', 'Oct', 'Nov', 'Déc'] day_names = ['', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi', 'Dimanche'] day_abbreviations = ['', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam', 'Dim'] ordinal_day_re = r'((?P\b1(?=er\b)|[1-3]?[02-9](?=e\b)|[1-3]1(?=e\b))(er|e)\b)' def _ordinal_number(self, n): if abs(n) == 1: return '{0}er'.format(n) return '{0}e'.format(n) class GreekLocale(Locale): names = ['el', 'el_gr'] past = '{0} πριν' future = 'σε {0}' timeframes = { 'now': 'τώρα', 'seconds': 'δευτερόλεπτα', 'minute': 'ένα λεπτό', 'minutes': '{0} λεπτά', 'hour': 'μια ώρα', 'hours': '{0} ώρες', 'day': 'μια μέρα', 'days': '{0} μέρες', 'month': 'ένα μήνα', 'months': '{0} μήνες', 'year': 'ένα χρόνο', 'years': '{0} χρόνια', } month_names = ['', 'Ιανουαρίου', 'Φεβρουαρίου', 'Μαρτίου', 'Απριλίου', 'Μαΐου', 'Ιουνίου', 'Ιουλίου', 'Αυγούστου', 'Σεπτεμβρίου', 'Οκτωβρίου', 'Νοεμβρίου', 'Δεκεμβρίου'] month_abbreviations = ['', 'Ιαν', 'Φεβ', 'Μαρ', 'Απρ', 'Μαϊ', 'Ιον', 'Ιολ', 'Αυγ', 'Σεπ', 'Οκτ', 'Νοε', 'Δεκ'] day_names = ['', 'Δευτέρα', 'Τρίτη', 'Τετάρτη', 'Πέμπτη', 'Παρασκευή', 'Σάββατο', 'Κυριακή'] day_abbreviations = ['', 'Δευ', 'Τρι', 'Τετ', 'Πεμ', 'Παρ', 'Σαβ', 'Κυρ'] class JapaneseLocale(Locale): names = ['ja', 'ja_jp'] past = '{0}前' future = '{0}後' timeframes = { 'now': '現在', 'seconds': '秒', 'minute': '1分', 'minutes': '{0}分', 'hour': '1時間', 'hours': '{0}時間', 'day': '1日', 'days': '{0}日', 'month': '1ヶ月', 'months': '{0}ヶ月', 'year': '1年', 'years': '{0}年', } month_names = ['', '1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'] month_abbreviations = ['', ' 1', ' 2', ' 3', ' 4', ' 5', ' 6', ' 7', ' 8', ' 9', '10', '11', '12'] day_names = ['', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日', '日曜日'] day_abbreviations = ['', '月', '火', '水', '木', '金', '土', '日'] class SwedishLocale(Locale): names = ['sv', 'sv_se'] past = 'för {0} sen' future = 'om {0}' timeframes = { 'now': 'just nu', 'seconds': 'några sekunder', 'minute': 'en minut', 'minutes': '{0} minuter', 'hour': 'en timme', 'hours': '{0} timmar', 'day': 'en dag', 'days': '{0} dagar', 'month': 'en månad', 'months': '{0} månader', 'year': 'ett år', 'years': '{0} år', } month_names = ['', 'Januari', 'Februari', 'Mars', 'April', 'Maj', 'Juni', 'Juli', 'Augusti', 'September', 'Oktober', 'November', 'December'] month_abbreviations = ['', 'Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'] day_names = ['', 'Måndag', 'Tisdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lördag', 'Söndag'] day_abbreviations = ['', 'Mån', 'Tis', 'Ons', 'Tor', 'Fre', 'Lör', 'Sön'] class FinnishLocale(Locale): names = ['fi', 'fi_fi'] # The finnish grammar is very complex, and its hard to convert # 1-to-1 to something like English. past = '{0} sitten' future = '{0} kuluttua' timeframes = { 'now': ['juuri nyt', 'juuri nyt'], 'seconds': ['muutama sekunti', 'muutaman sekunnin'], 'minute': ['minuutti', 'minuutin'], 'minutes': ['{0} minuuttia', '{0} minuutin'], 'hour': ['tunti', 'tunnin'], 'hours': ['{0} tuntia', '{0} tunnin'], 'day': ['päivä', 'päivä'], 'days': ['{0} päivää', '{0} päivän'], 'month': ['kuukausi', 'kuukauden'], 'months': ['{0} kuukautta', '{0} kuukauden'], 'year': ['vuosi', 'vuoden'], 'years': ['{0} vuotta', '{0} vuoden'], } # Months and days are lowercase in Finnish month_names = ['', 'tammikuu', 'helmikuu', 'maaliskuu', 'huhtikuu', 'toukokuu', 'kesäkuu', 'heinäkuu', 'elokuu', 'syyskuu', 'lokakuu', 'marraskuu', 'joulukuu'] month_abbreviations = ['', 'tammi', 'helmi', 'maalis', 'huhti', 'touko', 'kesä', 'heinä', 'elo', 'syys', 'loka', 'marras', 'joulu'] day_names = ['', 'maanantai', 'tiistai', 'keskiviikko', 'torstai', 'perjantai', 'lauantai', 'sunnuntai'] day_abbreviations = ['', 'ma', 'ti', 'ke', 'to', 'pe', 'la', 'su'] def _format_timeframe(self, timeframe, delta): return (self.timeframes[timeframe][0].format(abs(delta)), self.timeframes[timeframe][1].format(abs(delta))) def _format_relative(self, humanized, timeframe, delta): if timeframe == 'now': return humanized[0] direction = self.past if delta < 0 else self.future which = 0 if delta < 0 else 1 return direction.format(humanized[which]) class ChineseCNLocale(Locale): names = ['zh', 'zh_cn'] past = '{0}前' future = '{0}后' timeframes = { 'now': '刚才', 'seconds': '几秒', 'minute': '1分钟', 'minutes': '{0}分钟', 'hour': '1小时', 'hours': '{0}小时', 'day': '1天', 'days': '{0}天', 'month': '1个月', 'months': '{0}个月', 'year': '1年', 'years': '{0}年', } month_names = ['', '一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'] month_abbreviations = ['', ' 1', ' 2', ' 3', ' 4', ' 5', ' 6', ' 7', ' 8', ' 9', '10', '11', '12'] day_names = ['', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'] day_abbreviations = ['', '一', '二', '三', '四', '五', '六', '日'] class ChineseTWLocale(Locale): names = ['zh_tw'] past = '{0}前' future = '{0}後' timeframes = { 'now': '剛才', 'seconds': '幾秒', 'minute': '1分鐘', 'minutes': '{0}分鐘', 'hour': '1小時', 'hours': '{0}小時', 'day': '1天', 'days': '{0}天', 'month': '1個月', 'months': '{0}個月', 'year': '1年', 'years': '{0}年', } month_names = ['', '1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'] month_abbreviations = ['', ' 1', ' 2', ' 3', ' 4', ' 5', ' 6', ' 7', ' 8', ' 9', '10', '11', '12'] day_names = ['', '周一', '周二', '周三', '周四', '周五', '周六', '周日'] day_abbreviations = ['', '一', '二', '三', '四', '五', '六', '日'] class KoreanLocale(Locale): names = ['ko', 'ko_kr'] past = '{0} 전' future = '{0} 후' timeframes = { 'now': '지금', 'seconds': '몇초', 'minute': '일 분', 'minutes': '{0}분', 'hour': '1시간', 'hours': '{0}시간', 'day': '1일', 'days': '{0}일', 'month': '1개월', 'months': '{0}개월', 'year': '1년', 'years': '{0}년', } month_names = ['', '1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'] month_abbreviations = ['', ' 1', ' 2', ' 3', ' 4', ' 5', ' 6', ' 7', ' 8', ' 9', '10', '11', '12'] day_names = ['', '월요일', '화요일', '수요일', '목요일', '금요일', '토요일', '일요일'] day_abbreviations = ['', '월', '화', '수', '목', '금', '토', '일'] # derived locale types & implementations. class DutchLocale(Locale): names = ['nl', 'nl_nl'] past = '{0} geleden' future = 'over {0}' timeframes = { 'now': 'nu', 'seconds': 'seconden', 'minute': 'een minuut', 'minutes': '{0} minuten', 'hour': 'een uur', 'hours': '{0} uur', 'day': 'een dag', 'days': '{0} dagen', 'month': 'een maand', 'months': '{0} maanden', 'year': 'een jaar', 'years': '{0} jaar', } # In Dutch names of months and days are not starting with a capital letter # like in the English language. month_names = ['', 'januari', 'februari', 'maart', 'april', 'mei', 'juni', 'juli', 'augustus', 'september', 'oktober', 'november', 'december'] month_abbreviations = ['', 'jan', 'feb', 'mrt', 'apr', 'mei', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'] day_names = ['', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag', 'zondag'] day_abbreviations = ['', 'ma', 'di', 'wo', 'do', 'vr', 'za', 'zo'] class SlavicBaseLocale(Locale): def _format_timeframe(self, timeframe, delta): form = self.timeframes[timeframe] delta = abs(delta) if isinstance(form, list): if delta % 10 == 1 and delta % 100 != 11: form = form[0] elif 2 <= delta % 10 <= 4 and (delta % 100 < 10 or delta % 100 >= 20): form = form[1] else: form = form[2] return form.format(delta) class BelarusianLocale(SlavicBaseLocale): names = ['be', 'be_by'] past = '{0} таму' future = 'праз {0}' timeframes = { 'now': 'зараз', 'seconds': 'некалькі секунд', 'minute': 'хвіліну', 'minutes': ['{0} хвіліну', '{0} хвіліны', '{0} хвілін'], 'hour': 'гадзіну', 'hours': ['{0} гадзіну', '{0} гадзіны', '{0} гадзін'], 'day': 'дзень', 'days': ['{0} дзень', '{0} дні', '{0} дзён'], 'month': 'месяц', 'months': ['{0} месяц', '{0} месяцы', '{0} месяцаў'], 'year': 'год', 'years': ['{0} год', '{0} гады', '{0} гадоў'], } month_names = ['', 'студзеня', 'лютага', 'сакавіка', 'красавіка', 'траўня', 'чэрвеня', 'ліпеня', 'жніўня', 'верасня', 'кастрычніка', 'лістапада', 'снежня'] month_abbreviations = ['', 'студ', 'лют', 'сак', 'крас', 'трав', 'чэрв', 'ліп', 'жнів', 'вер', 'каст', 'ліст', 'снеж'] day_names = ['', 'панядзелак', 'аўторак', 'серада', 'чацвер', 'пятніца', 'субота', 'нядзеля'] day_abbreviations = ['', 'пн', 'ат', 'ср', 'чц', 'пт', 'сб', 'нд'] class PolishLocale(SlavicBaseLocale): names = ['pl', 'pl_pl'] past = '{0} temu' future = 'za {0}' timeframes = { 'now': 'teraz', 'seconds': 'kilka sekund', 'minute': 'minutę', 'minutes': ['{0} minut', '{0} minuty', '{0} minut'], 'hour': 'godzina', 'hours': ['{0} godzin', '{0} godziny', '{0} godzin'], 'day': 'dzień', 'days': ['{0} dzień', '{0} dni', '{0} dni'], 'month': 'miesiąc', 'months': ['{0} miesiąc', '{0} miesiące', '{0} miesięcy'], 'year': 'rok', 'years': ['{0} rok', '{0} lata', '{0} lat'], } month_names = ['', 'Styczeń', 'Luty', 'Marzec', 'Kwiecień', 'Maj', 'Czerwiec', 'Lipiec', 'Sierpień', 'Wrzesień', 'Październik', 'Listopad', 'Grudzień'] month_abbreviations = ['', 'sty', 'lut', 'mar', 'kwi', 'maj', 'cze', 'lip', 'sie', 'wrz', 'paź', 'lis', 'gru'] day_names = ['', 'Poniedziałek', 'Wtorek', 'Środa', 'Czwartek', 'Piątek', 'Sobota', 'Niedziela'] day_abbreviations = ['', 'Pn', 'Wt', 'Śr', 'Czw', 'Pt', 'So', 'Nd'] class RussianLocale(SlavicBaseLocale): names = ['ru', 'ru_ru'] past = '{0} назад' future = 'через {0}' timeframes = { 'now': 'сейчас', 'seconds': 'несколько секунд', 'minute': 'минуту', 'minutes': ['{0} минуту', '{0} минуты', '{0} минут'], 'hour': 'час', 'hours': ['{0} час', '{0} часа', '{0} часов'], 'day': 'день', 'days': ['{0} день', '{0} дня', '{0} дней'], 'month': 'месяц', 'months': ['{0} месяц', '{0} месяца', '{0} месяцев'], 'year': 'год', 'years': ['{0} год', '{0} года', '{0} лет'], } month_names = ['', 'января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря'] month_abbreviations = ['', 'янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'] day_names = ['', 'понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота', 'воскресенье'] day_abbreviations = ['', 'пн', 'вт', 'ср', 'чт', 'пт', 'сб', 'вс'] class UkrainianLocale(SlavicBaseLocale): names = ['ua', 'uk_ua'] past = '{0} тому' future = 'за {0}' timeframes = { 'now': 'зараз', 'seconds': 'кілька секунд', 'minute': 'хвилину', 'minutes': ['{0} хвилину', '{0} хвилини', '{0} хвилин'], 'hour': 'годину', 'hours': ['{0} годину', '{0} години', '{0} годин'], 'day': 'день', 'days': ['{0} день', '{0} дні', '{0} днів'], 'month': 'місяць', 'months': ['{0} місяць', '{0} місяці', '{0} місяців'], 'year': 'рік', 'years': ['{0} рік', '{0} роки', '{0} років'], } month_names = ['', 'січня', 'лютого', 'березня', 'квітня', 'травня', 'червня', 'липня', 'серпня', 'вересня', 'жовтня', 'листопада', 'грудня'] month_abbreviations = ['', 'січ', 'лют', 'бер', 'квіт', 'трав', 'черв', 'лип', 'серп', 'вер', 'жовт', 'лист', 'груд'] day_names = ['', 'понеділок', 'вівторок', 'середа', 'четвер', 'п’ятниця', 'субота', 'неділя'] day_abbreviations = ['', 'пн', 'вт', 'ср', 'чт', 'пт', 'сб', 'нд'] class GermanLocale(Locale): names = ['de', 'de_de'] past = 'vor {0}' future = 'in {0}' timeframes = { 'now': 'gerade eben', 'seconds': 'Sekunden', 'minute': 'einer Minute', 'minutes': '{0} Minuten', 'hour': 'einer Stunde', 'hours': '{0} Stunden', 'day': 'einem Tag', 'days': '{0} Tagen', 'month': 'einem Monat', 'months': '{0} Monaten', 'year': 'einem Jahr', 'years': '{0} Jahren', } month_names = [ '', 'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember' ] month_abbreviations = [ '', 'Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez' ] day_names = [ '', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag' ] day_abbreviations = ['', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'] class AustriaLocale(Locale): names = ['de', 'de_at'] past = 'vor {0}' future = 'in {0}' timeframes = { 'now': 'gerade eben', 'seconds': 'Sekunden', 'minute': 'einer Minute', 'minutes': '{0} Minuten', 'hour': 'einer Stunde', 'hours': '{0} Stunden', 'day': 'einem Tag', 'days': '{0} Tage', 'month': 'einem Monat', 'months': '{0} Monaten', 'year': 'einem Jahr', 'years': '{0} Jahren', } month_names = [ '', 'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember' ] month_abbreviations = [ '', 'Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez' ] day_names = [ '', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag' ] day_abbreviations = [ '', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So' ] class NorwegianLocale(Locale): names = ['nb', 'nb_no'] past = 'for {0} siden' future = 'om {0}' timeframes = { 'now': 'nå nettopp', 'seconds': 'noen sekunder', 'minute': 'ett minutt', 'minutes': '{0} minutter', 'hour': 'en time', 'hours': '{0} timer', 'day': 'en dag', 'days': '{0} dager', 'month': 'en måned', 'months': '{0} måneder', 'year': 'ett år', 'years': '{0} år', } month_names = ['', 'januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember'] month_abbreviations = ['', 'jan', 'feb', 'mar', 'apr', 'mai', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'des'] day_names = ['', 'mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag', 'søndag'] day_abbreviations = ['', 'ma', 'ti', 'on', 'to', 'fr', 'lø', 'sø'] class NewNorwegianLocale(Locale): names = ['nn', 'nn_no'] past = 'for {0} sidan' future = 'om {0}' timeframes = { 'now': 'no nettopp', 'seconds': 'nokre sekund', 'minute': 'ett minutt', 'minutes': '{0} minutt', 'hour': 'ein time', 'hours': '{0} timar', 'day': 'ein dag', 'days': '{0} dagar', 'month': 'en månad', 'months': '{0} månader', 'year': 'eit år', 'years': '{0} år', } month_names = ['', 'januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember'] month_abbreviations = ['', 'jan', 'feb', 'mar', 'apr', 'mai', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'des'] day_names = ['', 'måndag', 'tysdag', 'onsdag', 'torsdag', 'fredag', 'laurdag', 'sundag'] day_abbreviations = ['', 'må', 'ty', 'on', 'to', 'fr', 'la', 'su'] class PortugueseLocale(Locale): names = ['pt', 'pt_pt'] past = 'há {0}' future = 'em {0}' timeframes = { 'now': 'agora', 'seconds': 'segundos', 'minute': 'um minuto', 'minutes': '{0} minutos', 'hour': 'uma hora', 'hours': '{0} horas', 'day': 'um dia', 'days': '{0} dias', 'month': 'um mês', 'months': '{0} meses', 'year': 'um ano', 'years': '{0} anos', } month_names = ['', 'Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'] month_abbreviations = ['', 'Jan', 'Fev', 'Mar', 'Abr', 'Maio', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'] day_names = ['', 'Segunda-feira', 'Terça-feira', 'Quarta-feira', 'Quinta-feira', 'Sexta-feira', 'Sábado', 'Domingo'] day_abbreviations = ['', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sab', 'Dom'] class BrazilianPortugueseLocale(PortugueseLocale): names = ['pt_br'] past = 'fazem {0}' class TagalogLocale(Locale): names = ['tl'] past = 'nakaraang {0}' future = '{0} mula ngayon' timeframes = { 'now': 'ngayon lang', 'seconds': 'segundo', 'minute': 'isang minuto', 'minutes': '{0} minuto', 'hour': 'isang oras', 'hours': '{0} oras', 'day': 'isang araw', 'days': '{0} araw', 'month': 'isang buwan', 'months': '{0} buwan', 'year': 'isang taon', 'years': '{0} taon', } month_names = ['', 'Enero', 'Pebrero', 'Marso', 'Abril', 'Mayo', 'Hunyo', 'Hulyo', 'Agosto', 'Setyembre', 'Oktubre', 'Nobyembre', 'Disyembre'] month_abbreviations = ['', 'Ene', 'Peb', 'Mar', 'Abr', 'May', 'Hun', 'Hul', 'Ago', 'Set', 'Okt', 'Nob', 'Dis'] day_names = ['', 'Lunes', 'Martes', 'Miyerkules', 'Huwebes', 'Biyernes', 'Sabado', 'Linggo'] day_abbreviations = ['', 'Lun', 'Mar', 'Miy', 'Huw', 'Biy', 'Sab', 'Lin'] class VietnameseLocale(Locale): names = ['vi', 'vi_vn'] past = '{0} trước' future = '{0} nữa' timeframes = { 'now': 'hiện tại', 'seconds': 'giây', 'minute': 'một phút', 'minutes': '{0} phút', 'hour': 'một giờ', 'hours': '{0} giờ', 'day': 'một ngày', 'days': '{0} ngày', 'month': 'một tháng', 'months': '{0} tháng', 'year': 'một năm', 'years': '{0} năm', } month_names = ['', 'Tháng Một', 'Tháng Hai', 'Tháng Ba', 'Tháng Tư', 'Tháng Năm', 'Tháng Sáu', 'Tháng Bảy', 'Tháng Tám', 'Tháng Chín', 'Tháng Mười', 'Tháng Mười Một', 'Tháng Mười Hai'] month_abbreviations = ['', 'Tháng 1', 'Tháng 2', 'Tháng 3', 'Tháng 4', 'Tháng 5', 'Tháng 6', 'Tháng 7', 'Tháng 8', 'Tháng 9', 'Tháng 10', 'Tháng 11', 'Tháng 12'] day_names = ['', 'Thứ Hai', 'Thứ Ba', 'Thứ Tư', 'Thứ Năm', 'Thứ Sáu', 'Thứ Bảy', 'Chủ Nhật'] day_abbreviations = ['', 'Thứ 2', 'Thứ 3', 'Thứ 4', 'Thứ 5', 'Thứ 6', 'Thứ 7', 'CN'] class TurkishLocale(Locale): names = ['tr', 'tr_tr'] past = '{0} önce' future = '{0} sonra' timeframes = { 'now': 'şimdi', 'seconds': 'saniye', 'minute': 'bir dakika', 'minutes': '{0} dakika', 'hour': 'bir saat', 'hours': '{0} saat', 'day': 'bir gün', 'days': '{0} gün', 'month': 'bir ay', 'months': '{0} ay', 'year': 'a yıl', 'years': '{0} yıl', } month_names = ['', 'Ocak', 'Şubat', 'Mart', 'Nisan', 'Mayıs', 'Haziran', 'Temmuz', 'Ağustos', 'Eylül', 'Ekim', 'Kasım', 'Aralık'] month_abbreviations = ['', 'Oca', 'Şub', 'Mar', 'Nis', 'May', 'Haz', 'Tem', 'Ağu', 'Eyl', 'Eki', 'Kas', 'Ara'] day_names = ['', 'Pazartesi', 'Salı', 'Çarşamba', 'Perşembe', 'Cuma', 'Cumartesi', 'Pazar'] day_abbreviations = ['', 'Pzt', 'Sal', 'Çar', 'Per', 'Cum', 'Cmt', 'Paz'] class ArabicLocale(Locale): names = ['ar', 'ar_eg'] past = 'منذ {0}' future = 'خلال {0}' timeframes = { 'now': 'الآن', 'seconds': 'ثوان', 'minute': 'دقيقة', 'minutes': '{0} دقائق', 'hour': 'ساعة', 'hours': '{0} ساعات', 'day': 'يوم', 'days': '{0} أيام', 'month': 'شهر', 'months': '{0} شهور', 'year': 'سنة', 'years': '{0} سنوات', } month_names = ['', 'يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو', 'يوليو', 'أغسطس', 'سبتمبر', 'أكتوبر', 'نوفمبر', 'ديسمبر'] month_abbreviations = ['', 'يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو', 'يوليو', 'أغسطس', 'سبتمبر', 'أكتوبر', 'نوفمبر', 'ديسمبر'] day_names = ['', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت', 'الأحد'] day_abbreviations = ['', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة', 'سبت', 'أحد'] class IcelandicLocale(Locale): def _format_timeframe(self, timeframe, delta): timeframe = self.timeframes[timeframe] if delta < 0: timeframe = timeframe[0] elif delta > 0: timeframe = timeframe[1] return timeframe.format(abs(delta)) names = ['is', 'is_is'] past = 'fyrir {0} síðan' future = 'eftir {0}' timeframes = { 'now': 'rétt í þessu', 'seconds': ('nokkrum sekúndum', 'nokkrar sekúndur'), 'minute': ('einni mínútu', 'eina mínútu'), 'minutes': ('{0} mínútum', '{0} mínútur'), 'hour': ('einum tíma', 'einn tíma'), 'hours': ('{0} tímum', '{0} tíma'), 'day': ('einum degi', 'einn dag'), 'days': ('{0} dögum', '{0} daga'), 'month': ('einum mánuði', 'einn mánuð'), 'months': ('{0} mánuðum', '{0} mánuði'), 'year': ('einu ári', 'eitt ár'), 'years': ('{0} árum', '{0} ár'), } meridians = { 'am': 'f.h.', 'pm': 'e.h.', 'AM': 'f.h.', 'PM': 'e.h.', } month_names = ['', 'janúar', 'febrúar', 'mars', 'apríl', 'maí', 'júní', 'júlí', 'ágúst', 'september', 'október', 'nóvember', 'desember'] month_abbreviations = ['', 'jan', 'feb', 'mar', 'apr', 'maí', 'jún', 'júl', 'ágú', 'sep', 'okt', 'nóv', 'des'] day_names = ['', 'mánudagur', 'þriðjudagur', 'miðvikudagur', 'fimmtudagur', 'föstudagur', 'laugardagur', 'sunnudagur'] day_abbreviations = ['', 'mán', 'þri', 'mið', 'fim', 'fös', 'lau', 'sun'] class DanishLocale(Locale): names = ['da', 'da_dk'] past = 'for {0} siden' future = 'efter {0}' timeframes = { 'now': 'lige nu', 'seconds': 'et par sekunder', 'minute': 'et minut', 'minutes': '{0} minutter', 'hour': 'en time', 'hours': '{0} timer', 'day': 'en dag', 'days': '{0} dage', 'month': 'en måned', 'months': '{0} måneder', 'year': 'et år', 'years': '{0} år', } month_names = ['', 'januar', 'februar', 'marts', 'april', 'maj', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'december'] month_abbreviations = ['', 'jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'] day_names = ['', 'mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag', 'søndag'] day_abbreviations = ['', 'man', 'tir', 'ons', 'tor', 'fre', 'lør', 'søn'] class MalayalamLocale(Locale): names = ['ml'] past = '{0} മുമ്പ്' future = '{0} ശേഷം' timeframes = { 'now': 'ഇപ്പോൾ', 'seconds': 'സെക്കന്റ്‌', 'minute': 'ഒരു മിനിറ്റ്', 'minutes': '{0} മിനിറ്റ്', 'hour': 'ഒരു മണിക്കൂർ', 'hours': '{0} മണിക്കൂർ', 'day': 'ഒരു ദിവസം ', 'days': '{0} ദിവസം ', 'month': 'ഒരു മാസം ', 'months': '{0} മാസം ', 'year': 'ഒരു വർഷം ', 'years': '{0} വർഷം ', } meridians = { 'am': 'രാവിലെ', 'pm': 'ഉച്ചക്ക് ശേഷം', 'AM': 'രാവിലെ', 'PM': 'ഉച്ചക്ക് ശേഷം', } month_names = ['', 'ജനുവരി', 'ഫെബ്രുവരി', 'മാർച്ച്‌', 'ഏപ്രിൽ ', 'മെയ്‌ ', 'ജൂണ്‍', 'ജൂലൈ', 'ഓഗസ്റ്റ്‌', 'സെപ്റ്റംബർ', 'ഒക്ടോബർ', 'നവംബർ', 'ഡിസംബർ'] month_abbreviations = ['', 'ജനു', 'ഫെബ് ', 'മാർ', 'ഏപ്രിൽ', 'മേയ്', 'ജൂണ്‍', 'ജൂലൈ', 'ഓഗസ്റ', 'സെപ്റ്റ', 'ഒക്ടോ', 'നവം', 'ഡിസം'] day_names = ['', 'തിങ്കള്‍', 'ചൊവ്വ', 'ബുധന്‍', 'വ്യാഴം', 'വെള്ളി', 'ശനി', 'ഞായര്‍'] day_abbreviations = ['', 'തിങ്കള്‍', 'ചൊവ്വ', 'ബുധന്‍', 'വ്യാഴം', 'വെള്ളി', 'ശനി', 'ഞായര്‍'] class HindiLocale(Locale): names = ['hi'] past = '{0} पहले' future = '{0} बाद' timeframes = { 'now': 'अभि', 'seconds': 'सेकंड्', 'minute': 'एक मिनट ', 'minutes': '{0} मिनट ', 'hour': 'एक घंट', 'hours': '{0} घंटे', 'day': 'एक दिन', 'days': '{0} दिन', 'month': 'एक माह ', 'months': '{0} महीने ', 'year': 'एक वर्ष ', 'years': '{0} साल ', } meridians = { 'am': 'सुबह', 'pm': 'शाम', 'AM': 'सुबह', 'PM': 'शाम', } month_names = ['', 'जनवरी', 'फ़रवरी', 'मार्च', 'अप्रैल ', 'मई', 'जून', 'जुलाई', 'आगस्त', 'सितम्बर', 'अकतूबर', 'नवेम्बर', 'दिसम्बर'] month_abbreviations = ['', 'जन', 'फ़र', 'मार्च', 'अप्रै', 'मई', 'जून', 'जुलाई', 'आग', 'सित', 'अकत', 'नवे', 'दिस'] day_names = ['', 'सोमवार', 'मंगलवार', 'बुधवार', 'गुरुवार', 'शुक्रवार', 'शनिवार', 'रविवार'] day_abbreviations = ['', 'सोम', 'मंगल', 'बुध', 'गुरुवार', 'शुक्र', 'शनि', 'रवि'] class CzechLocale(Locale): names = ['cs', 'cs_cz'] timeframes = { 'now': 'Teď', 'seconds': { 'past': '{0} sekundami', 'future': ['{0} sekundy', '{0} sekund'] }, 'minute': {'past': 'minutou', 'future': 'minutu', 'zero': '{0} minut'}, 'minutes': { 'past': '{0} minutami', 'future': ['{0} minuty', '{0} minut'] }, 'hour': {'past': 'hodinou', 'future': 'hodinu', 'zero': '{0} hodin'}, 'hours': { 'past': '{0} hodinami', 'future': ['{0} hodiny', '{0} hodin'] }, 'day': {'past': 'dnem', 'future': 'den', 'zero': '{0} dnů'}, 'days': { 'past': '{0} dny', 'future': ['{0} dny', '{0} dnů'] }, 'month': {'past': 'měsícem', 'future': 'měsíc', 'zero': '{0} měsíců'}, 'months': { 'past': '{0} měsíci', 'future': ['{0} měsíce', '{0} měsíců'] }, 'year': {'past': 'rokem', 'future': 'rok', 'zero': '{0} let'}, 'years': { 'past': '{0} lety', 'future': ['{0} roky', '{0} let'] } } past = 'Před {0}' future = 'Za {0}' month_names = ['', 'Leden', 'Únor', 'Březen', 'Duben', 'Květen', 'Červen', 'Červenec', 'Srpen', 'Září', 'Říjen', 'Listopad', 'Prosinec'] month_abbreviations = ['', 'Led', 'Úno', 'Bře', 'Dub', 'Kvě', 'Čvn', 'Čvc', 'Srp', 'Zář', 'Říj', 'Lis', 'Pro'] day_names = ['', 'Pondělí', 'Úterý', 'Středa', 'Čtvrtek', 'Pátek', 'Sobota', 'Neděle'] day_abbreviations = ['', 'Po', 'Út', 'St', 'Čt', 'Pá', 'So', 'Ne'] def _format_timeframe(self, timeframe, delta): '''Czech aware time frame format function, takes into account the differences between past and future forms.''' form = self.timeframes[timeframe] if isinstance(form, dict): if delta == 0: form = form['zero'] # And *never* use 0 in the singular! elif delta > 0: form = form['future'] else: form = form['past'] delta = abs(delta) if isinstance(form, list): if 2 <= delta % 10 <= 4 and (delta % 100 < 10 or delta % 100 >= 20): form = form[0] else: form = form[1] return form.format(delta) class FarsiLocale(Locale): names = ['fa', 'fa_ir'] past = '{0} قبل' future = 'در {0}' timeframes = { 'now': 'اکنون', 'seconds': 'ثانیه', 'minute': 'یک دقیقه', 'minutes': '{0} دقیقه', 'hour': 'یک ساعت', 'hours': '{0} ساعت', 'day': 'یک روز', 'days': '{0} روز', 'month': 'یک ماه', 'months': '{0} ماه', 'year': 'یک سال', 'years': '{0} سال', } meridians = { 'am': 'قبل از ظهر', 'pm': 'بعد از ظهر', 'AM': 'قبل از ظهر', 'PM': 'بعد از ظهر', } month_names = ['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] month_abbreviations = ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] day_names = ['', 'دو شنبه', 'سه شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه', 'شنبه', 'یکشنبه'] day_abbreviations = ['', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] class MacedonianLocale(Locale): names = ['mk', 'mk_mk'] past = 'пред {0}' future = 'за {0}' timeframes = { 'now': 'сега', 'seconds': 'секунди', 'minute': 'една минута', 'minutes': '{0} минути', 'hour': 'еден саат', 'hours': '{0} саати', 'day': 'еден ден', 'days': '{0} дена', 'month': 'еден месец', 'months': '{0} месеци', 'year': 'една година', 'years': '{0} години', } meridians = { 'am': 'дп', 'pm': 'пп', 'AM': 'претпладне', 'PM': 'попладне', } month_names = ['', 'Јануари', 'Февруари', 'Март', 'Април', 'Мај', 'Јуни', 'Јули', 'Август', 'Септември', 'Октомври', 'Ноември', 'Декември'] month_abbreviations = ['', 'Јан.', ' Фев.', ' Мар.', ' Апр.', ' Мај', ' Јун.', ' Јул.', ' Авг.', ' Септ.', ' Окт.', ' Ноем.', ' Декем.'] day_names = ['', 'Понеделник', ' Вторник', ' Среда', ' Четврток', ' Петок', ' Сабота', ' Недела'] day_abbreviations = ['', 'Пон.', ' Вт.', ' Сре.', ' Чет.', ' Пет.', ' Саб.', ' Нед.'] class HebrewLocale(Locale): names = ['he', 'he_IL'] past = 'לפני {0}' future = 'בעוד {0}' timeframes = { 'now': 'הרגע', 'seconds': 'שניות', 'minute': 'דקה', 'minutes': '{0} דקות', 'hour': 'שעה', 'hours': '{0} שעות', '2-hours': 'שעתיים', 'day': 'יום', 'days': '{0} ימים', '2-days': 'יומיים', 'month': 'חודש', 'months': '{0} חודשים', '2-months': 'חודשיים', 'year': 'שנה', 'years': '{0} שנים', '2-years': 'שנתיים', } meridians = { 'am': 'לפנ"צ', 'pm': 'אחר"צ', 'AM': 'לפני הצהריים', 'PM': 'אחרי הצהריים', } month_names = ['', 'ינואר', 'פברואר', 'מרץ', 'אפריל', 'מאי', 'יוני', 'יולי', 'אוגוסט', 'ספטמבר', 'אוקטובר', 'נובמבר', 'דצמבר'] month_abbreviations = ['', 'ינו׳', 'פבר׳', 'מרץ', 'אפר׳', 'מאי', 'יוני', 'יולי', 'אוג׳', 'ספט׳', 'אוק׳', 'נוב׳', 'דצמ׳'] day_names = ['', 'שני', 'שלישי', 'רביעי', 'חמישי', 'שישי', 'שבת', 'ראשון'] day_abbreviations = ['', 'ב׳', 'ג׳', 'ד׳', 'ה׳', 'ו׳', 'ש׳', 'א׳'] def _format_timeframe(self, timeframe, delta): '''Hebrew couple of aware''' couple = '2-{0}'.format(timeframe) if abs(delta) == 2 and couple in self.timeframes: return self.timeframes[couple].format(abs(delta)) else: return self.timeframes[timeframe].format(abs(delta)) class MarathiLocale(Locale): names = ['mr'] past = '{0} आधी' future = '{0} नंतर' timeframes = { 'now': 'सद्य', 'seconds': 'सेकंद', 'minute': 'एक मिनिट ', 'minutes': '{0} मिनिट ', 'hour': 'एक तास', 'hours': '{0} तास', 'day': 'एक दिवस', 'days': '{0} दिवस', 'month': 'एक महिना ', 'months': '{0} महिने ', 'year': 'एक वर्ष ', 'years': '{0} वर्ष ', } meridians = { 'am': 'सकाळ', 'pm': 'संध्याकाळ', 'AM': 'सकाळ', 'PM': 'संध्याकाळ', } month_names = ['', 'जानेवारी', 'फेब्रुवारी', 'मार्च', 'एप्रिल', 'मे', 'जून', 'जुलै', 'अॉगस्ट', 'सप्टेंबर', 'अॉक्टोबर', 'नोव्हेंबर', 'डिसेंबर'] month_abbreviations = ['', 'जान', 'फेब्रु', 'मार्च', 'एप्रि', 'मे', 'जून', 'जुलै', 'अॉग', 'सप्टें', 'अॉक्टो', 'नोव्हें', 'डिसें'] day_names = ['', 'सोमवार', 'मंगळवार', 'बुधवार', 'गुरुवार', 'शुक्रवार', 'शनिवार', 'रविवार'] day_abbreviations = ['', 'सोम', 'मंगळ', 'बुध', 'गुरु', 'शुक्र', 'शनि', 'रवि'] def _map_locales(): locales = {} for cls_name, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass): if issubclass(cls, Locale): for name in cls.names: locales[name.lower()] = cls return locales class CatalaLocale(Locale): names = ['ca', 'ca_ca'] past = 'Fa {0}' future = '{0}' # I don't know what's the right phrase in catala for the future. timeframes = { 'now': 'Ara mateix', 'seconds': 'segons', 'minute': '1 minut', 'minutes': '{0} minuts', 'hour': 'una hora', 'hours': '{0} hores', 'day': 'un dia', 'days': '{0} dies', 'month': 'un mes', 'months': '{0} messos', 'year': 'un any', 'years': '{0} anys', } month_names = ['', 'Jener', 'Febrer', 'Març', 'Abril', 'Maig', 'Juny', 'Juliol', 'Agost', 'Setembre', 'Octubre', 'Novembre', 'Decembre'] month_abbreviations = ['', 'Jener', 'Febrer', 'Març', 'Abril', 'Maig', 'Juny', 'Juliol', 'Agost', 'Setembre', 'Octubre', 'Novembre', 'Decembre'] day_names = ['', 'Dilluns', 'Dimars', 'Dimecres', 'Dijous', 'Divendres', 'Disabte', 'Diumenge'] day_abbreviations = ['', 'Dilluns', 'Dimars', 'Dimecres', 'Dijous', 'Divendres', 'Disabte', 'Diumenge'] class BasqueLocale(Locale): names = ['eu', 'eu_eu'] past = 'duela {0}' future = '{0}' # I don't know what's the right phrase in Basque for the future. timeframes = { 'now': 'Orain', 'seconds': 'segundu', 'minute': 'minutu bat', 'minutes': '{0} minutu', 'hour': 'ordu bat', 'hours': '{0} ordu', 'day': 'egun bat', 'days': '{0} egun', 'month': 'hilabete bat', 'months': '{0} hilabet', 'year': 'urte bat', 'years': '{0} urte', } month_names = ['', 'Urtarrilak', 'Otsailak', 'Martxoak', 'Apirilak', 'Maiatzak', 'Ekainak', 'Uztailak', 'Abuztuak', 'Irailak', 'Urriak', 'Azaroak', 'Abenduak'] month_abbreviations = ['', 'urt', 'ots', 'mar', 'api', 'mai', 'eka', 'uzt', 'abu', 'ira', 'urr', 'aza', 'abe'] day_names = ['', 'Asteleehna', 'Asteartea', 'Asteazkena', 'Osteguna', 'Ostirala', 'Larunbata', 'Igandea'] day_abbreviations = ['', 'al', 'ar', 'az', 'og', 'ol', 'lr', 'ig'] class HungarianLocale(Locale): names = ['hu', 'hu_hu'] past = '{0} ezelőtt' future = '{0} múlva' timeframes = { 'now': 'éppen most', 'seconds': { 'past': 'másodpercekkel', 'future': 'pár másodperc' }, 'minute': {'past': 'egy perccel', 'future': 'egy perc'}, 'minutes': {'past': '{0} perccel', 'future': '{0} perc'}, 'hour': {'past': 'egy órával', 'future': 'egy óra'}, 'hours': {'past': '{0} órával', 'future': '{0} óra'}, 'day': { 'past': 'egy nappal', 'future': 'egy nap' }, 'days': { 'past': '{0} nappal', 'future': '{0} nap' }, 'month': {'past': 'egy hónappal', 'future': 'egy hónap'}, 'months': {'past': '{0} hónappal', 'future': '{0} hónap'}, 'year': {'past': 'egy évvel', 'future': 'egy év'}, 'years': {'past': '{0} évvel', 'future': '{0} év'}, } month_names = ['', 'Január', 'Február', 'Március', 'Április', 'Május', 'Június', 'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December'] month_abbreviations = ['', 'Jan', 'Febr', 'Márc', 'Ápr', 'Máj', 'Jún', 'Júl', 'Aug', 'Szept', 'Okt', 'Nov', 'Dec'] day_names = ['', 'Hétfő', 'Kedd', 'Szerda', 'Csütörtök', 'Péntek', 'Szombat', 'Vasárnap'] day_abbreviations = ['', 'Hét', 'Kedd', 'Szer', 'Csüt', 'Pént', 'Szom', 'Vas'] meridians = { 'am': 'de', 'pm': 'du', 'AM': 'DE', 'PM': 'DU', } def _format_timeframe(self, timeframe, delta): form = self.timeframes[timeframe] if isinstance(form, dict): if delta > 0: form = form['future'] else: form = form['past'] return form.format(abs(delta)) class ThaiLocale(Locale): names = ['th', 'th_th'] past = '{0}{1}ที่ผ่านมา' future = 'ในอีก{1}{0}' timeframes = { 'now': 'ขณะนี้', 'seconds': 'ไม่กี่วินาที', 'minute': '1 นาที', 'minutes': '{0} นาที', 'hour': '1 ชั่วโมง', 'hours': '{0} ชั่วโมง', 'day': '1 วัน', 'days': '{0} วัน', 'month': '1 เดือน', 'months': '{0} เดือน', 'year': '1 ปี', 'years': '{0} ปี', } month_names = ['', 'มกราคม', 'กุมภาพันธ์', 'มีนาคม', 'เมษายน', 'พฤษภาคม', 'มิถุนายน', 'กรกฏาคม', 'สิงหาคม', 'กันยายน', 'ตุลาคม', 'พฤศจิกายน', 'ธันวาคม'] month_abbreviations = ['', 'ม.ค.', 'ก.พ.', 'มี.ค.', 'เม.ย.', 'พ.ค.', 'มิ.ย.', 'ก.ค.', 'ส.ค.', 'ก.ย.', 'ต.ค.', 'พ.ย.', 'ธ.ค.'] day_names = ['', 'จันทร์', 'อังคาร', 'พุธ', 'พฤหัสบดี', 'ศุกร์', 'เสาร์', 'อาทิตย์'] day_abbreviations = ['', 'จ', 'อ', 'พ', 'พฤ', 'ศ', 'ส', 'อา'] meridians = { 'am': 'am', 'pm': 'pm', 'AM': 'AM', 'PM': 'PM', } BE_OFFSET = 543 def year_full(self, year): '''Thai always use Buddhist Era (BE) which is CE + 543''' year += self.BE_OFFSET return '{0:04d}'.format(year) def year_abbreviation(self, year): '''Thai always use Buddhist Era (BE) which is CE + 543''' year += self.BE_OFFSET return '{0:04d}'.format(year)[2:] def _format_relative(self, humanized, timeframe, delta): '''Thai normally doesn't have any space between words''' if timeframe == 'now': return humanized space = '' if timeframe == 'seconds' else ' ' direction = self.past if delta < 0 else self.future return direction.format(humanized, space) _locales = _map_locales() arrow-0.7.0/arrow/parser.py000066400000000000000000000226021260523235100156510ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import absolute_import from __future__ import unicode_literals from datetime import datetime from dateutil import tz import re from arrow import locales class ParserError(RuntimeError): pass class DateTimeParser(object): _FORMAT_RE = re.compile('(YYY?Y?|MM?M?M?|Do|DD?D?D?|HH?|hh?|mm?|ss?|SS?S?S?S?S?|ZZ?|a|A|X)') _ONE_THROUGH_SIX_DIGIT_RE = re.compile('\d{1,6}') _ONE_THROUGH_FIVE_DIGIT_RE = re.compile('\d{1,5}') _ONE_THROUGH_FOUR_DIGIT_RE = re.compile('\d{1,4}') _ONE_TWO_OR_THREE_DIGIT_RE = re.compile('\d{1,3}') _ONE_OR_TWO_DIGIT_RE = re.compile('\d{1,2}') _FOUR_DIGIT_RE = re.compile('\d{4}') _TWO_DIGIT_RE = re.compile('\d{2}') _TZ_RE = re.compile('[+\-]?\d{2}:?\d{2}') _BASE_INPUT_RE_MAP = { 'YYYY': _FOUR_DIGIT_RE, 'YY': _TWO_DIGIT_RE, 'MM': _TWO_DIGIT_RE, 'M': _ONE_OR_TWO_DIGIT_RE, 'DD': _TWO_DIGIT_RE, 'D': _ONE_OR_TWO_DIGIT_RE, 'HH': _TWO_DIGIT_RE, 'H': _ONE_OR_TWO_DIGIT_RE, 'hh': _TWO_DIGIT_RE, 'h': _ONE_OR_TWO_DIGIT_RE, 'mm': _TWO_DIGIT_RE, 'm': _ONE_OR_TWO_DIGIT_RE, 'ss': _TWO_DIGIT_RE, 's': _ONE_OR_TWO_DIGIT_RE, 'X': re.compile('\d+'), 'ZZ': _TZ_RE, 'Z': _TZ_RE, 'SSSSSS': _ONE_THROUGH_SIX_DIGIT_RE, 'SSSSS': _ONE_THROUGH_FIVE_DIGIT_RE, 'SSSS': _ONE_THROUGH_FOUR_DIGIT_RE, 'SSS': _ONE_TWO_OR_THREE_DIGIT_RE, 'SS': _ONE_OR_TWO_DIGIT_RE, 'S': re.compile('\d'), } def __init__(self, locale='en_us'): self.locale = locales.get_locale(locale) self._input_re_map = self._BASE_INPUT_RE_MAP.copy() self._input_re_map.update({ 'MMMM': self._choice_re(self.locale.month_names[1:], re.IGNORECASE), 'MMM': self._choice_re(self.locale.month_abbreviations[1:], re.IGNORECASE), 'Do': re.compile(self.locale.ordinal_day_re), 'a': self._choice_re( (self.locale.meridians['am'], self.locale.meridians['pm']) ), # note: 'A' token accepts both 'am/pm' and 'AM/PM' formats to # ensure backwards compatibility of this token 'A': self._choice_re(self.locale.meridians.values()) }) def parse_iso(self, string): has_time = 'T' in string or ' ' in string.strip() space_divider = ' ' in string.strip() if has_time: if space_divider: date_string, time_string = string.split(' ', 1) else: date_string, time_string = string.split('T', 1) time_parts = re.split('[+-]', time_string, 1) has_tz = len(time_parts) > 1 has_seconds = time_parts[0].count(':') > 1 has_subseconds = '.' in time_parts[0] if has_subseconds: subseconds_token = 'S' * min(len(re.split('\D+', time_parts[0].split('.')[1], 1)[0]), 6) formats = ['YYYY-MM-DDTHH:mm:ss.%s' % subseconds_token] elif has_seconds: formats = ['YYYY-MM-DDTHH:mm:ss'] else: formats = ['YYYY-MM-DDTHH:mm'] else: has_tz = False formats = [ 'YYYY-MM-DD', 'YYYY-MM', 'YYYY', ] if has_time and has_tz: formats = [f + 'Z' for f in formats] if space_divider: formats = [item.replace('T', ' ', 1) for item in formats] return self._parse_multiformat(string, formats) def parse(self, string, fmt): if isinstance(fmt, list): return self._parse_multiformat(string, fmt) # fmt is a string of tokens like 'YYYY-MM-DD' # we construct a new string by replacing each # token by its pattern: # 'YYYY-MM-DD' -> '(?P\d{4})-(?P\d{2})-(?P
\d{2})' fmt_pattern = fmt tokens = [] offset = 0 for m in self._FORMAT_RE.finditer(fmt): token = m.group(0) try: input_re = self._input_re_map[token] except KeyError: raise ParserError('Unrecognized token \'{0}\''.format(token)) input_pattern = '(?P<{0}>{1})'.format(token, input_re.pattern) tokens.append(token) # a pattern doesn't have the same length as the token # it replaces! We keep the difference in the offset variable. # This works because the string is scanned left-to-right and matches # are returned in the order found by finditer. fmt_pattern = fmt_pattern[:m.start() + offset] + input_pattern + fmt_pattern[m.end() + offset:] offset += len(input_pattern) - (m.end() - m.start()) match = re.search(fmt_pattern, string, flags=re.IGNORECASE) if match is None: raise ParserError('Failed to match \'{0}\' when parsing \'{1}\''.format(fmt_pattern, string)) parts = {} for token in tokens: if token == 'Do': value = match.group('value') else: value = match.group(token) self._parse_token(token, value, parts) return self._build_datetime(parts) def _parse_token(self, token, value, parts): if token == 'YYYY': parts['year'] = int(value) elif token == 'YY': value = int(value) parts['year'] = 1900 + value if value > 68 else 2000 + value elif token in ['MMMM', 'MMM']: parts['month'] = self.locale.month_number(value.capitalize()) elif token in ['MM', 'M']: parts['month'] = int(value) elif token in ['DD', 'D']: parts['day'] = int(value) elif token in ['Do']: parts['day'] = int(value) elif token.upper() in ['HH', 'H']: parts['hour'] = int(value) elif token in ['mm', 'm']: parts['minute'] = int(value) elif token in ['ss', 's']: parts['second'] = int(value) elif token == 'SSSSSS': parts['microsecond'] = int(value) elif token == 'SSSSS': parts['microsecond'] = int(value) * 10 elif token == 'SSSS': parts['microsecond'] = int(value) * 100 elif token == 'SSS': parts['microsecond'] = int(value) * 1000 elif token == 'SS': parts['microsecond'] = int(value) * 10000 elif token == 'S': parts['microsecond'] = int(value) * 100000 elif token == 'X': parts['timestamp'] = int(value) elif token in ['ZZ', 'Z']: parts['tzinfo'] = TzinfoParser.parse(value) elif token in ['a', 'A']: if value in ( self.locale.meridians['am'], self.locale.meridians['AM'] ): parts['am_pm'] = 'am' elif value in ( self.locale.meridians['pm'], self.locale.meridians['PM'] ): parts['am_pm'] = 'pm' @staticmethod def _build_datetime(parts): timestamp = parts.get('timestamp') if timestamp: tz_utc = tz.tzutc() return datetime.fromtimestamp(timestamp, tz=tz_utc) am_pm = parts.get('am_pm') hour = parts.get('hour', 0) if am_pm == 'pm' and hour < 12: hour += 12 elif am_pm == 'am' and hour == 12: hour = 0 return datetime(year=parts.get('year', 1), month=parts.get('month', 1), day=parts.get('day', 1), hour=hour, minute=parts.get('minute', 0), second=parts.get('second', 0), microsecond=parts.get('microsecond', 0), tzinfo=parts.get('tzinfo')) def _parse_multiformat(self, string, formats): _datetime = None for fmt in formats: try: _datetime = self.parse(string, fmt) break except: pass if _datetime is None: raise ParserError('Could not match input to any of {0} on \'{1}\''.format(formats, string)) return _datetime @staticmethod def _map_lookup(input_map, key): try: return input_map[key] except KeyError: raise ParserError('Could not match "{0}" to {1}'.format(key, input_map)) @staticmethod def _try_timestamp(string): try: return float(string) except: return None @staticmethod def _choice_re(choices, flags=0): return re.compile('({0})'.format('|'.join(choices)), flags=flags) class TzinfoParser(object): _TZINFO_RE = re.compile('([+\-])?(\d\d):?(\d\d)') @classmethod def parse(cls, string): tzinfo = None if string == 'local': tzinfo = tz.tzlocal() elif string in ['utc', 'UTC']: tzinfo = tz.tzutc() else: iso_match = cls._TZINFO_RE.match(string) if iso_match: sign, hours, minutes = iso_match.groups() seconds = int(hours) * 3600 + int(minutes) * 60 if sign == '-': seconds *= -1 tzinfo = tz.tzoffset(None, seconds) else: tzinfo = tz.gettz(string) if tzinfo is None: raise ParserError('Could not parse timezone expression "{0}"', string) return tzinfo arrow-0.7.0/arrow/util.py000066400000000000000000000017701260523235100153350ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import absolute_import from datetime import timedelta import sys # python 2.6 / 2.7 definitions for total_seconds function. def _total_seconds_27(td): # pragma: no cover return td.total_seconds() def _total_seconds_26(td): return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 1e6) / 1e6 # get version info and assign correct total_seconds function. version = '{0}.{1}.{2}'.format(*sys.version_info[:3]) if version < '2.7': # pragma: no cover total_seconds = _total_seconds_26 else: # pragma: no cover total_seconds = _total_seconds_27 def is_timestamp(value): try: float(value) return True except: return False # python 2.7 / 3.0+ definitions for isstr function. try: # pragma: no cover basestring def isstr(s): return isinstance(s, basestring) except NameError: #pragma: no cover def isstr(s): return isinstance(s, str) __all__ = ['total_seconds', 'is_timestamp', 'isstr'] arrow-0.7.0/docs/000077500000000000000000000000001260523235100135775ustar00rootroot00000000000000arrow-0.7.0/docs/Makefile000066400000000000000000000151461260523235100152460ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Arrow.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Arrow.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/Arrow" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Arrow" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." arrow-0.7.0/docs/_themes/000077500000000000000000000000001260523235100152235ustar00rootroot00000000000000arrow-0.7.0/docs/_themes/COPYING.txt000066400000000000000000000012141260523235100170720ustar00rootroot00000000000000Copyright (c) 2011 Vimalkumar Velayudhan This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see arrow-0.7.0/docs/_themes/README.rst000066400000000000000000000017251260523235100167170ustar00rootroot00000000000000sphinx-themes ============= These are some themes for Python `Sphinx `_ documentation projects. Preview ------- To see how these themes look, visit http://vimalkumar.in/sphinx-themes Download -------- Released versions are available from https://github.com/vkvn/sphinx-themes/downloads You can also download this repository as a `zip archive `_ Support ------- If there are problems with any of these themes, you can file a bug report at https://github.com/vkvn/sphinx-themes/issues Themes are licensed under the `GNU General Public License `_. .. raw:: html Endorse vkvn on Coderwall arrow-0.7.0/docs/_themes/f6/000077500000000000000000000000001260523235100155365ustar00rootroot00000000000000arrow-0.7.0/docs/_themes/f6/NEWS.txt000066400000000000000000000001071260523235100170510ustar00rootroot00000000000000News ==== 1.0 --- * Release date: 2012-11-01 * Initial release arrow-0.7.0/docs/_themes/f6/README.rst000066400000000000000000000015001260523235100172210ustar00rootroot00000000000000f6 theme for Python Sphinx ========================== f6? --- A light theme for Python Sphinx documentation projects. Mostly white -> #ffffff -> f6 Preview ------- http://vimalkumar.in/sphinx-themes/f6 Download -------- Released versions are available from http://github.com/vkvn/sphinx-themes/downloads Installation ------------ #. Extract the archive. #. Modify ``conf.py`` of an existing Sphinx project or create new project using ``sphinx-quickstart``. #. Change the ``html_theme`` parameter to ``f6``. #. Change the ``html_theme_path`` to the location containing the extracted archive. License ------- `GNU General Public License `_ Credits ------- Modified from the default Sphinx theme -- Sphinxdoc Background pattern from http://subtlepatterns.com arrow-0.7.0/docs/_themes/f6/layout.html000066400000000000000000000040531260523235100177430ustar00rootroot00000000000000{% extends "basic/layout.html" %} {%- block doctype -%} {%- endblock -%} {%- block extrahead -%} {%- endblock -%} {# put the sidebar before the body #} {% block sidebarlogo %} Fork me on GitHub

github.com/crsmithdev/arrow

{% endblock%} {% block sidebar1 %}{{ sidebar() }}{% endblock %} {% block sidebar2 %}{% endblock %} {%- block relbar1 %}{% endblock %} {%- block footer %} {%- endblock %} arrow-0.7.0/docs/_themes/f6/static/000077500000000000000000000000001260523235100170255ustar00rootroot00000000000000arrow-0.7.0/docs/_themes/f6/static/brillant.png000066400000000000000000000001251260523235100213400ustar00rootroot00000000000000PNG  IHDRJ"IDATc !  AIENDB`arrow-0.7.0/docs/_themes/f6/static/f6.css000066400000000000000000000165331260523235100200620ustar00rootroot00000000000000/* f6.css * Modified from sphinxdoc.css of the sphinxdoc theme. */ @import url("basic.css"); /* -- page layout ----------------------------------------------------------- */ body { font-family: 'Source Sans Pro', sans-serif; font-size: 16px; line-height: 150%; text-align: center; color: #4d4d4c; padding: 0; margin: 0px 80px 0px 80px; min-width: 740px; border: 1px solid #d6d6d6; background: url("brilliant.png") repeat; margin: 0px 200px 0px 200px; } div.document { text-align: left; background-repeat: repeat-x; } div.bodywrapper { margin: 0 240px 0 0; border-right: 1px dotted #d6d6d6; } div.body { background-color: white; margin: 0; padding: 0.5em 20px 20px 20px; } div.related { font-size: 1em; background-color: #efefef; color: #4d4d4c; padding: 5px 0px; border-bottom: 1px solid #d6d6d6; } div.related ul { height: 2em; margin: 2px; } div.related ul li { margin: 0; padding: 0; height: 2em; float: left; } div.related ul li.right { float: right; margin-right: 5px; } div.related ul li a { margin: 0; padding: 2px 5px; line-height: 2em; text-decoration: none; color: #4d4d4c; } div.related ul li a:hover { color: #4271ae; -webkit-border-radius: 2px; -moz-border-radius: 2px; border-radius: 2px; } div.sphinxsidebarwrapper { padding: 0; } div.sphinxsidebar { margin: 0; padding: 0.5em 15px 15px 0; width: 210px; float: right; font-size: 0.9em; text-align: left; } div.sphinxsidebar h3, div.sphinxsidebar h4 { font-size: 1em; padding: 0.5em 0 0.5em 0; text-transform: uppercase; } div.sphinxsidebar h3 a { color: #4271ae; } div.sphinxsidebar ul { padding-left: 1.5em; margin-top: 7px; padding: 0; line-height: 150%; color: #4d4d4c; } div.sphinxsidebar ul li { color: #8e908c; } div.sphinxsidebar ul ul { margin-left: 1em; } div.sphinxsidebar input { border: 1px solid #efefef; font-family: inherit; } div.sphinxsidebar #searchbox input[type="submit"] { color: white; background-color: #4271ae; } div.footer { color: #4d4d4c; padding: 3px 8px 3px 0; clear: both; font-size: 0.8em; } div.footer a { color: #4d4d4c; text-decoration: none; border-bottom: 1px dotted #4271ae; } div.footer a:hover { color: #4271ae; text-decoration: none; border-bottom: 1px dotted #4271ae; } /* -- body styles ----------------------------------------------------------- */ p { margin: 0.8em 0 0.5em 0; } div.body a, div.sphinxsidebarwrapper a { color: #4d4d4c; text-decoration: none; border-bottom: 1px dotted #4271ae; } div.body a:hover, div.sphinxsidebarwrapper a:hover { color: #4271ae; border-bottom: 1px dotted #4271ae; } h1, h2, h3, h4, h5, h6 { font-family: "Source Sans Pro", sans-serif; font-weight: 400; text-shadow: #efefef 0.1em 0.1em 0.1em; } h1 { margin: 0; padding: 0.7em 0 0.3em 0; line-height: 1.2em; text-shadow: #efefef 0.1em 0.1em 0.1em; } h2 { margin: 1.3em 0 0.2em 0; padding: 0 0 10px 0; } h3 { margin: 1em 0 -0.3em 0; padding-bottom: 5px; } h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor { display: none; margin: 0 0 0 0.3em; padding: 0 0.2em 0 0.2em; color: #aaa!important; } h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor { display: inline; } h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover, h5 a.anchor:hover, h6 a.anchor:hover { color: #777; background-color: #eee; } a.headerlink { color: #4d4d4c!important; font-size: 1em; margin-left: 6px; padding: 0 4px 0 4px; text-decoration: none!important; } a.headerlink:hover { background-color: #efefef; color: white!important; } cite, code, tt { font-family: 'Source Code Pro', monospace; font-size: 0.9em; letter-spacing: 0.01em; background-color: #fbfbfb; font-style: normal; border: 1px dotted #efefef; border-radius: 2px; padding: 0 2px; } hr { border: 1px solid #d6d6d6; margin: 2em; } .highlight { -webkit-border-radius: 2px; -moz-border-radius: 2px; border-radius: 2px; background: #f0f0f0 !important; } .highlighted { background-color: #4271ae; color: white; padding: 0 0.3em; } pre { font-family: 'Source Code Pro', monospace; font-style: normal; font-size: 0.9em; letter-spacing: 0.015em; line-height: 130%; padding: 0.7em; white-space: pre-wrap; /* css-3 */ white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ white-space: -pre-wrap; /* Opera 4-6 */ white-space: -o-pre-wrap; /* Opera 7 */ word-wrap: break-word; /* Internet Explorer 5.5+ */ } pre a { color: inherit; text-decoration: underline; } td.linenos pre { padding: 0.5em 0; } div.quotebar { background-color: #f8f8f8; max-width: 250px; float: right; padding: 2px 7px; border: 1px solid #ccc; } div.topic { background-color: #f8f8f8; } table { border-collapse: collapse; margin: 0 -0.5em 0 -0.5em; } table.docutils { width: 100% !important; margin-left: 2px; border: 0; } table.docutils tbody tr td { padding-top: 5px; padding-bottom: 5px; border: 0; } table.docutils thead tr th { padding-top: 5px; padding-bottom: 5px; border: 0; } .row-even { background-color: #F0F0F0; } table td, table th { padding: 0.2em 0.5em 0.2em 0.5em; } div.admonition { font-size: 0.9em; margin: 1em 0 1em 0; background-color: #fdfdfd; padding: 0; -moz-box-shadow: 0px 8px 6px -8px #d6d6d6; -webkit-box-shadow: 0px 8px 6px -8px #d6d6d6; box-shadow: 0px 8px 6px -8px #d6d6d6; } div.admonition p { margin: 0.5em 1em 0.5em 1em; padding: 0.2em; } div.admonition pre { margin: 0.4em 1em 0.4em 1em; } div.admonition p.admonition-title { margin: 0; padding: 0.2em 0 0.2em 0.6em; background-color: white; border-bottom: 1px solid #4271ae; font-weight: 600; font-size: 1.2em; color: #4271ae; text-transform: uppercase; } div.note p.admonition-title { color: #4271ae; border-bottom: 1px solid #4271ae; } div.warning p.admonition-title, div.important p.admonition-title { color: #f5871f; border-bottom: 1px solid #f5871f; } div.hint p.admonition-title, div.tip p.admonition-title { color: #718c00; border-bottom: 1px solid #718c00; } div.caution p.admonition-title, div.attention p.admonition-title, div.danger p.admonition-title, div.error p.admonition-title { color: #c82829; border-bottom: 1px solid #c82829; } div.admonition ul, div.admonition ol { margin: 0.1em 0.5em 0.5em 3em; padding: 0; } div.versioninfo { margin: 1em 0 0 0; border: 1px solid #eee; background-color: #DDEAF0; padding: 8px; line-height: 1.3em; font-size: 0.9em; } div.viewcode-block:target { background-color: #f4debf; border-top: 1px solid #eee; border-bottom: 1px solid #eee; } arrow-0.7.0/docs/_themes/f6/theme.conf000066400000000000000000000000571260523235100175110ustar00rootroot00000000000000[theme] inherit = basic stylesheet = f6.css arrow-0.7.0/docs/conf.py000066400000000000000000000174341260523235100151070ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Arrow documentation build configuration file, created by # sphinx-quickstart on Mon May 6 15:25:39 2013. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath('../')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'Arrow' copyright = u'2013, Chris Smith' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '0.4.4' # The full version, including alpha/beta/rc tags. release = '0.4.4' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'f6' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. html_theme_path = ['_themes'] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. html_use_index = False # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. html_show_sourcelink = False # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'Arrowdoc' # -- Options for LaTeX output -------------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'Arrow.tex', u'Arrow Documentation', u'Chris Smith', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'arrow', u'Arrow Documentation', [u'Chris Smith'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'Arrow', u'Arrow Documentation', u'Chris Smith', 'Arrow', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False autodoc_member_order = 'bysource' arrow-0.7.0/docs/index.rst000066400000000000000000000370431260523235100154470ustar00rootroot00000000000000========================================= Arrow: better dates and times for Python ========================================= ----- What? ----- Arrow is a Python library that offers a sensible, human-friendly approach to creating, manipulating, formatting and converting dates, times, and timestamps. It implements and updates the datetime type, plugging gaps in functionality, and provides an intelligent module API that supports many common creation scenarios. Simply put, it helps you work with dates and times with fewer imports and a lot less code. Arrow is heavily inspired by `moment.js `_ and `requests `_. ---- Why? ---- Python's standard library and some other low-level modules have near-complete date, time and time zone functionality but don't work very well from a usability perspective: - Too many modules: datetime, time, calendar, dateutil, pytz and more - Too many types: date, time, datetime, tzinfo, timedelta, relativedelta, etc. - Time zones and timestamp conversions are verbose and unpleasant - Time zone naivety is the norm - Gaps in functionality: ISO-8601 parsing, time spans, humanization -------- Features -------- - Fully implemented, drop-in replacement for datetime - Supports Python 2.6, 2.7 and 3.3 - Time zone-aware & UTC by default - Provides super-simple creation options for many common input scenarios - Updated .replace method with support for relative offsets, including weeks - Formats and parses strings, including ISO-8601-formatted strings automatically - Timezone conversion - Timestamp available as a property - Generates time spans, ranges, floors and ceilings in time frames from year to microsecond - Humanizes and supports a growing list of contributed locales - Extensible for your own Arrow-derived types ---------- Quickstart ---------- .. code-block:: bash $ pip install arrow .. code-block:: python >>> import arrow >>> utc = arrow.utcnow() >>> utc >>> utc = utc.replace(hours=-1) >>> utc >>> local = utc.to('US/Pacific') >>> local >>> arrow.get('2013-05-11T21:23:58.970460+00:00') >>> local.timestamp 1368303838 >>> local.format() '2013-05-11 13:23:58 -07:00' >>> local.format('YYYY-MM-DD HH:mm:ss ZZ') '2013-05-11 13:23:58 -07:00' >>> local.humanize() 'an hour ago' >>> local.humanize(locale='ko_kr') '1시간 전' ------------ User's Guide ------------ Creation ======== Get 'now' easily: .. code-block:: python >>> arrow.utcnow() >>> arrow.now() >>> arrow.now('US/Pacific') Create from timestamps (ints or floats, or strings that convert to a float): .. code-block:: python >>> arrow.get(1367900664) >>> arrow.get('1367900664') >>> arrow.get(1367900664.152325) >>> arrow.get('1367900664.152325') Use a naive or timezone-aware datetime, or flexibly specify a time zone: .. code-block:: python >>> arrow.get(datetime.utcnow()) >>> arrow.get(datetime.now(), 'US/Pacific') >>> from dateutil import tz >>> arrow.get(datetime.now(), tz.gettz('US/Pacific')) >>> arrow.get(datetime.now(tz.gettz('US/Pacific'))) Parse from a string: .. code-block:: python >>> arrow.get('2013-05-05 12:30:45', 'YYYY-MM-DD HH:mm:ss') Search a date in a string: .. code-block:: python >>> arrow.get('June was born in May 1980', 'MMMM YYYY') Many ISO-8601 compliant strings are recognized and parsed without a format string: >>> arrow.get('2013-09-30T15:34:00.000-07:00') Arrow objects can be instantiated directly too, with the same arguments as a datetime: .. code-block:: python >>> arrow.get(2013, 5, 5) >>> arrow.Arrow(2013, 5, 5) Properties ========== Get a datetime or timestamp representation: .. code-block:: python >>> a = arrow.utcnow() >>> a.datetime datetime.datetime(2013, 5, 7, 4, 38, 15, 447644, tzinfo=tzutc()) >>> a.timestamp 1367901495 Get a naive datetime, and tzinfo: .. code-block:: python >>> a.naive datetime.datetime(2013, 5, 7, 4, 38, 15, 447644) >>> a.tzinfo tzutc() Get any datetime value: .. code-block:: python >>> a.year 2013 Call datetime functions that return properties: .. code-block:: python >>> a.date() datetime.date(2013, 5, 7) >>> a.time() datetime.time(4, 38, 15, 447644) Replace & shift =============== Get a new :class:`Arrow ` object, with altered attributes, just as you would with a datetime: .. code-block:: python >>> arw = arrow.utcnow() >>> arw >>> arw.replace(hour=4, minute=40) Or, get one with attributes shifted forward or backward: .. code-block:: python >>> arw.replace(weeks=+3) Format ====== .. code-block:: python >>> arrow.utcnow().format('YYYY-MM-DD HH:mm:ss ZZ') '2013-05-07 05:23:16 -00:00' Convert ======= Convert to timezones by name or tzinfo: .. code-block:: python >>> utc = arrow.utcnow() >>> utc >>> utc.to('US/Pacific') >>> utc.to(tz.gettz('US/Pacific')) Or using shorthand: .. code-block:: python >>> utc.to('local') >>> utc.to('local').to('utc') Humanize ======== Humanize relative to now: .. code-block:: python >>> past = arrow.utcnow().replace(hours=-1) >>> past.humanize() 'an hour ago' Or another Arrow, or datetime: .. code-block:: python >>> present = arrow.utcnow() >>> future = present.replace(hours=2) >>> future.humanize(present) 'in 2 hours' Support for a growing number of locales (see `locales.py` for supported languages): .. code-block:: python >>> future = arrow.utcnow().replace(hours=1) >>> future.humanize(a, locale='ru') 'через 2 час(а,ов)' Ranges & spans ============== Get the time span of any unit: .. code-block:: python >>> arrow.utcnow().span('hour') (, ) Or just get the floor and ceiling: .. code-block:: python >>> arrow.utcnow().floor('hour') >>> arrow.utcnow().ceil('hour') You can also get a range of time spans: .. code-block:: python >>> start = datetime(2013, 5, 5, 12, 30) >>> end = datetime(2013, 5, 5, 17, 15) >>> for r in arrow.Arrow.span_range('hour', start, end): ... print r ... (, ) (, ) (, ) (, ) (, ) Or just iterate over a range of time: .. code-block:: python >>> start = datetime(2013, 5, 5, 12, 30) >>> end = datetime(2013, 5, 5, 17, 15) >>> for r in arrow.Arrow.range('hour', start, end): ... print repr(r) ... .. toctree:: :maxdepth: 2 Factories ========= Use factories to harness Arrow's module API for a custom Arrow-derived type. First, derive your type: .. code-block:: python >>> class CustomArrow(arrow.Arrow): ... ... def days_till_xmas(self): ... ... xmas = arrow.Arrow(self.year, 12, 25) ... ... if self > xmas: ... xmas = xmas.replace(years=1) ... ... return (xmas - self).days Then get and use a factory for it: .. code-block:: python >>> factory = arrow.Factory(CustomArrow) >>> custom = factory.utcnow() >>> custom >>> >>> custom.days_till_xmas() >>> 211 Tokens ====== Use the following tokens in parsing and formatting. Note that they're not the same as the tokens for `strptime(3) `_: +--------------------------------+--------------+-------------------------------------------+ | |Token |Output | +================================+==============+===========================================+ |**Year** |YYYY |2000, 2001, 2002 ... 2012, 2013 | +--------------------------------+--------------+-------------------------------------------+ | |YY |00, 01, 02 ... 12, 13 | +--------------------------------+--------------+-------------------------------------------+ |**Month** |MMMM |January, February, March ... [#t1]_ | +--------------------------------+--------------+-------------------------------------------+ | |MMM |Jan, Feb, Mar ... [#t1]_ | +--------------------------------+--------------+-------------------------------------------+ | |MM |01, 02, 03 ... 11, 12 | +--------------------------------+--------------+-------------------------------------------+ | |M |1, 2, 3 ... 11, 12 | +--------------------------------+--------------+-------------------------------------------+ |**Day of Year** |DDDD |001, 002, 003 ... 364, 365 | +--------------------------------+--------------+-------------------------------------------+ | |DDD |1, 2, 3 ... 4, 5 | +--------------------------------+--------------+-------------------------------------------+ |**Day of Month** |DD |01, 02, 03 ... 30, 31 | +--------------------------------+--------------+-------------------------------------------+ | |D |1, 2, 3 ... 30, 31 | +--------------------------------+--------------+-------------------------------------------+ | |Do |1st, 2nd, 3rd ... 30th, 31st | +--------------------------------+--------------+-------------------------------------------+ |**Day of Week** |dddd |Monday, Tuesday, Wednesday ... [#t2]_ | +--------------------------------+--------------+-------------------------------------------+ | |ddd |Mon, Tue, Wed ... [#t2]_ | +--------------------------------+--------------+-------------------------------------------+ | |d |1, 2, 3 ... 6, 7 | +--------------------------------+--------------+-------------------------------------------+ |**Hour** |HH |00, 01, 02 ... 23, 24 | +--------------------------------+--------------+-------------------------------------------+ | |H |0, 1, 2 ... 23, 24 | +--------------------------------+--------------+-------------------------------------------+ | |hh |01, 02, 03 ... 11, 12 | +--------------------------------+--------------+-------------------------------------------+ | |h |1, 2, 3 ... 11, 12 | +--------------------------------+--------------+-------------------------------------------+ |**AM / PM** |A |AM, PM, am, pm [#t1]_ | +--------------------------------+--------------+-------------------------------------------+ | |a |am, pm [#t1]_ | +--------------------------------+--------------+-------------------------------------------+ |**Minute** |mm |00, 01, 02 ... 58, 59 | +--------------------------------+--------------+-------------------------------------------+ | |m |0, 1, 2 ... 58, 59 | +--------------------------------+--------------+-------------------------------------------+ |**Second** |ss |00, 01, 02 ... 58, 59 | +--------------------------------+--------------+-------------------------------------------+ | |s |0, 1, 2 ... 58, 59 | +--------------------------------+--------------+-------------------------------------------+ |**Sub-second** |SSS |000, 001, 002 ... 998, 999 | +--------------------------------+--------------+-------------------------------------------+ | |SS |00, 01, 02 ... 98, 99 | +--------------------------------+--------------+-------------------------------------------+ | |S |0, 1, 2 ... 8, 9 | +--------------------------------+--------------+-------------------------------------------+ |**Timezone** |ZZ |-07:00, -06:00 ... +06:00, +07:00 | +--------------------------------+--------------+-------------------------------------------+ | |Z |-0700, -0600 ... +0600, +0700 | +--------------------------------+--------------+-------------------------------------------+ |**Timestamp** |X |1381685817 | +--------------------------------+--------------+-------------------------------------------+ .. rubric:: Footnotes .. [#t1] localization support for parsing and formatting .. [#t2] localization support only for formatting --------- API Guide --------- arrow.arrow =========== .. automodule:: arrow.arrow :members: arrow.factory ============= .. automodule:: arrow.factory :members: arrow.api ========= .. automodule:: arrow.api :members: arrow.locale ============ .. automodule:: arrow.locales :members: arrow-0.7.0/requirements.txt000066400000000000000000000001331260523235100161300ustar00rootroot00000000000000python-dateutil==2.1 nose==1.3.0 nose-cov==1.6 chai==0.4.8 sphinx==1.2b1 simplejson==3.6.5 arrow-0.7.0/requirements26.txt000066400000000000000000000000141260523235100162760ustar00rootroot00000000000000chai==0.3.1 arrow-0.7.0/setup.py000066400000000000000000000025011260523235100143570ustar00rootroot00000000000000import codecs import os.path import re try: from setuptools import setup except ImportError: from distutils.core import setup def fpath(name): return os.path.join(os.path.dirname(__file__), name) def read(fname): return codecs.open(fpath(fname), encoding='utf-8').read() def grep(attrname): pattern = r"{0}\W*=\W*'([^']+)'".format(attrname) strval, = re.findall(pattern, file_text) return strval file_text = read(fpath('arrow/__init__.py')) setup( name='arrow', version=grep('__version__'), description='Better dates and times for Python', long_description=read(fpath('README.rst')), url='https://github.com/crsmithdev/arrow/', author='Chris Smith', author_email="crsmithdev@gmail.com", license='Apache 2.0', packages=['arrow'], zip_safe=False, install_requires=[ 'python-dateutil' ], test_suite="tests", classifiers=[ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'License :: OSI Approved :: Apache Software License', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Topic :: Software Development :: Libraries :: Python Modules' ] ) arrow-0.7.0/tests/000077500000000000000000000000001260523235100140115ustar00rootroot00000000000000arrow-0.7.0/tests/__init__.py000066400000000000000000000000001260523235100161100ustar00rootroot00000000000000arrow-0.7.0/tests/api_tests.py000066400000000000000000000014671260523235100163660ustar00rootroot00000000000000from chai import Chai from datetime import datetime from dateutil import tz import time from arrow import api, factory, arrow, util class ModuleTests(Chai): def test_get(self): expect(api._factory.get).args(1, b=2).returns('result') assertEqual(api.get(1, b=2), 'result') def test_utcnow(self): expect(api._factory.utcnow).returns('utcnow') assertEqual(api.utcnow(), 'utcnow') def test_now(self): expect(api._factory.now).args('tz').returns('now') assertEqual(api.now('tz'), 'now') def test_factory(self): class MockCustomArrowClass(arrow.Arrow): pass result = api.factory(MockCustomArrowClass) assertIsInstance(result, factory.ArrowFactory) assertIsInstance(result.utcnow(), MockCustomArrowClass) arrow-0.7.0/tests/arrow_tests.py000066400000000000000000001022131260523235100167360ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import absolute_import from __future__ import unicode_literals from chai import Chai from datetime import date, datetime, timedelta from dateutil import tz import simplejson as json import calendar import pickle import time import sys from arrow import arrow, util def assertDtEqual(dt1, dt2, within=10): assertEqual(dt1.tzinfo, dt2.tzinfo) assertTrue(abs(util.total_seconds(dt1 - dt2)) < within) class ArrowInitTests(Chai): def test_init(self): result = arrow.Arrow(2013, 2, 2, 12, 30, 45, 999999) expected = datetime(2013, 2, 2, 12, 30, 45, 999999, tzinfo=tz.tzutc()) assertEqual(result._datetime, expected) class ArrowFactoryTests(Chai): def test_now(self): result = arrow.Arrow.now() assertDtEqual(result._datetime, datetime.now().replace(tzinfo=tz.tzlocal())) def test_utcnow(self): result = arrow.Arrow.utcnow() assertDtEqual(result._datetime, datetime.utcnow().replace(tzinfo=tz.tzutc())) def test_fromtimestamp(self): timestamp = time.time() result = arrow.Arrow.fromtimestamp(timestamp) assertDtEqual(result._datetime, datetime.now().replace(tzinfo=tz.tzlocal())) def test_fromdatetime(self): dt = datetime(2013, 2, 3, 12, 30, 45, 1) result = arrow.Arrow.fromdatetime(dt) assertEqual(result._datetime, dt.replace(tzinfo=tz.tzutc())) def test_fromdatetime_dt_tzinfo(self): dt = datetime(2013, 2, 3, 12, 30, 45, 1, tzinfo=tz.gettz('US/Pacific')) result = arrow.Arrow.fromdatetime(dt) assertEqual(result._datetime, dt.replace(tzinfo=tz.gettz('US/Pacific'))) def test_fromdatetime_tzinfo_arg(self): dt = datetime(2013, 2, 3, 12, 30, 45, 1) result = arrow.Arrow.fromdatetime(dt, tz.gettz('US/Pacific')) assertEqual(result._datetime, dt.replace(tzinfo=tz.gettz('US/Pacific'))) def test_fromdate(self): dt = date(2013, 2, 3) result = arrow.Arrow.fromdate(dt, tz.gettz('US/Pacific')) assertEqual(result._datetime, datetime(2013, 2, 3, tzinfo=tz.gettz('US/Pacific'))) def test_strptime(self): formatted = datetime(2013, 2, 3, 12, 30, 45).strftime('%Y-%m-%d %H:%M:%S') result = arrow.Arrow.strptime(formatted, '%Y-%m-%d %H:%M:%S') assertEqual(result._datetime, datetime(2013, 2, 3, 12, 30, 45, tzinfo=tz.tzutc())) class ArrowRepresentationTests(Chai): def setUp(self): super(ArrowRepresentationTests, self).setUp() self.arrow = arrow.Arrow(2013, 2, 3, 12, 30, 45, 1) def test_repr(self): result = self.arrow.__repr__() assertEqual(result, ''.format(self.arrow._datetime.isoformat())) def test_str(self): result = self.arrow.__str__() assertEqual(result, self.arrow._datetime.isoformat()) def test_hash(self): result = self.arrow.__hash__() assertEqual(result, self.arrow._datetime.__hash__()) def test_format(self): result = '{0:YYYY-MM-DD}'.format(self.arrow) assertEqual(result, '2013-02-03') def test_bare_format(self): result = self.arrow.format() assertEqual(result, '2013-02-03 12:30:45-00:00') def test_format_no_format_string(self): result = '{0}'.format(self.arrow) assertEqual(result, str(self.arrow)) def test_clone(self): result = self.arrow.clone() assertTrue(result is not self.arrow) assertEqual(result._datetime, self.arrow._datetime) class ArrowAttributeTests(Chai): def setUp(self): super(ArrowAttributeTests, self).setUp() self.arrow = arrow.Arrow(2013, 1, 1) def test_getattr_base(self): with assertRaises(AttributeError): self.arrow.prop def test_getattr_week(self): assertEqual(self.arrow.week, 1) def test_getattr_dt_value(self): assertEqual(self.arrow.year, 2013) def test_tzinfo(self): self.arrow.tzinfo = tz.gettz('PST') assertEqual(self.arrow.tzinfo, tz.gettz('PST')) def test_naive(self): assertEqual(self.arrow.naive, self.arrow._datetime.replace(tzinfo=None)) def test_timestamp(self): assertEqual(self.arrow.timestamp, calendar.timegm(self.arrow._datetime.utctimetuple())) def test_float_timestamp(self): result = self.arrow.float_timestamp - self.arrow.timestamp assertEqual(result, self.arrow.microsecond) class ArrowComparisonTests(Chai): def setUp(self): super(ArrowComparisonTests, self).setUp() self.arrow = arrow.Arrow.utcnow() def test_eq(self): assertTrue(self.arrow == self.arrow) assertTrue(self.arrow == self.arrow.datetime) assertFalse(self.arrow == 'abc') def test_ne(self): assertFalse(self.arrow != self.arrow) assertFalse(self.arrow != self.arrow.datetime) assertTrue(self.arrow != 'abc') def test_gt(self): arrow_cmp = self.arrow.replace(minutes=1) assertFalse(self.arrow > self.arrow) assertFalse(self.arrow > self.arrow.datetime) with assertRaises(TypeError): self.arrow > 'abc' assertTrue(self.arrow < arrow_cmp) assertTrue(self.arrow < arrow_cmp.datetime) def test_ge(self): with assertRaises(TypeError): self.arrow >= 'abc' assertTrue(self.arrow >= self.arrow) assertTrue(self.arrow >= self.arrow.datetime) def test_lt(self): arrow_cmp = self.arrow.replace(minutes=1) assertFalse(self.arrow < self.arrow) assertFalse(self.arrow < self.arrow.datetime) with assertRaises(TypeError): self.arrow < 'abc' assertTrue(self.arrow < arrow_cmp) assertTrue(self.arrow < arrow_cmp.datetime) def test_le(self): with assertRaises(TypeError): self.arrow <= 'abc' assertTrue(self.arrow <= self.arrow) assertTrue(self.arrow <= self.arrow.datetime) class ArrowMathTests(Chai): def setUp(self): super(ArrowMathTests, self).setUp() self.arrow = arrow.Arrow(2013, 1, 1) def test_add_timedelta(self): result = self.arrow.__add__(timedelta(days=1)) assertEqual(result._datetime, datetime(2013, 1, 2, tzinfo=tz.tzutc())) def test_add_other(self): with assertRaises(TypeError): self.arrow.__add__(1) def test_radd(self): result = self.arrow.__radd__(timedelta(days=1)) assertEqual(result._datetime, datetime(2013, 1, 2, tzinfo=tz.tzutc())) def test_sub_timedelta(self): result = self.arrow.__sub__(timedelta(days=1)) assertEqual(result._datetime, datetime(2012, 12, 31, tzinfo=tz.tzutc())) def test_sub_datetime(self): result = self.arrow.__sub__(datetime(2012, 12, 21, tzinfo=tz.tzutc())) assertEqual(result, timedelta(days=11)) def test_sub_arrow(self): result = self.arrow.__sub__(arrow.Arrow(2012, 12, 21, tzinfo=tz.tzutc())) assertEqual(result, timedelta(days=11)) def test_sub_other(self): with assertRaises(TypeError): self.arrow.__sub__(object()) def test_rsub(self): result = self.arrow.__rsub__(timedelta(days=1)) assertEqual(result._datetime, datetime(2012, 12, 31, tzinfo=tz.tzutc())) class ArrowDatetimeInterfaceTests(Chai): def setUp(self): super(ArrowDatetimeInterfaceTests, self).setUp() self.arrow = arrow.Arrow.utcnow() def test_date(self): result = self.arrow.date() assertEqual(result, self.arrow._datetime.date()) def test_time(self): result = self.arrow.time() assertEqual(result, self.arrow._datetime.time()) def test_timetz(self): result = self.arrow.timetz() assertEqual(result, self.arrow._datetime.timetz()) def test_astimezone(self): other_tz = tz.gettz('US/Pacific') result = self.arrow.astimezone(other_tz) assertEqual(result, self.arrow._datetime.astimezone(other_tz)) def test_utcoffset(self): result = self.arrow.utcoffset() assertEqual(result, self.arrow._datetime.utcoffset()) def test_dst(self): result = self.arrow.dst() assertEqual(result, self.arrow._datetime.dst()) def test_timetuple(self): result = self.arrow.timetuple() assertEqual(result, self.arrow._datetime.timetuple()) def test_utctimetuple(self): result = self.arrow.utctimetuple() assertEqual(result, self.arrow._datetime.utctimetuple()) def test_toordinal(self): result = self.arrow.toordinal() assertEqual(result, self.arrow._datetime.toordinal()) def test_weekday(self): result = self.arrow.weekday() assertEqual(result, self.arrow._datetime.weekday()) def test_isoweekday(self): result = self.arrow.isoweekday() assertEqual(result, self.arrow._datetime.isoweekday()) def test_isocalendar(self): result = self.arrow.isocalendar() assertEqual(result, self.arrow._datetime.isocalendar()) def test_isoformat(self): result = self.arrow.isoformat() assertEqual(result, self.arrow._datetime.isoformat()) def test_simplejson(self): result = json.dumps({'v': self.arrow.for_json()}, for_json=True) assertEqual(json.loads(result)['v'], self.arrow._datetime.isoformat()) def test_ctime(self): result = self.arrow.ctime() assertEqual(result, self.arrow._datetime.ctime()) def test_strftime(self): result = self.arrow.strftime('%Y') assertEqual(result, self.arrow._datetime.strftime('%Y')) class ArrowConversionTests(Chai): def test_to(self): dt_from = datetime.now() arrow_from = arrow.Arrow.fromdatetime(dt_from, tz.gettz('US/Pacific')) result = arrow_from.to('UTC') expected = dt_from.replace(tzinfo=tz.gettz('US/Pacific')).astimezone(tz.tzutc()) assertEqual(result.datetime, expected) class ArrowPicklingTests(Chai): def test_pickle_and_unpickle(self): dt = arrow.Arrow.utcnow() pickled = pickle.dumps(dt) unpickled = pickle.loads(pickled) assertEqual(unpickled, dt) class ArrowReplaceTests(Chai): def test_not_attr(self): with assertRaises(AttributeError): arrow.Arrow.utcnow().replace(abc=1) def test_replace_absolute(self): arw = arrow.Arrow(2013, 5, 5, 12, 30, 45) assertEqual(arw.replace(year=2012), arrow.Arrow(2012, 5, 5, 12, 30, 45)) assertEqual(arw.replace(month=1), arrow.Arrow(2013, 1, 5, 12, 30, 45)) assertEqual(arw.replace(day=1), arrow.Arrow(2013, 5, 1, 12, 30, 45)) assertEqual(arw.replace(hour=1), arrow.Arrow(2013, 5, 5, 1, 30, 45)) assertEqual(arw.replace(minute=1), arrow.Arrow(2013, 5, 5, 12, 1, 45)) assertEqual(arw.replace(second=1), arrow.Arrow(2013, 5, 5, 12, 30, 1)) def test_replace_relative(self): arw = arrow.Arrow(2013, 5, 5, 12, 30, 45) assertEqual(arw.replace(years=1), arrow.Arrow(2014, 5, 5, 12, 30, 45)) assertEqual(arw.replace(months=1), arrow.Arrow(2013, 6, 5, 12, 30, 45)) assertEqual(arw.replace(weeks=1), arrow.Arrow(2013, 5, 12, 12, 30, 45)) assertEqual(arw.replace(days=1), arrow.Arrow(2013, 5, 6, 12, 30, 45)) assertEqual(arw.replace(hours=1), arrow.Arrow(2013, 5, 5, 13, 30, 45)) assertEqual(arw.replace(minutes=1), arrow.Arrow(2013, 5, 5, 12, 31, 45)) assertEqual(arw.replace(seconds=1), arrow.Arrow(2013, 5, 5, 12, 30, 46)) def test_replace_relative_negative(self): arw = arrow.Arrow(2013, 5, 5, 12, 30, 45) assertEqual(arw.replace(years=-1), arrow.Arrow(2012, 5, 5, 12, 30, 45)) assertEqual(arw.replace(months=-1), arrow.Arrow(2013, 4, 5, 12, 30, 45)) assertEqual(arw.replace(weeks=-1), arrow.Arrow(2013, 4, 28, 12, 30, 45)) assertEqual(arw.replace(days=-1), arrow.Arrow(2013, 5, 4, 12, 30, 45)) assertEqual(arw.replace(hours=-1), arrow.Arrow(2013, 5, 5, 11, 30, 45)) assertEqual(arw.replace(minutes=-1), arrow.Arrow(2013, 5, 5, 12, 29, 45)) assertEqual(arw.replace(seconds=-1), arrow.Arrow(2013, 5, 5, 12, 30, 44)) assertEqual(arw.replace(microseconds=-1), arrow.Arrow(2013, 5, 5, 12, 30, 44, 999999)) def test_replace_tzinfo(self): arw = arrow.Arrow.utcnow().to('US/Eastern') result = arw.replace(tzinfo=tz.gettz('US/Pacific')) assertEqual(result, arw.datetime.replace(tzinfo=tz.gettz('US/Pacific'))) def test_replace_week(self): with assertRaises(AttributeError): arrow.Arrow.utcnow().replace(week=1) def test_replace_other_kwargs(self): with assertRaises(AttributeError): arrow.utcnow().replace(abc='def') class ArrowRangeTests(Chai): def test_year(self): result = arrow.Arrow.range('year', datetime(2013, 1, 2, 3, 4, 5), datetime(2016, 4, 5, 6, 7, 8)) assertEqual(result, [ arrow.Arrow(2013, 1, 2, 3, 4, 5), arrow.Arrow(2014, 1, 2, 3, 4, 5), arrow.Arrow(2015, 1, 2, 3, 4, 5), arrow.Arrow(2016, 1, 2, 3, 4, 5), ]) def test_quarter(self): result = arrow.Arrow.range('quarter', datetime(2013, 2, 3, 4, 5, 6), datetime(2013, 5, 6, 7, 8, 9)) assertEqual(result, [ arrow.Arrow(2013, 2, 3, 4, 5, 6), arrow.Arrow(2013, 5, 3, 4, 5, 6), ]) def test_month(self): result = arrow.Arrow.range('month', datetime(2013, 2, 3, 4, 5, 6), datetime(2013, 5, 6, 7, 8, 9)) assertEqual(result, [ arrow.Arrow(2013, 2, 3, 4, 5, 6), arrow.Arrow(2013, 3, 3, 4, 5, 6), arrow.Arrow(2013, 4, 3, 4, 5, 6), arrow.Arrow(2013, 5, 3, 4, 5, 6), ]) def test_week(self): result = arrow.Arrow.range('week', datetime(2013, 9, 1, 2, 3, 4), datetime(2013, 10, 1, 2, 3, 4)) assertEqual(result, [ arrow.Arrow(2013, 9, 1, 2, 3, 4), arrow.Arrow(2013, 9, 8, 2, 3, 4), arrow.Arrow(2013, 9, 15, 2, 3, 4), arrow.Arrow(2013, 9, 22, 2, 3, 4), arrow.Arrow(2013, 9, 29, 2, 3, 4) ]) def test_day(self): result = arrow.Arrow.range('day', datetime(2013, 1, 2, 3, 4, 5), datetime(2013, 1, 5, 6, 7, 8)) assertEqual(result, [ arrow.Arrow(2013, 1, 2, 3, 4, 5), arrow.Arrow(2013, 1, 3, 3, 4, 5), arrow.Arrow(2013, 1, 4, 3, 4, 5), arrow.Arrow(2013, 1, 5, 3, 4, 5), ]) def test_hour(self): result = arrow.Arrow.range('hour', datetime(2013, 1, 2, 3, 4, 5), datetime(2013, 1, 2, 6, 7, 8)) assertEqual(result, [ arrow.Arrow(2013, 1, 2, 3, 4, 5), arrow.Arrow(2013, 1, 2, 4, 4, 5), arrow.Arrow(2013, 1, 2, 5, 4, 5), arrow.Arrow(2013, 1, 2, 6, 4, 5), ]) result = arrow.Arrow.range('hour', datetime(2013, 1, 2, 3, 4, 5), datetime(2013, 1, 2, 3, 4, 5)) assertEqual(result, [ arrow.Arrow(2013, 1, 2, 3, 4, 5), ]) def test_minute(self): result = arrow.Arrow.range('minute', datetime(2013, 1, 2, 3, 4, 5), datetime(2013, 1, 2, 3, 7, 8)) assertEqual(result, [ arrow.Arrow(2013, 1, 2, 3, 4, 5), arrow.Arrow(2013, 1, 2, 3, 5, 5), arrow.Arrow(2013, 1, 2, 3, 6, 5), arrow.Arrow(2013, 1, 2, 3, 7, 5), ]) def test_second(self): result = arrow.Arrow.range('second', datetime(2013, 1, 2, 3, 4, 5), datetime(2013, 1, 2, 3, 4, 8)) assertEqual(result, [ arrow.Arrow(2013, 1, 2, 3, 4, 5), arrow.Arrow(2013, 1, 2, 3, 4, 6), arrow.Arrow(2013, 1, 2, 3, 4, 7), arrow.Arrow(2013, 1, 2, 3, 4, 8), ]) def test_arrow(self): result = arrow.Arrow.range('day', arrow.Arrow(2013, 1, 2, 3, 4, 5), arrow.Arrow(2013, 1, 5, 6, 7, 8)) assertEqual(result, [ arrow.Arrow(2013, 1, 2, 3, 4, 5), arrow.Arrow(2013, 1, 3, 3, 4, 5), arrow.Arrow(2013, 1, 4, 3, 4, 5), arrow.Arrow(2013, 1, 5, 3, 4, 5), ]) def test_naive_tz(self): result = arrow.Arrow.range('year', datetime(2013, 1, 2, 3), datetime(2016, 4, 5, 6), 'US/Pacific') [assertEqual(r.tzinfo, tz.gettz('US/Pacific')) for r in result] def test_aware_same_tz(self): result = arrow.Arrow.range('day', arrow.Arrow(2013, 1, 1, tzinfo=tz.gettz('US/Pacific')), arrow.Arrow(2013, 1, 3, tzinfo=tz.gettz('US/Pacific'))) [assertEqual(r.tzinfo, tz.gettz('US/Pacific')) for r in result] def test_aware_different_tz(self): result = arrow.Arrow.range('day', datetime(2013, 1, 1, tzinfo=tz.gettz('US/Eastern')), datetime(2013, 1, 3, tzinfo=tz.gettz('US/Pacific'))) [assertEqual(r.tzinfo, tz.gettz('US/Eastern')) for r in result] def test_aware_tz(self): result = arrow.Arrow.range('day', datetime(2013, 1, 1, tzinfo=tz.gettz('US/Eastern')), datetime(2013, 1, 3, tzinfo=tz.gettz('US/Pacific')), tz=tz.gettz('US/Central')) [assertEqual(r.tzinfo, tz.gettz('US/Central')) for r in result] def test_unsupported(self): with assertRaises(AttributeError): arrow.Arrow.range('abc', datetime.utcnow(), datetime.utcnow()) class ArrowSpanRangeTests(Chai): def test_year(self): result = arrow.Arrow.span_range('year', datetime(2013, 2, 1), datetime(2016, 3, 31)) assertEqual(result, [ (arrow.Arrow(2013, 1, 1), arrow.Arrow(2013, 12, 31, 23, 59, 59, 999999)), (arrow.Arrow(2014, 1, 1), arrow.Arrow(2014, 12, 31, 23, 59, 59, 999999)), (arrow.Arrow(2015, 1, 1), arrow.Arrow(2015, 12, 31, 23, 59, 59, 999999)), (arrow.Arrow(2016, 1, 1), arrow.Arrow(2016, 12, 31, 23, 59, 59, 999999)), ]) def test_quarter(self): result = arrow.Arrow.span_range('quarter', datetime(2013, 2, 2), datetime(2013, 5, 15)) assertEqual(result, [ (arrow.Arrow(2013, 1, 1), arrow.Arrow(2013, 3, 31, 23, 59, 59, 999999)), (arrow.Arrow(2013, 4, 1), arrow.Arrow(2013, 6, 30, 23, 59, 59, 999999)), ]) def test_month(self): result = arrow.Arrow.span_range('month', datetime(2013, 1, 2), datetime(2013, 4, 15)) assertEqual(result, [ (arrow.Arrow(2013, 1, 1), arrow.Arrow(2013, 1, 31, 23, 59, 59, 999999)), (arrow.Arrow(2013, 2, 1), arrow.Arrow(2013, 2, 28, 23, 59, 59, 999999)), (arrow.Arrow(2013, 3, 1), arrow.Arrow(2013, 3, 31, 23, 59, 59, 999999)), (arrow.Arrow(2013, 4, 1), arrow.Arrow(2013, 4, 30, 23, 59, 59, 999999)), ]) def test_week(self): result = arrow.Arrow.span_range('week', datetime(2013, 2, 2), datetime(2013, 2, 28)) assertEqual(result, [ (arrow.Arrow(2013, 1, 28), arrow.Arrow(2013, 2, 3, 23, 59, 59, 999999)), (arrow.Arrow(2013, 2, 4), arrow.Arrow(2013, 2, 10, 23, 59, 59, 999999)), (arrow.Arrow(2013, 2, 11), arrow.Arrow(2013, 2, 17, 23, 59, 59, 999999)), (arrow.Arrow(2013, 2, 18), arrow.Arrow(2013, 2, 24, 23, 59, 59, 999999)), (arrow.Arrow(2013, 2, 25), arrow.Arrow(2013, 3, 3, 23, 59, 59, 999999)), ]) def test_day(self): result = arrow.Arrow.span_range('day', datetime(2013, 1, 1, 12), datetime(2013, 1, 4, 12)) assertEqual(result, [ (arrow.Arrow(2013, 1, 1, 0), arrow.Arrow(2013, 1, 1, 23, 59, 59, 999999)), (arrow.Arrow(2013, 1, 2, 0), arrow.Arrow(2013, 1, 2, 23, 59, 59, 999999)), (arrow.Arrow(2013, 1, 3, 0), arrow.Arrow(2013, 1, 3, 23, 59, 59, 999999)), (arrow.Arrow(2013, 1, 4, 0), arrow.Arrow(2013, 1, 4, 23, 59, 59, 999999)), ]) def test_hour(self): result = arrow.Arrow.span_range('hour', datetime(2013, 1, 1, 0, 30), datetime(2013, 1, 1, 3, 30)) assertEqual(result, [ (arrow.Arrow(2013, 1, 1, 0), arrow.Arrow(2013, 1, 1, 0, 59, 59, 999999)), (arrow.Arrow(2013, 1, 1, 1), arrow.Arrow(2013, 1, 1, 1, 59, 59, 999999)), (arrow.Arrow(2013, 1, 1, 2), arrow.Arrow(2013, 1, 1, 2, 59, 59, 999999)), (arrow.Arrow(2013, 1, 1, 3), arrow.Arrow(2013, 1, 1, 3, 59, 59, 999999)), ]) result = arrow.Arrow.span_range('hour', datetime(2013, 1, 1, 3, 30), datetime(2013, 1, 1, 3, 30)) assertEqual(result, [ (arrow.Arrow(2013, 1, 1, 3), arrow.Arrow(2013, 1, 1, 3, 59, 59, 999999)), ]) def test_minute(self): result = arrow.Arrow.span_range('minute', datetime(2013, 1, 1, 0, 0, 30), datetime(2013, 1, 1, 0, 3, 30)) assertEqual(result, [ (arrow.Arrow(2013, 1, 1, 0, 0), arrow.Arrow(2013, 1, 1, 0, 0, 59, 999999)), (arrow.Arrow(2013, 1, 1, 0, 1), arrow.Arrow(2013, 1, 1, 0, 1, 59, 999999)), (arrow.Arrow(2013, 1, 1, 0, 2), arrow.Arrow(2013, 1, 1, 0, 2, 59, 999999)), (arrow.Arrow(2013, 1, 1, 0, 3), arrow.Arrow(2013, 1, 1, 0, 3, 59, 999999)), ]) def test_second(self): result = arrow.Arrow.span_range('second', datetime(2013, 1, 1), datetime(2013, 1, 1, 0, 0, 3)) assertEqual(result, [ (arrow.Arrow(2013, 1, 1, 0, 0, 0), arrow.Arrow(2013, 1, 1, 0, 0, 0, 999999)), (arrow.Arrow(2013, 1, 1, 0, 0, 1), arrow.Arrow(2013, 1, 1, 0, 0, 1, 999999)), (arrow.Arrow(2013, 1, 1, 0, 0, 2), arrow.Arrow(2013, 1, 1, 0, 0, 2, 999999)), (arrow.Arrow(2013, 1, 1, 0, 0, 3), arrow.Arrow(2013, 1, 1, 0, 0, 3, 999999)), ]) def test_naive_tz(self): tzinfo = tz.gettz('US/Pacific') result = arrow.Arrow.span_range('hour', datetime(2013, 1, 1, 0), datetime(2013, 1, 1, 3, 59), 'US/Pacific') for f, c in result: assertEqual(f.tzinfo, tzinfo) assertEqual(c.tzinfo, tzinfo) def test_aware_same_tz(self): tzinfo = tz.gettz('US/Pacific') result = arrow.Arrow.span_range('hour', datetime(2013, 1, 1, 0, tzinfo=tzinfo), datetime(2013, 1, 1, 2, 59, tzinfo=tzinfo)) for f, c in result: assertEqual(f.tzinfo, tzinfo) assertEqual(c.tzinfo, tzinfo) def test_aware_different_tz(self): tzinfo1 = tz.gettz('US/Pacific') tzinfo2 = tz.gettz('US/Eastern') result = arrow.Arrow.span_range('hour', datetime(2013, 1, 1, 0, tzinfo=tzinfo1), datetime(2013, 1, 1, 2, 59, tzinfo=tzinfo2)) for f, c in result: assertEqual(f.tzinfo, tzinfo1) assertEqual(c.tzinfo, tzinfo1) def test_aware_tz(self): result = arrow.Arrow.span_range('hour', datetime(2013, 1, 1, 0, tzinfo=tz.gettz('US/Eastern')), datetime(2013, 1, 1, 2, 59, tzinfo=tz.gettz('US/Eastern')), tz='US/Central') for f, c in result: assertEqual(f.tzinfo, tz.gettz('US/Central')) assertEqual(c.tzinfo, tz.gettz('US/Central')) class ArrowSpanTests(Chai): def setUp(self): super(ArrowSpanTests, self).setUp() self.datetime = datetime(2013, 2, 15, 3, 41, 22, 8923) self.arrow = arrow.Arrow.fromdatetime(self.datetime) def test_span_attribute(self): with assertRaises(AttributeError): self.arrow.span('span') def test_span_year(self): floor, ceil = self.arrow.span('year') assertEqual(floor, datetime(2013, 1, 1, tzinfo=tz.tzutc())) assertEqual(ceil, datetime(2013, 12, 31, 23, 59, 59, 999999, tzinfo=tz.tzutc())) def test_span_quarter(self): floor, ceil = self.arrow.span('quarter') assertEqual(floor, datetime(2013, 1, 1, tzinfo=tz.tzutc())) assertEqual(ceil, datetime(2013, 3, 31, 23, 59, 59, 999999, tzinfo=tz.tzutc())) def test_span_quarter_count(self): floor, ceil = self.arrow.span('quarter', 2) assertEqual(floor, datetime(2013, 1, 1, tzinfo=tz.tzutc())) assertEqual(ceil, datetime(2013, 6, 30, 23, 59, 59, 999999, tzinfo=tz.tzutc())) def test_span_year_count(self): floor, ceil = self.arrow.span('year', 2) assertEqual(floor, datetime(2013, 1, 1, tzinfo=tz.tzutc())) assertEqual(ceil, datetime(2014, 12, 31, 23, 59, 59, 999999, tzinfo=tz.tzutc())) def test_span_month(self): floor, ceil = self.arrow.span('month') assertEqual(floor, datetime(2013, 2, 1, tzinfo=tz.tzutc())) assertEqual(ceil, datetime(2013, 2, 28, 23, 59, 59, 999999, tzinfo=tz.tzutc())) def test_span_week(self): floor, ceil = self.arrow.span('week') assertEqual(floor, datetime(2013, 2, 11, tzinfo=tz.tzutc())) assertEqual(ceil, datetime(2013, 2, 17, 23, 59, 59, 999999, tzinfo=tz.tzutc())) def test_span_day(self): floor, ceil = self.arrow.span('day') assertEqual(floor, datetime(2013, 2, 15, tzinfo=tz.tzutc())) assertEqual(ceil, datetime(2013, 2, 15, 23, 59, 59, 999999, tzinfo=tz.tzutc())) def test_span_hour(self): floor, ceil = self.arrow.span('hour') assertEqual(floor, datetime(2013, 2, 15, 3, tzinfo=tz.tzutc())) assertEqual(ceil, datetime(2013, 2, 15, 3, 59, 59, 999999, tzinfo=tz.tzutc())) def test_span_minute(self): floor, ceil = self.arrow.span('minute') assertEqual(floor, datetime(2013, 2, 15, 3, 41, tzinfo=tz.tzutc())) assertEqual(ceil, datetime(2013, 2, 15, 3, 41, 59, 999999, tzinfo=tz.tzutc())) def test_span_second(self): floor, ceil = self.arrow.span('second') assertEqual(floor, datetime(2013, 2, 15, 3, 41, 22, tzinfo=tz.tzutc())) assertEqual(ceil, datetime(2013, 2, 15, 3, 41, 22, 999999, tzinfo=tz.tzutc())) def test_span_hour(self): floor, ceil = self.arrow.span('microsecond') assertEqual(floor, datetime(2013, 2, 15, 3, 41, 22, 8923, tzinfo=tz.tzutc())) assertEqual(ceil, datetime(2013, 2, 15, 3, 41, 22, 8923, tzinfo=tz.tzutc())) def test_floor(self): floor, ceil = self.arrow.span('month') assertEqual(floor, self.arrow.floor('month')) assertEqual(ceil, self.arrow.ceil('month')) class ArrowHumanizeTests(Chai): def setUp(self): super(ArrowHumanizeTests, self).setUp() self.datetime = datetime(2013, 1, 1) self.now = arrow.Arrow.utcnow() def test_seconds(self): later = self.now.replace(seconds=10) assertEqual(self.now.humanize(later), 'seconds ago') assertEqual(later.humanize(self.now), 'in seconds') assertEqual(self.now.humanize(later, only_distance=True), 'seconds') assertEqual(later.humanize(self.now, only_distance=True), 'seconds') def test_minute(self): later = self.now.replace(minutes=1) assertEqual(self.now.humanize(later), 'a minute ago') assertEqual(later.humanize(self.now), 'in a minute') assertEqual(self.now.humanize(later, only_distance=True), 'a minute') assertEqual(later.humanize(self.now, only_distance=True), 'a minute') def test_minutes(self): later = self.now.replace(minutes=2) assertEqual(self.now.humanize(later), '2 minutes ago') assertEqual(later.humanize(self.now), 'in 2 minutes') assertEqual(self.now.humanize(later, only_distance=True), '2 minutes') assertEqual(later.humanize(self.now, only_distance=True), '2 minutes') def test_hour(self): later = self.now.replace(hours=1) assertEqual(self.now.humanize(later), 'an hour ago') assertEqual(later.humanize(self.now), 'in an hour') assertEqual(self.now.humanize(later, only_distance=True), 'an hour') assertEqual(later.humanize(self.now, only_distance=True), 'an hour') def test_hours(self): later = self.now.replace(hours=2) assertEqual(self.now.humanize(later), '2 hours ago') assertEqual(later.humanize(self.now), 'in 2 hours') assertEqual(self.now.humanize(later, only_distance=True), '2 hours') assertEqual(later.humanize(self.now, only_distance=True), '2 hours') def test_day(self): later = self.now.replace(days=1) assertEqual(self.now.humanize(later), 'a day ago') assertEqual(later.humanize(self.now), 'in a day') assertEqual(self.now.humanize(later, only_distance=True), 'a day') assertEqual(later.humanize(self.now, only_distance=True), 'a day') def test_days(self): later = self.now.replace(days=2) assertEqual(self.now.humanize(later), '2 days ago') assertEqual(later.humanize(self.now), 'in 2 days') assertEqual(self.now.humanize(later, only_distance=True), '2 days') assertEqual(later.humanize(self.now, only_distance=True), '2 days') def test_month(self): later = self.now.replace(months=1) assertEqual(self.now.humanize(later), 'a month ago') assertEqual(later.humanize(self.now), 'in a month') assertEqual(self.now.humanize(later, only_distance=True), 'a month') assertEqual(later.humanize(self.now, only_distance=True), 'a month') def test_months(self): later = self.now.replace(months=2) assertEqual(self.now.humanize(later), '2 months ago') assertEqual(later.humanize(self.now), 'in 2 months') assertEqual(self.now.humanize(later, only_distance=True), '2 months') assertEqual(later.humanize(self.now, only_distance=True), '2 months') def test_year(self): later = self.now.replace(years=1) assertEqual(self.now.humanize(later), 'a year ago') assertEqual(later.humanize(self.now), 'in a year') assertEqual(self.now.humanize(later, only_distance=True), 'a year') assertEqual(later.humanize(self.now, only_distance=True), 'a year') def test_years(self): later = self.now.replace(years=2) assertEqual(self.now.humanize(later), '2 years ago') assertEqual(later.humanize(self.now), 'in 2 years') assertEqual(self.now.humanize(later, only_distance=True), '2 years') assertEqual(later.humanize(self.now, only_distance=True), '2 years') arw = arrow.Arrow(2014, 7, 2) result = arw.humanize(self.datetime) assertEqual(result, 'in 2 years') def test_arrow(self): arw = arrow.Arrow.fromdatetime(self.datetime) result = arw.humanize(arrow.Arrow.fromdatetime(self.datetime)) assertEqual(result, 'just now') def test_datetime_tzinfo(self): arw = arrow.Arrow.fromdatetime(self.datetime) result = arw.humanize(self.datetime.replace(tzinfo=tz.tzutc())) assertEqual(result, 'just now') def test_other(self): arw = arrow.Arrow.fromdatetime(self.datetime) with assertRaises(TypeError): arw.humanize(object()) def test_invalid_locale(self): arw = arrow.Arrow.fromdatetime(self.datetime) with assertRaises(ValueError): arw.humanize(locale='klingon') def test_none(self): arw = arrow.Arrow.utcnow() result = arw.humanize() assertEqual(result, 'just now') class ArrowHumanizeTestsWithLocale(Chai): def setUp(self): super(ArrowHumanizeTestsWithLocale, self).setUp() self.datetime = datetime(2013, 1, 1) def test_now(self): arw = arrow.Arrow(2013, 1, 1, 0, 0, 0) result = arw.humanize(self.datetime, locale='ru') assertEqual(result, 'сейчас') def test_seconds(self): arw = arrow.Arrow(2013, 1, 1, 0, 0, 44) result = arw.humanize(self.datetime, locale='ru') assertEqual(result, 'через несколько секунд') def test_years(self): arw = arrow.Arrow(2011, 7, 2) result = arw.humanize(self.datetime, locale='ru') assertEqual(result, '2 года назад') class ArrowUtilTests(Chai): def test_get_datetime(self): get_datetime = arrow.Arrow._get_datetime arw = arrow.Arrow.utcnow() dt = datetime.utcnow() timestamp = time.time() assertEqual(get_datetime(arw), arw.datetime) assertEqual(get_datetime(dt), dt) assertEqual(get_datetime(timestamp), arrow.Arrow.utcfromtimestamp(timestamp).datetime) with assertRaises(ValueError): get_datetime('abc') def test_get_tzinfo(self): get_tzinfo = arrow.Arrow._get_tzinfo with assertRaises(ValueError): get_tzinfo('abc') def test_get_timestamp_from_input(self): assertEqual(arrow.Arrow._get_timestamp_from_input(123), 123) assertEqual(arrow.Arrow._get_timestamp_from_input(123.4), 123.4) assertEqual(arrow.Arrow._get_timestamp_from_input('123'), 123.0) assertEqual(arrow.Arrow._get_timestamp_from_input('123.4'), 123.4) with assertRaises(ValueError): arrow.Arrow._get_timestamp_from_input('abc') def test_get_iteration_params(self): assertEqual(arrow.Arrow._get_iteration_params('end', None), ('end', sys.maxsize)) assertEqual(arrow.Arrow._get_iteration_params(None, 100), (arrow.Arrow.max, 100)) with assertRaises(Exception): arrow.Arrow._get_iteration_params(None, None) arrow-0.7.0/tests/factory_tests.py000066400000000000000000000125551260523235100172640ustar00rootroot00000000000000from chai import Chai from datetime import datetime, date from dateutil import tz import time from arrow import factory, util def assertDtEqual(dt1, dt2, within=10): assertEqual(dt1.tzinfo, dt2.tzinfo) assertTrue(abs(util.total_seconds(dt1 - dt2)) < within) class GetTests(Chai): def setUp(self): super(GetTests, self).setUp() self.factory = factory.ArrowFactory() def test_no_args(self): assertDtEqual(self.factory.get(), datetime.utcnow().replace(tzinfo=tz.tzutc())) def test_timestamp_one_arg_no_arg(self): no_arg = self.factory.get('1406430900').timestamp one_arg = self.factory.get('1406430900', 'X').timestamp assertEqual(no_arg, one_arg) def test_one_arg_non(self): assertDtEqual(self.factory.get(None), datetime.utcnow().replace(tzinfo=tz.tzutc())) def test_struct_time(self): assertDtEqual(self.factory.get(time.gmtime()), datetime.utcnow().replace(tzinfo=tz.tzutc())) def test_one_arg_timestamp(self): timestamp = 12345 timestamp_dt = datetime.utcfromtimestamp(timestamp).replace(tzinfo=tz.tzutc()) assertEqual(self.factory.get(timestamp), timestamp_dt) assertEqual(self.factory.get(str(timestamp)), timestamp_dt) timestamp = 123.45 timestamp_dt = datetime.utcfromtimestamp(timestamp).replace(tzinfo=tz.tzutc()) assertEqual(self.factory.get(timestamp), timestamp_dt) assertEqual(self.factory.get(str(timestamp)), timestamp_dt) # Issue 216 timestamp = '99999999999999999999999999' # Python 3 raises `OverflowError`, Python 2 raises `ValueError` with assertRaises((OverflowError, ValueError,)): self.factory.get(timestamp) def test_one_arg_arrow(self): arw = self.factory.utcnow() result = self.factory.get(arw) assertEqual(arw, result) def test_one_arg_datetime(self): dt = datetime.utcnow().replace(tzinfo=tz.tzutc()) assertEqual(self.factory.get(dt), dt) def test_one_arg_date(self): d = date.today() dt = datetime(d.year, d.month, d.day, tzinfo=tz.tzutc()) assertEqual(self.factory.get(d), dt) def test_one_arg_tzinfo(self): expected = datetime.utcnow().replace(tzinfo=tz.tzutc()).astimezone(tz.gettz('US/Pacific')) assertDtEqual(self.factory.get(tz.gettz('US/Pacific')), expected) def test_one_arg_iso_str(self): dt = datetime.utcnow() assertDtEqual(self.factory.get(dt.isoformat()), dt.replace(tzinfo=tz.tzutc())) def test_one_arg_other(self): with assertRaises(TypeError): self.factory.get(object()) def test_two_args_datetime_tzinfo(self): result = self.factory.get(datetime(2013, 1, 1), tz.gettz('US/Pacific')) assertEqual(result._datetime, datetime(2013, 1, 1, tzinfo=tz.gettz('US/Pacific'))) def test_two_args_datetime_tz_str(self): result = self.factory.get(datetime(2013, 1, 1), 'US/Pacific') assertEqual(result._datetime, datetime(2013, 1, 1, tzinfo=tz.gettz('US/Pacific'))) def test_two_args_date_tzinfo(self): result = self.factory.get(date(2013, 1, 1), tz.gettz('US/Pacific')) assertEqual(result._datetime, datetime(2013, 1, 1, tzinfo=tz.gettz('US/Pacific'))) def test_two_args_date_tz_str(self): result = self.factory.get(date(2013, 1, 1), 'US/Pacific') assertEqual(result._datetime, datetime(2013, 1, 1, tzinfo=tz.gettz('US/Pacific'))) def test_two_args_datetime_other(self): with assertRaises(TypeError): self.factory.get(datetime.utcnow(), object()) def test_two_args_date_other(self): with assertRaises(TypeError): self.factory.get(date.today(), object()) def test_two_args_str_str(self): result = self.factory.get('2013-01-01', 'YYYY-MM-DD') assertEqual(result._datetime, datetime(2013, 1, 1, tzinfo=tz.tzutc())) def test_two_args_str_list(self): result = self.factory.get('2013-01-01', ['MM/DD/YYYY', 'YYYY-MM-DD']) assertEqual(result._datetime, datetime(2013, 1, 1, tzinfo=tz.tzutc())) def test_two_args_unicode_unicode(self): result = self.factory.get(u'2013-01-01', u'YYYY-MM-DD') assertEqual(result._datetime, datetime(2013, 1, 1, tzinfo=tz.tzutc())) def test_two_args_other(self): with assertRaises(TypeError): self.factory.get(object(), object()) def test_three_args_with_tzinfo(self): timefmt = 'YYYYMMDD' d = '20150514' assertEqual(self.factory.get(d, timefmt, tzinfo=tz.tzlocal()), datetime(2015, 5, 14, tzinfo=tz.tzlocal())) def test_three_args(self): assertEqual(self.factory.get(2013, 1, 1), datetime(2013, 1, 1, tzinfo=tz.tzutc())) def UtcNowTests(Chai): def test_utcnow(self): assertDtEqual(self.factory.utcnow()._datetime, datetime.utcnow().replace(tzinfo=tz.tzutc())) class NowTests(Chai): def setUp(self): super(NowTests, self).setUp() self.factory = factory.ArrowFactory() def test_no_tz(self): assertDtEqual(self.factory.now(), datetime.now(tz.tzlocal())) def test_tzinfo(self): assertDtEqual(self.factory.now(tz.gettz('EST')), datetime.now(tz.gettz('EST'))) def test_tz_str(self): assertDtEqual(self.factory.now('EST'), datetime.now(tz.gettz('EST'))) arrow-0.7.0/tests/formatter_tests.py000066400000000000000000000113571260523235100176170ustar00rootroot00000000000000from chai import Chai from arrow import formatter from datetime import datetime from dateutil import tz as dateutil_tz import time class DateTimeFormatterFormatTokenTests(Chai): def setUp(self): super(DateTimeFormatterFormatTokenTests, self).setUp() self.formatter = formatter.DateTimeFormatter() def test_format(self): dt = datetime(2013, 2, 5, 12, 32, 51) result = self.formatter.format(dt, 'MM-DD-YYYY hh:mm:ss a') assertEqual(result, '02-05-2013 12:32:51 pm') def test_year(self): dt = datetime(2013, 1, 1) assertEqual(self.formatter._format_token(dt, 'YYYY'), '2013') assertEqual(self.formatter._format_token(dt, 'YY'), '13') def test_month(self): dt = datetime(2013, 1, 1) assertEqual(self.formatter._format_token(dt, 'MMMM'), 'January') assertEqual(self.formatter._format_token(dt, 'MMM'), 'Jan') assertEqual(self.formatter._format_token(dt, 'MM'), '01') assertEqual(self.formatter._format_token(dt, 'M'), '1') def test_day(self): dt = datetime(2013, 2, 1) assertEqual(self.formatter._format_token(dt, 'DDDD'), '032') assertEqual(self.formatter._format_token(dt, 'DDD'), '32') assertEqual(self.formatter._format_token(dt, 'DD'), '01') assertEqual(self.formatter._format_token(dt, 'D'), '1') assertEqual(self.formatter._format_token(dt, 'Do'), '1st') assertEqual(self.formatter._format_token(dt, 'dddd'), 'Friday') assertEqual(self.formatter._format_token(dt, 'ddd'), 'Fri') assertEqual(self.formatter._format_token(dt, 'd'), '5') def test_hour(self): dt = datetime(2013, 1, 1, 2) assertEqual(self.formatter._format_token(dt, 'HH'), '02') assertEqual(self.formatter._format_token(dt, 'H'), '2') dt = datetime(2013, 1, 1, 13) assertEqual(self.formatter._format_token(dt, 'HH'), '13') assertEqual(self.formatter._format_token(dt, 'H'), '13') dt = datetime(2013, 1, 1, 2) assertEqual(self.formatter._format_token(dt, 'hh'), '02') assertEqual(self.formatter._format_token(dt, 'h'), '2') dt = datetime(2013, 1, 1, 13) assertEqual(self.formatter._format_token(dt, 'hh'), '01') assertEqual(self.formatter._format_token(dt, 'h'), '1') # test that 12-hour time converts to '12' at midnight dt = datetime(2013, 1, 1, 0) assertEqual(self.formatter._format_token(dt, 'hh'), '12') assertEqual(self.formatter._format_token(dt, 'h'), '12') def test_minute(self): dt = datetime(2013, 1, 1, 0, 1) assertEqual(self.formatter._format_token(dt, 'mm'), '01') assertEqual(self.formatter._format_token(dt, 'm'), '1') def test_second(self): dt = datetime(2013, 1, 1, 0, 0, 1) assertEqual(self.formatter._format_token(dt, 'ss'), '01') assertEqual(self.formatter._format_token(dt, 's'), '1') def test_sub_second(self): dt = datetime(2013, 1, 1, 0, 0, 0, 123456) assertEqual(self.formatter._format_token(dt, 'SSSSSS'), '123456') assertEqual(self.formatter._format_token(dt, 'SSSSS'), '12345') assertEqual(self.formatter._format_token(dt, 'SSSS'), '1234') assertEqual(self.formatter._format_token(dt, 'SSS'), '123') assertEqual(self.formatter._format_token(dt, 'SS'), '12') assertEqual(self.formatter._format_token(dt, 'S'), '1') dt = datetime(2013, 1, 1, 0, 0, 0, 2000) assertEqual(self.formatter._format_token(dt, 'SSSSSS'), '002000') assertEqual(self.formatter._format_token(dt, 'SSSSS'), '00200') assertEqual(self.formatter._format_token(dt, 'SSSS'), '0020') assertEqual(self.formatter._format_token(dt, 'SSS'), '002') assertEqual(self.formatter._format_token(dt, 'SS'), '00') assertEqual(self.formatter._format_token(dt, 'S'), '0') def test_timestamp(self): timestamp = time.time() dt = datetime.utcfromtimestamp(timestamp) assertEqual(self.formatter._format_token(dt, 'X'), str(int(timestamp))) def test_timezone(self): dt = datetime.utcnow().replace(tzinfo=dateutil_tz.gettz('US/Pacific')) result = self.formatter._format_token(dt, 'ZZ') assertTrue(result == '-07:00' or result == '-08:00') result = self.formatter._format_token(dt, 'Z') assertTrue(result == '-0700' or result == '-0800') def test_am_pm(self): dt = datetime(2012, 1, 1, 11) assertEqual(self.formatter._format_token(dt, 'a'), 'am') assertEqual(self.formatter._format_token(dt, 'A'), 'AM') dt = datetime(2012, 1, 1, 13) assertEqual(self.formatter._format_token(dt, 'a'), 'pm') assertEqual(self.formatter._format_token(dt, 'A'), 'PM') arrow-0.7.0/tests/locales_tests.py000066400000000000000000000254711260523235100172400ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import unicode_literals from datetime import datetime from chai import Chai from arrow import locales from arrow.api import now from arrow import arrow class ModuleTests(Chai): def test_get_locale(self): mock_locales = mock(locales, '_locales') mock_locale_cls = mock() mock_locale = mock() expect(mock_locales.get).args('name').returns(mock_locale_cls) expect(mock_locale_cls).returns(mock_locale) result = locales.get_locale('name') assertEqual(result, mock_locale) def test_locales(self): assertTrue(len(locales._locales) > 0) class LocaleTests(Chai): def setUp(self): super(LocaleTests, self).setUp() self.locale = locales.EnglishLocale() def test_format_timeframe(self): assertEqual(self.locale._format_timeframe('hours', 2), '2 hours') assertEqual(self.locale._format_timeframe('hour', 0), 'an hour') def test_format_relative_now(self): result = self.locale._format_relative('just now', 'now', 0) assertEqual(result, 'just now') def test_format_relative_past(self): result = self.locale._format_relative('an hour', 'hour', 1) assertEqual(result, 'in an hour') def test_format_relative_future(self): result = self.locale._format_relative('an hour', 'hour', -1) assertEqual(result, 'an hour ago') def test_ordinal_number(self): assertEqual(self.locale.ordinal_number(0), '0th') assertEqual(self.locale.ordinal_number(1), '1st') assertEqual(self.locale.ordinal_number(2), '2nd') assertEqual(self.locale.ordinal_number(3), '3rd') assertEqual(self.locale.ordinal_number(4), '4th') assertEqual(self.locale.ordinal_number(10), '10th') assertEqual(self.locale.ordinal_number(11), '11th') assertEqual(self.locale.ordinal_number(12), '12th') assertEqual(self.locale.ordinal_number(13), '13th') assertEqual(self.locale.ordinal_number(14), '14th') assertEqual(self.locale.ordinal_number(21), '21st') assertEqual(self.locale.ordinal_number(22), '22nd') assertEqual(self.locale.ordinal_number(23), '23rd') assertEqual(self.locale.ordinal_number(24), '24th') assertEqual(self.locale.ordinal_number(100), '100th') assertEqual(self.locale.ordinal_number(101), '101st') assertEqual(self.locale.ordinal_number(102), '102nd') assertEqual(self.locale.ordinal_number(103), '103rd') assertEqual(self.locale.ordinal_number(104), '104th') assertEqual(self.locale.ordinal_number(110), '110th') assertEqual(self.locale.ordinal_number(111), '111th') assertEqual(self.locale.ordinal_number(112), '112th') assertEqual(self.locale.ordinal_number(113), '113th') assertEqual(self.locale.ordinal_number(114), '114th') assertEqual(self.locale.ordinal_number(121), '121st') assertEqual(self.locale.ordinal_number(122), '122nd') assertEqual(self.locale.ordinal_number(123), '123rd') assertEqual(self.locale.ordinal_number(124), '124th') class ItalianLocalesTests(Chai): def test_ordinal_number(self): locale = locales.ItalianLocale() assertEqual(locale.ordinal_number(1), '1°') class SpanishLocalesTests(Chai): def test_ordinal_number(self): locale = locales.SpanishLocale() assertEqual(locale.ordinal_number(1), '1°') class FrenchLocalesTests(Chai): def test_ordinal_number(self): locale = locales.FrenchLocale() assertEqual(locale.ordinal_number(1), '1er') assertEqual(locale.ordinal_number(2), '2e') class RussianLocalesTests(Chai): def test_plurals2(self): locale = locales.RussianLocale() assertEqual(locale._format_timeframe('hours', 0), '0 часов') assertEqual(locale._format_timeframe('hours', 1), '1 час') assertEqual(locale._format_timeframe('hours', 2), '2 часа') assertEqual(locale._format_timeframe('hours', 4), '4 часа') assertEqual(locale._format_timeframe('hours', 5), '5 часов') assertEqual(locale._format_timeframe('hours', 21), '21 час') assertEqual(locale._format_timeframe('hours', 22), '22 часа') assertEqual(locale._format_timeframe('hours', 25), '25 часов') # feminine grammatical gender should be tested separately assertEqual(locale._format_timeframe('minutes', 0), '0 минут') assertEqual(locale._format_timeframe('minutes', 1), '1 минуту') assertEqual(locale._format_timeframe('minutes', 2), '2 минуты') assertEqual(locale._format_timeframe('minutes', 4), '4 минуты') assertEqual(locale._format_timeframe('minutes', 5), '5 минут') assertEqual(locale._format_timeframe('minutes', 21), '21 минуту') assertEqual(locale._format_timeframe('minutes', 22), '22 минуты') assertEqual(locale._format_timeframe('minutes', 25), '25 минут') class PolishLocalesTests(Chai): def test_plurals(self): locale = locales.PolishLocale() assertEqual(locale._format_timeframe('hours', 0), '0 godzin') assertEqual(locale._format_timeframe('hours', 1), '1 godzin') assertEqual(locale._format_timeframe('hours', 2), '2 godziny') assertEqual(locale._format_timeframe('hours', 4), '4 godziny') assertEqual(locale._format_timeframe('hours', 5), '5 godzin') assertEqual(locale._format_timeframe('hours', 21), '21 godzin') assertEqual(locale._format_timeframe('hours', 22), '22 godziny') assertEqual(locale._format_timeframe('hours', 25), '25 godzin') class IcelandicLocalesTests(Chai): def setUp(self): super(IcelandicLocalesTests, self).setUp() self.locale = locales.IcelandicLocale() def test_format_timeframe(self): assertEqual(self.locale._format_timeframe('minute', -1), 'einni mínútu') assertEqual(self.locale._format_timeframe('minute', 1), 'eina mínútu') assertEqual(self.locale._format_timeframe('hours', -2), '2 tímum') assertEqual(self.locale._format_timeframe('hours', 2), '2 tíma') class MalayalamLocaleTests(Chai): def setUp(self): super(MalayalamLocaleTests, self).setUp() self.locale = locales.MalayalamLocale() def test_format_timeframe(self): assertEqual(self.locale._format_timeframe('hours', 2), '2 മണിക്കൂർ') assertEqual(self.locale._format_timeframe('hour', 0), 'ഒരു മണിക്കൂർ') def test_format_relative_now(self): result = self.locale._format_relative('ഇപ്പോൾ', 'now', 0) assertEqual(result, 'ഇപ്പോൾ') def test_format_relative_past(self): result = self.locale._format_relative('ഒരു മണിക്കൂർ', 'hour', 1) assertEqual(result, 'ഒരു മണിക്കൂർ ശേഷം') def test_format_relative_future(self): result = self.locale._format_relative('ഒരു മണിക്കൂർ', 'hour', -1) assertEqual(result, 'ഒരു മണിക്കൂർ മുമ്പ്') class HindiLocaleTests(Chai): def setUp(self): super(HindiLocaleTests, self).setUp() self.locale = locales.HindiLocale() def test_format_timeframe(self): assertEqual(self.locale._format_timeframe('hours', 2), '2 घंटे') assertEqual(self.locale._format_timeframe('hour', 0), 'एक घंट') def test_format_relative_now(self): result = self.locale._format_relative('अभि', 'now', 0) assertEqual(result, 'अभि') def test_format_relative_past(self): result = self.locale._format_relative('एक घंट', 'hour', 1) assertEqual(result, 'एक घंट बाद') def test_format_relative_future(self): result = self.locale._format_relative('एक घंट', 'hour', -1) assertEqual(result, 'एक घंट पहले') class CzechLocaleTests(Chai): def setUp(self): super(CzechLocaleTests, self).setUp() self.locale = locales.CzechLocale() def test_format_timeframe(self): assertEqual(self.locale._format_timeframe('hours', 2), '2 hodiny') assertEqual(self.locale._format_timeframe('hour', 0), '0 hodin') def test_format_relative_now(self): result = self.locale._format_relative('Teď', 'now', 0) assertEqual(result, 'Teď') def test_format_relative_future(self): result = self.locale._format_relative('hodinu', 'hour', 1) assertEqual(result, 'Za hodinu') def test_format_relative_past(self): result = self.locale._format_relative('hodinou', 'hour', -1) assertEqual(result, 'Před hodinou') class HebrewLocaleTests(Chai): def test_couple_of_timeframe(self): locale = locales.HebrewLocale() assertEqual(locale._format_timeframe('hours', 2), 'שעתיים') assertEqual(locale._format_timeframe('months', 2), 'חודשיים') assertEqual(locale._format_timeframe('days', 2), 'יומיים') assertEqual(locale._format_timeframe('years', 2), 'שנתיים') assertEqual(locale._format_timeframe('hours', 3), '3 שעות') assertEqual(locale._format_timeframe('months', 4), '4 חודשים') assertEqual(locale._format_timeframe('days', 3), '3 ימים') assertEqual(locale._format_timeframe('years', 5), '5 שנים') class MarathiLocaleTests(Chai): def setUp(self): super(MarathiLocaleTests, self).setUp() self.locale = locales.MarathiLocale() def test_dateCoreFunctionality(self): dt = arrow.Arrow(2015, 4, 11, 17, 30, 00) assertEqual (self.locale.month_name(dt.month),'एप्रिल') assertEqual (self.locale.month_abbreviation(dt.month),'एप्रि') assertEqual (self.locale.day_name(dt.isoweekday()),'शनिवार') assertEqual (self.locale.day_abbreviation(dt.isoweekday()), 'शनि') def test_format_timeframe(self): assertEqual(self.locale._format_timeframe('hours', 2), '2 तास') assertEqual(self.locale._format_timeframe('hour', 0), 'एक तास') def test_format_relative_now(self): result = self.locale._format_relative('सद्य', 'now', 0) assertEqual(result, 'सद्य') def test_format_relative_past(self): result = self.locale._format_relative('एक तास', 'hour', 1) assertEqual(result, 'एक तास नंतर') def test_format_relative_future(self): result = self.locale._format_relative('एक तास', 'hour', -1) assertEqual(result, 'एक तास आधी') # Not currently implemented def test_ordinal_number(self): assertEqual(self.locale.ordinal_number(1), '1') arrow-0.7.0/tests/parser_tests.py000066400000000000000000000501711260523235100171050ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import unicode_literals from chai import Chai from datetime import datetime from dateutil import tz import calendar import time from arrow import parser from arrow.parser import ParserError class DateTimeParserTests(Chai): def setUp(self): super(DateTimeParserTests, self).setUp() self.parser = parser.DateTimeParser() def test_parse_multiformat(self): mock_datetime = mock() expect(self.parser.parse).args('str', 'fmt_a').raises(Exception) expect(self.parser.parse).args('str', 'fmt_b').returns(mock_datetime) result = self.parser._parse_multiformat('str', ['fmt_a', 'fmt_b']) assertEqual(result, mock_datetime) def test_parse_multiformat_all_fail(self): expect(self.parser.parse).args('str', 'fmt_a').raises(Exception) expect(self.parser.parse).args('str', 'fmt_b').raises(Exception) with assertRaises(Exception): self.parser._parse_multiformat('str', ['fmt_a', 'fmt_b']) class DateTimeParserParseTests(Chai): def setUp(self): super(DateTimeParserParseTests, self).setUp() self.parser = parser.DateTimeParser() def test_parse_list(self): expect(self.parser._parse_multiformat).args('str', ['fmt_a', 'fmt_b']).returns('result') result = self.parser.parse('str', ['fmt_a', 'fmt_b']) assertEqual(result, 'result') def test_parse_unrecognized_token(self): mock_input_re_map = mock(self.parser, '_input_re_map') expect(mock_input_re_map.__getitem__).args('YYYY').raises(KeyError) with assertRaises(parser.ParserError): self.parser.parse('2013-01-01', 'YYYY-MM-DD') def test_parse_parse_no_match(self): with assertRaises(parser.ParserError): self.parser.parse('01-01', 'YYYY-MM-DD') def test_parse_separators(self): with assertRaises(parser.ParserError): self.parser.parse('1403549231', 'YYYY-MM-DD') def test_parse_numbers(self): expected = datetime(2012, 1, 1, 12, 5, 10) assertEqual(self.parser.parse('2012-01-01 12:05:10', 'YYYY-MM-DD HH:mm:ss'), expected) def test_parse_year_two_digit(self): expected = datetime(1979, 1, 1, 12, 5, 10) assertEqual(self.parser.parse('79-01-01 12:05:10', 'YY-MM-DD HH:mm:ss'), expected) def test_parse_timestamp(self): tz_utc = tz.tzutc() timestamp = int(time.time()) expected = datetime.fromtimestamp(timestamp, tz=tz_utc) assertEqual(self.parser.parse(str(timestamp), 'X'), expected) def test_parse_names(self): expected = datetime(2012, 1, 1) assertEqual(self.parser.parse('January 1, 2012', 'MMMM D, YYYY'), expected) assertEqual(self.parser.parse('Jan 1, 2012', 'MMM D, YYYY'), expected) def test_parse_pm(self): expected = datetime(1, 1, 1, 13, 0, 0) assertEqual(self.parser.parse('1 pm', 'H a'), expected) assertEqual(self.parser.parse('1 pm', 'h a'), expected) expected = datetime(1, 1, 1, 1, 0, 0) assertEqual(self.parser.parse('1 am', 'H A'), expected) assertEqual(self.parser.parse('1 am', 'h A'), expected) expected = datetime(1, 1, 1, 0, 0, 0) assertEqual(self.parser.parse('12 am', 'H A'), expected) assertEqual(self.parser.parse('12 am', 'h A'), expected) expected = datetime(1, 1, 1, 12, 0, 0) assertEqual(self.parser.parse('12 pm', 'H A'), expected) assertEqual(self.parser.parse('12 pm', 'h A'), expected) def test_parse_tz(self): expected = datetime(2013, 1, 1, tzinfo=tz.tzoffset(None, -7 * 3600)) assertEqual(self.parser.parse('2013-01-01 -07:00', 'YYYY-MM-DD ZZ'), expected) def test_parse_subsecond(self): expected = datetime(2013, 1, 1, 12, 30, 45, 900000) assertEqual(self.parser.parse('2013-01-01 12:30:45.9', 'YYYY-MM-DD HH:mm:ss.S'), expected) assertEqual(self.parser.parse_iso('2013-01-01 12:30:45.9'), expected) expected = datetime(2013, 1, 1, 12, 30, 45, 980000) assertEqual(self.parser.parse('2013-01-01 12:30:45.98', 'YYYY-MM-DD HH:mm:ss.SS'), expected) assertEqual(self.parser.parse_iso('2013-01-01 12:30:45.98'), expected) expected = datetime(2013, 1, 1, 12, 30, 45, 987000) assertEqual(self.parser.parse('2013-01-01 12:30:45.987', 'YYYY-MM-DD HH:mm:ss.SSS'), expected) assertEqual(self.parser.parse_iso('2013-01-01 12:30:45.987'), expected) expected = datetime(2013, 1, 1, 12, 30, 45, 987600) assertEqual(self.parser.parse('2013-01-01 12:30:45.9876', 'YYYY-MM-DD HH:mm:ss.SSSS'), expected) assertEqual(self.parser.parse_iso('2013-01-01 12:30:45.9876'), expected) expected = datetime(2013, 1, 1, 12, 30, 45, 987650) assertEqual(self.parser.parse('2013-01-01 12:30:45.98765', 'YYYY-MM-DD HH:mm:ss.SSSSS'), expected) assertEqual(self.parser.parse_iso('2013-01-01 12:30:45.98765'), expected) expected = datetime(2013, 1, 1, 12, 30, 45, 987654) assertEqual(self.parser.parse('2013-01-01 12:30:45.987654', 'YYYY-MM-DD HH:mm:ss.SSSSSS'), expected) assertEqual(self.parser.parse_iso('2013-01-01 12:30:45.987654'), expected) expected = datetime(2013, 1, 1, 12, 30, 45, 987654) assertEqual(self.parser.parse('2013-01-01 12:30:45.9876543', 'YYYY-MM-DD HH:mm:ss.SSSSSS'), expected) assertEqual(self.parser.parse_iso('2013-01-01 12:30:45.9876543'), expected) expected = datetime(2013, 1, 1, 12, 30, 45, 987654) assertEqual(self.parser.parse('2013-01-01 12:30:45.98765432', 'YYYY-MM-DD HH:mm:ss.SSSSSS'), expected) assertEqual(self.parser.parse_iso('2013-01-01 12:30:45.98765432'), expected) expected = datetime(2013, 1, 1, 12, 30, 45, 987654) assertEqual(self.parser.parse('2013-01-01 12:30:45.987654321', 'YYYY-MM-DD HH:mm:ss.SSSSSS'), expected) assertEqual(self.parser.parse_iso('2013-01-01 12:30:45.987654321'), expected) def test_map_lookup_keyerror(self): with assertRaises(parser.ParserError): parser.DateTimeParser._map_lookup({'a': '1'}, 'b') def test_try_timestamp(self): assertEqual(parser.DateTimeParser._try_timestamp('1.1'), 1.1) assertEqual(parser.DateTimeParser._try_timestamp('1'), 1) assertEqual(parser.DateTimeParser._try_timestamp('abc'), None) class DateTimeParserRegexTests(Chai): def setUp(self): super(DateTimeParserRegexTests, self).setUp() self.format_regex = parser.DateTimeParser._FORMAT_RE def test_format_year(self): assertEqual(self.format_regex.findall('YYYY-YY'), ['YYYY', 'YY']) def test_format_month(self): assertEqual(self.format_regex.findall('MMMM-MMM-MM-M'), ['MMMM', 'MMM', 'MM', 'M']) def test_format_day(self): assertEqual(self.format_regex.findall('DDDD-DDD-DD-D'), ['DDDD', 'DDD', 'DD', 'D']) def test_format_hour(self): assertEqual(self.format_regex.findall('HH-H-hh-h'), ['HH', 'H', 'hh', 'h']) def test_format_minute(self): assertEqual(self.format_regex.findall('mm-m'), ['mm', 'm']) def test_format_second(self): assertEqual(self.format_regex.findall('ss-s'), ['ss', 's']) def test_format_subsecond(self): assertEqual(self.format_regex.findall('SSSSSS-SSSSS-SSSS-SSS-SS-S'), ['SSSSSS', 'SSSSS', 'SSSS', 'SSS', 'SS', 'S']) def test_format_tz(self): assertEqual(self.format_regex.findall('ZZ-Z'), ['ZZ', 'Z']) def test_format_am_pm(self): assertEqual(self.format_regex.findall('A-a'), ['A', 'a']) def test_format_timestamp(self): assertEqual(self.format_regex.findall('X'), ['X']) def test_month_names(self): p = parser.DateTimeParser('en_us') text = '_'.join(calendar.month_name[1:]) result = p._input_re_map['MMMM'].findall(text) assertEqual(result, calendar.month_name[1:]) def test_month_abbreviations(self): p = parser.DateTimeParser('en_us') text = '_'.join(calendar.month_abbr[1:]) result = p._input_re_map['MMM'].findall(text) assertEqual(result, calendar.month_abbr[1:]) def test_digits(self): assertEqual(parser.DateTimeParser._TWO_DIGIT_RE.findall('12-3-45'), ['12', '45']) assertEqual(parser.DateTimeParser._FOUR_DIGIT_RE.findall('1234-56'), ['1234']) assertEqual(parser.DateTimeParser._ONE_OR_TWO_DIGIT_RE.findall('4-56'), ['4', '56']) class DateTimeParserISOTests(Chai): def setUp(self): super(DateTimeParserISOTests, self).setUp() self.parser = parser.DateTimeParser('en_us') def test_YYYY(self): assertEqual( self.parser.parse_iso('2013'), datetime(2013, 1, 1) ) def test_YYYY_MM(self): assertEqual( self.parser.parse_iso('2013-02'), datetime(2013, 2, 1) ) def test_YYYY_MM_DD(self): assertEqual( self.parser.parse_iso('2013-02-03'), datetime(2013, 2, 3) ) def test_YYYY_MM_DDTHH_mmZ(self): assertEqual( self.parser.parse_iso('2013-02-03T04:05+01:00'), datetime(2013, 2, 3, 4, 5, tzinfo=tz.tzoffset(None, 3600)) ) def test_YYYY_MM_DDTHH_mm(self): assertEqual( self.parser.parse_iso('2013-02-03T04:05'), datetime(2013, 2, 3, 4, 5) ) def test_YYYY_MM_DDTHH_mm_ssZ(self): assertEqual( self.parser.parse_iso('2013-02-03T04:05:06+01:00'), datetime(2013, 2, 3, 4, 5, 6, tzinfo=tz.tzoffset(None, 3600)) ) def test_YYYY_MM_DDTHH_mm_ss(self): assertEqual( self.parser.parse_iso('2013-02-03T04:05:06'), datetime(2013, 2, 3, 4, 5, 6) ) def test_YYYY_MM_DD_HH_mmZ(self): assertEqual( self.parser.parse_iso('2013-02-03 04:05+01:00'), datetime(2013, 2, 3, 4, 5, tzinfo=tz.tzoffset(None, 3600)) ) def test_YYYY_MM_DD_HH_mm(self): assertEqual( self.parser.parse_iso('2013-02-03 04:05'), datetime(2013, 2, 3, 4, 5) ) def test_YYYY_MM_DD_HH_mm_ssZ(self): assertEqual( self.parser.parse_iso('2013-02-03 04:05:06+01:00'), datetime(2013, 2, 3, 4, 5, 6, tzinfo=tz.tzoffset(None, 3600)) ) def test_YYYY_MM_DD_HH_mm_ss(self): assertEqual( self.parser.parse_iso('2013-02-03 04:05:06'), datetime(2013, 2, 3, 4, 5, 6) ) def test_YYYY_MM_DDTHH_mm_ss_S(self): assertEqual( self.parser.parse_iso('2013-02-03T04:05:06.7'), datetime(2013, 2, 3, 4, 5, 6, 700000) ) assertEqual( self.parser.parse_iso('2013-02-03T04:05:06.78'), datetime(2013, 2, 3, 4, 5, 6, 780000) ) assertEqual( self.parser.parse_iso('2013-02-03T04:05:06.789'), datetime(2013, 2, 3, 4, 5, 6, 789000) ) assertEqual( self.parser.parse_iso('2013-02-03T04:05:06.7891'), datetime(2013, 2, 3, 4, 5, 6, 789100) ) assertEqual( self.parser.parse_iso('2013-02-03T04:05:06.78912'), datetime(2013, 2, 3, 4, 5, 6, 789120) ) def test_YYYY_MM_DDTHH_mm_ss_SZ(self): assertEqual( self.parser.parse_iso('2013-02-03T04:05:06.7+01:00'), datetime(2013, 2, 3, 4, 5, 6, 700000, tzinfo=tz.tzoffset(None, 3600)) ) assertEqual( self.parser.parse_iso('2013-02-03T04:05:06.78+01:00'), datetime(2013, 2, 3, 4, 5, 6, 780000, tzinfo=tz.tzoffset(None, 3600)) ) assertEqual( self.parser.parse_iso('2013-02-03T04:05:06.789+01:00'), datetime(2013, 2, 3, 4, 5, 6, 789000, tzinfo=tz.tzoffset(None, 3600)) ) assertEqual( self.parser.parse_iso('2013-02-03T04:05:06.7891+01:00'), datetime(2013, 2, 3, 4, 5, 6, 789100, tzinfo=tz.tzoffset(None, 3600)) ) assertEqual( self.parser.parse_iso('2013-02-03T04:05:06.78912+01:00'), datetime(2013, 2, 3, 4, 5, 6, 789120, tzinfo=tz.tzoffset(None, 3600)) ) # Properly parse string with Z timezone assertEqual( self.parser.parse_iso('2013-02-03T04:05:06.78912Z'), datetime(2013, 2, 3, 4, 5, 6, 789120) ) def test_isoformat(self): dt = datetime.utcnow() assertEqual(self.parser.parse_iso(dt.isoformat()), dt) class TzinfoParserTests(Chai): def setUp(self): super(TzinfoParserTests, self).setUp() self.parser = parser.TzinfoParser() def test_parse_local(self): assertEqual(self.parser.parse('local'), tz.tzlocal()) def test_parse_utc(self): assertEqual(self.parser.parse('utc'), tz.tzutc()) assertEqual(self.parser.parse('UTC'), tz.tzutc()) def test_parse_iso(self): assertEqual(self.parser.parse('01:00'), tz.tzoffset(None, 3600)) assertEqual(self.parser.parse('+01:00'), tz.tzoffset(None, 3600)) assertEqual(self.parser.parse('-01:00'), tz.tzoffset(None, -3600)) def test_parse_str(self): assertEqual(self.parser.parse('US/Pacific'), tz.gettz('US/Pacific')) def test_parse_fails(self): with assertRaises(parser.ParserError): self.parser.parse('fail') class DateTimeParserMonthNameTests(Chai): def setUp(self): super(DateTimeParserMonthNameTests, self).setUp() self.parser = parser.DateTimeParser('en_us') def test_shortmonth_capitalized(self): assertEqual( self.parser.parse('2013-Jan-01', 'YYYY-MMM-DD'), datetime(2013, 1, 1) ) def test_shortmonth_allupper(self): assertEqual( self.parser.parse('2013-JAN-01', 'YYYY-MMM-DD'), datetime(2013, 1, 1) ) def test_shortmonth_alllower(self): assertEqual( self.parser.parse('2013-jan-01', 'YYYY-MMM-DD'), datetime(2013, 1, 1) ) def test_month_capitalized(self): assertEqual( self.parser.parse('2013-January-01', 'YYYY-MMMM-DD'), datetime(2013, 1, 1) ) def test_month_allupper(self): assertEqual( self.parser.parse('2013-JANUARY-01', 'YYYY-MMMM-DD'), datetime(2013, 1, 1) ) def test_month_alllower(self): assertEqual( self.parser.parse('2013-january-01', 'YYYY-MMMM-DD'), datetime(2013, 1, 1) ) def test_localized_month_name(self): parser_ = parser.DateTimeParser('fr_fr') assertEqual( parser_.parse('2013-Janvier-01', 'YYYY-MMMM-DD'), datetime(2013, 1, 1) ) def test_localized_month_abbreviation(self): parser_ = parser.DateTimeParser('it_it') assertEqual( parser_.parse('2013-Gen-01', 'YYYY-MMM-DD'), datetime(2013, 1, 1) ) class DateTimeParserMeridiansTests(Chai): def setUp(self): super(DateTimeParserMeridiansTests, self).setUp() self.parser = parser.DateTimeParser('en_us') def test_meridians_lowercase(self): assertEqual( self.parser.parse('2013-01-01 5am', 'YYYY-MM-DD ha'), datetime(2013, 1, 1, 5) ) assertEqual( self.parser.parse('2013-01-01 5pm', 'YYYY-MM-DD ha'), datetime(2013, 1, 1, 17) ) def test_meridians_capitalized(self): assertEqual( self.parser.parse('2013-01-01 5AM', 'YYYY-MM-DD hA'), datetime(2013, 1, 1, 5) ) assertEqual( self.parser.parse('2013-01-01 5PM', 'YYYY-MM-DD hA'), datetime(2013, 1, 1, 17) ) def test_localized_meridians_lowercase(self): parser_ = parser.DateTimeParser('hu_hu') assertEqual( parser_.parse('2013-01-01 5 de', 'YYYY-MM-DD h a'), datetime(2013, 1, 1, 5) ) assertEqual( parser_.parse('2013-01-01 5 du', 'YYYY-MM-DD h a'), datetime(2013, 1, 1, 17) ) def test_localized_meridians_capitalized(self): parser_ = parser.DateTimeParser('hu_hu') assertEqual( parser_.parse('2013-01-01 5 DE', 'YYYY-MM-DD h A'), datetime(2013, 1, 1, 5) ) assertEqual( parser_.parse('2013-01-01 5 DU', 'YYYY-MM-DD h A'), datetime(2013, 1, 1, 17) ) class DateTimeParserMonthOrdinalDayTests(Chai): def setUp(self): super(DateTimeParserMonthOrdinalDayTests, self).setUp() self.parser = parser.DateTimeParser('en_us') def test_english(self): parser_ = parser.DateTimeParser('en_us') assertEqual( parser_.parse('January 1st, 2013', 'MMMM Do, YYYY'), datetime(2013, 1, 1) ) assertEqual( parser_.parse('January 2nd, 2013', 'MMMM Do, YYYY'), datetime(2013, 1, 2) ) assertEqual( parser_.parse('January 3rd, 2013', 'MMMM Do, YYYY'), datetime(2013, 1, 3) ) assertEqual( parser_.parse('January 4th, 2013', 'MMMM Do, YYYY'), datetime(2013, 1, 4) ) assertEqual( parser_.parse('January 11th, 2013', 'MMMM Do, YYYY'), datetime(2013, 1, 11) ) assertEqual( parser_.parse('January 12th, 2013', 'MMMM Do, YYYY'), datetime(2013, 1, 12) ) assertEqual( parser_.parse('January 13th, 2013', 'MMMM Do, YYYY'), datetime(2013, 1, 13) ) assertEqual( parser_.parse('January 21st, 2013', 'MMMM Do, YYYY'), datetime(2013, 1, 21) ) assertEqual( parser_.parse('January 31st, 2013', 'MMMM Do, YYYY'), datetime(2013, 1, 31) ) with assertRaises(ParserError): parser_.parse('January 1th, 2013', 'MMMM Do, YYYY') with assertRaises(ParserError): parser_.parse('January 11st, 2013', 'MMMM Do, YYYY') def test_italian(self): parser_ = parser.DateTimeParser('it_it') assertEqual(parser_.parse('Gennaio 1°, 2013', 'MMMM Do, YYYY'), datetime(2013, 1, 1)) def test_spanish(self): parser_ = parser.DateTimeParser('es_es') assertEqual(parser_.parse('Enero 1°, 2013', 'MMMM Do, YYYY'), datetime(2013, 1, 1)) def test_french(self): parser_ = parser.DateTimeParser('fr_fr') assertEqual(parser_.parse('Janvier 1er, 2013', 'MMMM Do, YYYY'), datetime(2013, 1, 1)) assertEqual(parser_.parse('Janvier 2e, 2013', 'MMMM Do, YYYY'), datetime(2013, 1, 2)) assertEqual(parser_.parse('Janvier 11e, 2013', 'MMMM Do, YYYY'), datetime(2013, 1, 11)) class DateTimeParserSearchDateTests(Chai): def setUp(self): super(DateTimeParserSearchDateTests, self).setUp() self.parser = parser.DateTimeParser() def test_parse_search(self): assertEqual( self.parser.parse('Today is 25 of September of 2003', 'DD of MMMM of YYYY'), datetime(2003, 9, 25)) def test_parse_seach_with_numbers(self): assertEqual( self.parser.parse('2000 people met the 2012-01-01 12:05:10', 'YYYY-MM-DD HH:mm:ss'), datetime(2012, 1, 1, 12, 5, 10)) assertEqual( self.parser.parse('Call 01-02-03 on 79-01-01 12:05:10', 'YY-MM-DD HH:mm:ss'), datetime(1979, 1, 1, 12, 5, 10)) def test_parse_seach_with_names(self): assertEqual( self.parser.parse('June was born in May 1980', 'MMMM YYYY'), datetime(1980, 5, 1)) def test_parse_seach_locale_with_names(self): p = parser.DateTimeParser('sv_se') assertEqual( p.parse('Jan föddes den 31 Dec 1980', 'DD MMM YYYY'), datetime(1980, 12, 31)) assertEqual( p.parse('Jag föddes den 25 Augusti 1975', 'DD MMMM YYYY'), datetime(1975, 8, 25)) def test_parse_seach_fails(self): with assertRaises(parser.ParserError): self.parser.parse('Jag föddes den 25 Augusti 1975', 'DD MMMM YYYY') arrow-0.7.0/tests/util_tests.py000066400000000000000000000007611260523235100165660ustar00rootroot00000000000000# -*- coding: utf-8 -*- from chai import Chai from datetime import timedelta import sys from arrow import util class UtilTests(Chai): def setUp(self): super(UtilTests, self).setUp() def test_total_seconds_26(self): td = timedelta(seconds=30) assertEqual(util._total_seconds_26(td), 30) if util.version >= '2.7': def test_total_seconds_27(self): td = timedelta(seconds=30) assertEqual(util._total_seconds_27(td), 30)