summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--python-edtf.spec678
-rw-r--r--sources1
3 files changed, 680 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e69de29..dc65801 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1 @@
+/edtf-4.0.1.tar.gz
diff --git a/python-edtf.spec b/python-edtf.spec
new file mode 100644
index 0000000..6c4addb
--- /dev/null
+++ b/python-edtf.spec
@@ -0,0 +1,678 @@
+%global _empty_manifest_terminate_build 0
+Name: python-edtf
+Version: 4.0.1
+Release: 1
+Summary: Python implementation of Library of Congress EDTF (Extended Date Time Format) specification
+License: MIT
+URL: https://github.com/ixc/python-edtf
+Source0: https://mirrors.nju.edu.cn/pypi/web/packages/a9/5f/1e2e40520f60ac4d0faed04aa2f4fd1fbf82fbb779a1a26188668c611762/edtf-4.0.1.tar.gz
+BuildArch: noarch
+
+Requires: python3-dateutil
+Requires: python3-pyparsing
+Requires: python3-six
+Requires: python3-django
+Requires: python3-nose
+Requires: python3-tox
+
+%description
+An implementation of EDTF format in Python, together with utility functions for parsing natural language date texts, and converting EDTF dates to related Python `date` objects.
+See http://www.loc.gov/standards/datetime/ for the current draft specification.
+## To install
+ pip install edtf
+## To use
+ >>> from edtf import parse_edtf
+ # Parse an EDTF string to an EDTFObject
+ >>> e = parse_edtf("1979-08~") # approx August 1979
+ >>> e
+ UncertainOrApproximate: '1979-08~'
+ # normalised string representation (some different EDTF strings have identical meanings)
+ >>> unicode(e)
+ u'1979-08~'
+ # Derive Python date objects
+ # lower and upper bounds that strictly adhere to the given range
+ >>> e.lower_strict()[:3], e.upper_strict()[:3]
+ ((1979, 8, 1), (1979, 8, 31))
+ # lower and upper bounds that are padded if there's indicated uncertainty
+ >>> e.lower_fuzzy()[:3], e.upper_fuzzy()[:3]
+ ((1979, 7, 1), (1979, 9, 30))
+ # Date intervals
+ >>> interval = parse_edtf("1979-08~/open")
+ >>> interval
+ Level1Interval: '1979-08~/open'
+ # Intervals have lower and upper EDTF objects.
+ >>> interval.lower, interval.upper
+ (UncertainOrApproximate: '1979-08~', UncertainOrApproximate: 'open')
+ >>> interval.lower.upper_strict()[:3]
+ (1979, 8, 31)
+ >>> interval.upper.lower_strict() # 'open' is interpreted to mean 'still happening'.
+ [Today's date]
+ # Date collections
+ >>> coll = parse_edtf('{1667,1668, 1670..1672}')
+ >>> coll
+ MultipleDates: '{1667, 1668, 1670..1672}'
+ >>> coll.objects
+ (Date: '1667', Date: '1668', Consecutives: '1670..1672')
+The object returned by `parse_edtf()` is an instance of an `edtf.parser.parser_classes.EDTFObject` subclass, depending on the type of date that was parsed. These classes are:
+ # Level 0
+ Date
+ DateAndTime
+ Interval
+ # Level 1
+ UncertainOrApproximate
+ Unspecified
+ Level1Interval
+ LongYear
+ Season
+ # Level 2
+ PartialUncertainOrApproximate
+ PartialUnspecified
+ OneOfASet
+ MultipleDates
+ MaskedPrecision
+ Level2Interval
+ ExponentialYear
+All of these implement `upper/lower_strict/fuzzy()` methods to derive Python `date` objects.
+The `*Interval` instances have `upper` and `lower` properties that are themselves `EDTFObject` instances.
+`OneOfASet` and `MultipleDates` instances have an `objects` property that is a list of all of the EDTF dates parsed in the set or list.
+## EDTF Specification Inclusions
+The library includes implementation of levels 0, 1 and 2 of the EDTF spec.
+Test coverage includes every example given in the spec table of features.
+### Level 0 ISO 8601 Features
+* Date:
+ >>> parse_edtf('1979-08') # August 1979
+ Date: '1979-08'
+* Date and Time:
+ >>> parse_edtf('2004-01-01T10:10:10+05:00')
+ DateAndTime: '2004-01-01T10:10:10+05:00'
+* Interval (start/end):
+ >>> parse_edtf('1979-08-28/1979-09-25') # From August 28 to September 25 1979
+ Interval: '1979-08-28/1979-09-25'
+### Level 1 Extensions
+* Uncertain/Approximate dates:
+ >>> parse_edtf('1979-08-28~') # Approximately August 28th 1979
+ UncertainOrApproximate: '1979-08-28~'
+* Unspecified dates:
+ >>> parse_edtf('1979-08-uu') # An unknown day in August 1979
+ Unspecified: '1979-08-uu'
+ >>> parse_edtf('1979-uu') # Some month in 1979
+ Unspecified: '1979-uu'
+* Extended intervals:
+ >>> parse_edtf('1984-06-02?/2004-08-08~')
+ Level1Interval: '1984-06-02?/2004-08-08~'
+* Years exceeding four digits:
+ >>> parse_edtf('y-12000') # 12000 years BCE
+ LongYear: 'y-12000'
+* Season:
+ >>> parse_edtf('1979-22') # Summer 1979
+ Season: '1979-22'
+### Level 2 Extensions
+* Partial uncertain/approximate:
+ >>> parse_edtf('(2011)-06-04~') # year certain, month/day approximate.
+ # Note that the result text is normalized
+ PartialUncertainOrApproximate: '2011-(06-04)~'
+* Partial unspecified:
+ >>> parse_edtf('1979-uu-28') # The 28th day of an uncertain month in 1979
+ PartialUnspecified: '1979-uu-28'
+* One of a set:
+ >>> parse_edtf("[..1760-12-03,1762]")
+ OneOfASet: '[..1760-12-03, 1762]'
+* Multiple dates:
+ >>> parse_edtf('{1667,1668, 1670..1672}')
+ MultipleDates: '{1667, 1668, 1670..1672}'
+* Masked precision:
+ >>> parse_edtf('197x') # A date in the 1970s.
+ MaskedPrecision: '197x'
+* Level 2 Extended intervals:
+ >>> parse_edtf('2004-06-(01)~/2004-06-(20)~')
+ Level2Interval: '2004-06-(01)~/2004-06-(20)~'
+* Year requiring more than 4 digits - exponential form:
+ >>> parse_edtf('y-17e7')
+ ExponentialYear: 'y-17e7'
+### Natural language representation
+The library includes a basic English natural language parser (it's not yet smart enough to work with occasions such as 'Easter', or in other languages):
+ >>> from edtf import text_to_edtf
+ >>> text_to_edtf("circa August 1979")
+ '1979-08~'
+Note that the result is a string, not an `ETDFObject`.
+The parser can parse strings such as:
+ 'January 12, 1940' => '1940-01-12'
+ '90' => '1990' #implied century
+ 'January 2008' => '2008-01'
+ 'the year 1800' => '1800'
+ '10/7/2008' => '2008-10-07' # in a full-specced date, assume US ordering
+ # uncertain/approximate
+ '1860?' => '1860?'
+ '1862 (uncertain)' => '1862?'
+ 'circa Feb 1812' => '1812-02~'
+ 'c.1860' => '1860~' #with or without .
+ 'ca1860' => '1860~'
+ 'approx 1860' => '1860~'
+ # masked precision
+ '1860s' => '186x' #186x has decade precision, 186u has year precision.
+ '1800s' => '18xx' # without uncertainty indicators, assume century
+ # masked precision + uncertainty
+ 'ca. 1860s' => '186x~'
+ 'circa 1840s' => '184x~'
+ 'ca. 1860s?' => '186x?~'
+ 'c1800s?' => '180x?~' # with uncertainty indicators, use the decade
+ # unspecified parts
+ 'January 12' => 'uuuu-01-12'
+ 'January' => 'uuuu-01'
+ '7/2008' => '2008-07'
+ #seasons
+ 'Autumn 1872' => '1872-23'
+ 'Fall 1872' => '1872-23'
+ # before/after
+ 'earlier than 1928' => 'unknown/1928'
+ 'later than 1928' => '1928/unknown'
+ 'before January 1928' => 'unknown/1928-01'
+ 'after about the 1920s' => '192x~/unknown'
+ # unspecified
+ 'year in the 1860s' => '186u' #186x has decade precision, 186u has year precision.
+ ('year in the 1800s', '18xu')
+ 'month in 1872' => '1872-uu'
+ 'day in January 1872' => '1872-01-uu'
+ 'day in 1872' => '1872-uu-uu'
+ #centuries
+ '1st century' => '00xx'
+ '10c' => '09xx'
+ '19th century?' => '18xx?'
+ # just showing off now...
+ 'a day in about Spring 1849?' => '1849-21-uu?~'
+ # simple ranges, which aren't as accurate as they could be. The parser is
+ limited to only picking the first year range it finds.
+ '1851-1852' => '1851/1852'
+ '1851-1852; printed 1853-1854' => '1851/1852'
+ '1851-52' => '1851/1852'
+ '1856-ca. 1865' => '1856/1865~'
+ '1860s-1870s' => '186x/187x'
+ '1920s -early 1930s' => '192x/193x'
+ '1938, printed 1940s-1950s' => '1938'
+Generating natural text from an EDTF representation is a future goal.
+### What assumptions does the natural text parser make when interpreting an ambiguous date?
+* "1800s" is ambiguously a century or decade. If the given date is either uncertain or approximate, the decade interpretation is used. If the date is certain and precise, the century interpretation is used.
+* If the century isn't specified (`EDTF(natural_text="the '70s")`), we imply the century to be "19" if the year is greater than the current year, otherwise we imply the century to be the current century.
+* US-ordered dates (mm/dd/yyyy) are assumed by default in natural language. To change this, set `DAY_FIRST` to True in settings.
+* If a natural language groups dates with a '/', it's interpreted as "or" rather than "and". The resulting EDTF text is a list bracketed by `[]` ("one of these dates") rather than `{}` (all of these dates).
+## Converting to and from Python dates
+Since EDTF dates are often regions, and often imprecise, we need to use a few different Python dates, depending on the circumstance. Generally, Python dates are used for sorting and filtering, and are not displayed directly to users.
+### `struct_time` date representation
+Because Python's `datetime` module does not support dates out side the range 1 AD to 9999 AD we return dates as `time.struct_time` objects by default instead of the `datetime.date` or `datetime.datetime` objects you might expect.
+The `struct_time` representation is more difficult to work with, but can be sorted as-is which is the primary use-case, and can be converted relatively easily to `date` or `datetime` objects (provided the year is within 1 to 9999 AD) or to date objects in more flexible libraries like [astropy.time](http://docs.astropy.org/en/stable/time/index.html) for years outside these bounds.
+If you are sure you are working with dates within the range supported by Python's `datetime` module, you can get these more convenient objects using the `edtf.struct_time_to_date` and `edtf.struct_time_to_datetime` functions.
+NOTE: This library previously did return `date` and `datetime` objects from methods by default before we switched to `struct_time`. See ticket https://github.com/ixc/python-edtf/issues/26.
+### `lower_strict` and `upper_strict`
+These dates indicate the earliest and latest dates that are __strictly__ in the date range, ignoring uncertainty or approximation. One way to think about this is 'if you had to pick a single date to sort by, what would it be?'.
+In an ascending sort (most recent last), sort by `lower_strict` to get a natural sort order. In a descending sort (most recent first), sort by `upper_strict`:
+ >>> e = parse_edtf('1912-04~')
+ >>> e.lower_strict() # Returns struct_time
+ >>> time.struct_time(tm_year=1912, tm_mon=4, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=0, tm_yday=0, tm_isdst=-1)
+ >>> e.lower_strict()[:3] # Show only interesting parts of struct_time
+ (1912, 4, 01)
+ >>> from edtf import struct_time_to_date
+ >>> struct_time_to_date(e.lower_strict()) # Convert to date
+ datetime.date(1912, 4, 01)
+ >>> e.upper_strict()[:3]
+ (1912, 4, 30)
+ >>> struct_time_to_date(e.upper_strict())
+ datetime.date(1912, 4, 30)
+
+%package -n python3-edtf
+Summary: Python implementation of Library of Congress EDTF (Extended Date Time Format) specification
+Provides: python-edtf
+BuildRequires: python3-devel
+BuildRequires: python3-setuptools
+BuildRequires: python3-pip
+%description -n python3-edtf
+An implementation of EDTF format in Python, together with utility functions for parsing natural language date texts, and converting EDTF dates to related Python `date` objects.
+See http://www.loc.gov/standards/datetime/ for the current draft specification.
+## To install
+ pip install edtf
+## To use
+ >>> from edtf import parse_edtf
+ # Parse an EDTF string to an EDTFObject
+ >>> e = parse_edtf("1979-08~") # approx August 1979
+ >>> e
+ UncertainOrApproximate: '1979-08~'
+ # normalised string representation (some different EDTF strings have identical meanings)
+ >>> unicode(e)
+ u'1979-08~'
+ # Derive Python date objects
+ # lower and upper bounds that strictly adhere to the given range
+ >>> e.lower_strict()[:3], e.upper_strict()[:3]
+ ((1979, 8, 1), (1979, 8, 31))
+ # lower and upper bounds that are padded if there's indicated uncertainty
+ >>> e.lower_fuzzy()[:3], e.upper_fuzzy()[:3]
+ ((1979, 7, 1), (1979, 9, 30))
+ # Date intervals
+ >>> interval = parse_edtf("1979-08~/open")
+ >>> interval
+ Level1Interval: '1979-08~/open'
+ # Intervals have lower and upper EDTF objects.
+ >>> interval.lower, interval.upper
+ (UncertainOrApproximate: '1979-08~', UncertainOrApproximate: 'open')
+ >>> interval.lower.upper_strict()[:3]
+ (1979, 8, 31)
+ >>> interval.upper.lower_strict() # 'open' is interpreted to mean 'still happening'.
+ [Today's date]
+ # Date collections
+ >>> coll = parse_edtf('{1667,1668, 1670..1672}')
+ >>> coll
+ MultipleDates: '{1667, 1668, 1670..1672}'
+ >>> coll.objects
+ (Date: '1667', Date: '1668', Consecutives: '1670..1672')
+The object returned by `parse_edtf()` is an instance of an `edtf.parser.parser_classes.EDTFObject` subclass, depending on the type of date that was parsed. These classes are:
+ # Level 0
+ Date
+ DateAndTime
+ Interval
+ # Level 1
+ UncertainOrApproximate
+ Unspecified
+ Level1Interval
+ LongYear
+ Season
+ # Level 2
+ PartialUncertainOrApproximate
+ PartialUnspecified
+ OneOfASet
+ MultipleDates
+ MaskedPrecision
+ Level2Interval
+ ExponentialYear
+All of these implement `upper/lower_strict/fuzzy()` methods to derive Python `date` objects.
+The `*Interval` instances have `upper` and `lower` properties that are themselves `EDTFObject` instances.
+`OneOfASet` and `MultipleDates` instances have an `objects` property that is a list of all of the EDTF dates parsed in the set or list.
+## EDTF Specification Inclusions
+The library includes implementation of levels 0, 1 and 2 of the EDTF spec.
+Test coverage includes every example given in the spec table of features.
+### Level 0 ISO 8601 Features
+* Date:
+ >>> parse_edtf('1979-08') # August 1979
+ Date: '1979-08'
+* Date and Time:
+ >>> parse_edtf('2004-01-01T10:10:10+05:00')
+ DateAndTime: '2004-01-01T10:10:10+05:00'
+* Interval (start/end):
+ >>> parse_edtf('1979-08-28/1979-09-25') # From August 28 to September 25 1979
+ Interval: '1979-08-28/1979-09-25'
+### Level 1 Extensions
+* Uncertain/Approximate dates:
+ >>> parse_edtf('1979-08-28~') # Approximately August 28th 1979
+ UncertainOrApproximate: '1979-08-28~'
+* Unspecified dates:
+ >>> parse_edtf('1979-08-uu') # An unknown day in August 1979
+ Unspecified: '1979-08-uu'
+ >>> parse_edtf('1979-uu') # Some month in 1979
+ Unspecified: '1979-uu'
+* Extended intervals:
+ >>> parse_edtf('1984-06-02?/2004-08-08~')
+ Level1Interval: '1984-06-02?/2004-08-08~'
+* Years exceeding four digits:
+ >>> parse_edtf('y-12000') # 12000 years BCE
+ LongYear: 'y-12000'
+* Season:
+ >>> parse_edtf('1979-22') # Summer 1979
+ Season: '1979-22'
+### Level 2 Extensions
+* Partial uncertain/approximate:
+ >>> parse_edtf('(2011)-06-04~') # year certain, month/day approximate.
+ # Note that the result text is normalized
+ PartialUncertainOrApproximate: '2011-(06-04)~'
+* Partial unspecified:
+ >>> parse_edtf('1979-uu-28') # The 28th day of an uncertain month in 1979
+ PartialUnspecified: '1979-uu-28'
+* One of a set:
+ >>> parse_edtf("[..1760-12-03,1762]")
+ OneOfASet: '[..1760-12-03, 1762]'
+* Multiple dates:
+ >>> parse_edtf('{1667,1668, 1670..1672}')
+ MultipleDates: '{1667, 1668, 1670..1672}'
+* Masked precision:
+ >>> parse_edtf('197x') # A date in the 1970s.
+ MaskedPrecision: '197x'
+* Level 2 Extended intervals:
+ >>> parse_edtf('2004-06-(01)~/2004-06-(20)~')
+ Level2Interval: '2004-06-(01)~/2004-06-(20)~'
+* Year requiring more than 4 digits - exponential form:
+ >>> parse_edtf('y-17e7')
+ ExponentialYear: 'y-17e7'
+### Natural language representation
+The library includes a basic English natural language parser (it's not yet smart enough to work with occasions such as 'Easter', or in other languages):
+ >>> from edtf import text_to_edtf
+ >>> text_to_edtf("circa August 1979")
+ '1979-08~'
+Note that the result is a string, not an `ETDFObject`.
+The parser can parse strings such as:
+ 'January 12, 1940' => '1940-01-12'
+ '90' => '1990' #implied century
+ 'January 2008' => '2008-01'
+ 'the year 1800' => '1800'
+ '10/7/2008' => '2008-10-07' # in a full-specced date, assume US ordering
+ # uncertain/approximate
+ '1860?' => '1860?'
+ '1862 (uncertain)' => '1862?'
+ 'circa Feb 1812' => '1812-02~'
+ 'c.1860' => '1860~' #with or without .
+ 'ca1860' => '1860~'
+ 'approx 1860' => '1860~'
+ # masked precision
+ '1860s' => '186x' #186x has decade precision, 186u has year precision.
+ '1800s' => '18xx' # without uncertainty indicators, assume century
+ # masked precision + uncertainty
+ 'ca. 1860s' => '186x~'
+ 'circa 1840s' => '184x~'
+ 'ca. 1860s?' => '186x?~'
+ 'c1800s?' => '180x?~' # with uncertainty indicators, use the decade
+ # unspecified parts
+ 'January 12' => 'uuuu-01-12'
+ 'January' => 'uuuu-01'
+ '7/2008' => '2008-07'
+ #seasons
+ 'Autumn 1872' => '1872-23'
+ 'Fall 1872' => '1872-23'
+ # before/after
+ 'earlier than 1928' => 'unknown/1928'
+ 'later than 1928' => '1928/unknown'
+ 'before January 1928' => 'unknown/1928-01'
+ 'after about the 1920s' => '192x~/unknown'
+ # unspecified
+ 'year in the 1860s' => '186u' #186x has decade precision, 186u has year precision.
+ ('year in the 1800s', '18xu')
+ 'month in 1872' => '1872-uu'
+ 'day in January 1872' => '1872-01-uu'
+ 'day in 1872' => '1872-uu-uu'
+ #centuries
+ '1st century' => '00xx'
+ '10c' => '09xx'
+ '19th century?' => '18xx?'
+ # just showing off now...
+ 'a day in about Spring 1849?' => '1849-21-uu?~'
+ # simple ranges, which aren't as accurate as they could be. The parser is
+ limited to only picking the first year range it finds.
+ '1851-1852' => '1851/1852'
+ '1851-1852; printed 1853-1854' => '1851/1852'
+ '1851-52' => '1851/1852'
+ '1856-ca. 1865' => '1856/1865~'
+ '1860s-1870s' => '186x/187x'
+ '1920s -early 1930s' => '192x/193x'
+ '1938, printed 1940s-1950s' => '1938'
+Generating natural text from an EDTF representation is a future goal.
+### What assumptions does the natural text parser make when interpreting an ambiguous date?
+* "1800s" is ambiguously a century or decade. If the given date is either uncertain or approximate, the decade interpretation is used. If the date is certain and precise, the century interpretation is used.
+* If the century isn't specified (`EDTF(natural_text="the '70s")`), we imply the century to be "19" if the year is greater than the current year, otherwise we imply the century to be the current century.
+* US-ordered dates (mm/dd/yyyy) are assumed by default in natural language. To change this, set `DAY_FIRST` to True in settings.
+* If a natural language groups dates with a '/', it's interpreted as "or" rather than "and". The resulting EDTF text is a list bracketed by `[]` ("one of these dates") rather than `{}` (all of these dates).
+## Converting to and from Python dates
+Since EDTF dates are often regions, and often imprecise, we need to use a few different Python dates, depending on the circumstance. Generally, Python dates are used for sorting and filtering, and are not displayed directly to users.
+### `struct_time` date representation
+Because Python's `datetime` module does not support dates out side the range 1 AD to 9999 AD we return dates as `time.struct_time` objects by default instead of the `datetime.date` or `datetime.datetime` objects you might expect.
+The `struct_time` representation is more difficult to work with, but can be sorted as-is which is the primary use-case, and can be converted relatively easily to `date` or `datetime` objects (provided the year is within 1 to 9999 AD) or to date objects in more flexible libraries like [astropy.time](http://docs.astropy.org/en/stable/time/index.html) for years outside these bounds.
+If you are sure you are working with dates within the range supported by Python's `datetime` module, you can get these more convenient objects using the `edtf.struct_time_to_date` and `edtf.struct_time_to_datetime` functions.
+NOTE: This library previously did return `date` and `datetime` objects from methods by default before we switched to `struct_time`. See ticket https://github.com/ixc/python-edtf/issues/26.
+### `lower_strict` and `upper_strict`
+These dates indicate the earliest and latest dates that are __strictly__ in the date range, ignoring uncertainty or approximation. One way to think about this is 'if you had to pick a single date to sort by, what would it be?'.
+In an ascending sort (most recent last), sort by `lower_strict` to get a natural sort order. In a descending sort (most recent first), sort by `upper_strict`:
+ >>> e = parse_edtf('1912-04~')
+ >>> e.lower_strict() # Returns struct_time
+ >>> time.struct_time(tm_year=1912, tm_mon=4, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=0, tm_yday=0, tm_isdst=-1)
+ >>> e.lower_strict()[:3] # Show only interesting parts of struct_time
+ (1912, 4, 01)
+ >>> from edtf import struct_time_to_date
+ >>> struct_time_to_date(e.lower_strict()) # Convert to date
+ datetime.date(1912, 4, 01)
+ >>> e.upper_strict()[:3]
+ (1912, 4, 30)
+ >>> struct_time_to_date(e.upper_strict())
+ datetime.date(1912, 4, 30)
+
+%package help
+Summary: Development documents and examples for edtf
+Provides: python3-edtf-doc
+%description help
+An implementation of EDTF format in Python, together with utility functions for parsing natural language date texts, and converting EDTF dates to related Python `date` objects.
+See http://www.loc.gov/standards/datetime/ for the current draft specification.
+## To install
+ pip install edtf
+## To use
+ >>> from edtf import parse_edtf
+ # Parse an EDTF string to an EDTFObject
+ >>> e = parse_edtf("1979-08~") # approx August 1979
+ >>> e
+ UncertainOrApproximate: '1979-08~'
+ # normalised string representation (some different EDTF strings have identical meanings)
+ >>> unicode(e)
+ u'1979-08~'
+ # Derive Python date objects
+ # lower and upper bounds that strictly adhere to the given range
+ >>> e.lower_strict()[:3], e.upper_strict()[:3]
+ ((1979, 8, 1), (1979, 8, 31))
+ # lower and upper bounds that are padded if there's indicated uncertainty
+ >>> e.lower_fuzzy()[:3], e.upper_fuzzy()[:3]
+ ((1979, 7, 1), (1979, 9, 30))
+ # Date intervals
+ >>> interval = parse_edtf("1979-08~/open")
+ >>> interval
+ Level1Interval: '1979-08~/open'
+ # Intervals have lower and upper EDTF objects.
+ >>> interval.lower, interval.upper
+ (UncertainOrApproximate: '1979-08~', UncertainOrApproximate: 'open')
+ >>> interval.lower.upper_strict()[:3]
+ (1979, 8, 31)
+ >>> interval.upper.lower_strict() # 'open' is interpreted to mean 'still happening'.
+ [Today's date]
+ # Date collections
+ >>> coll = parse_edtf('{1667,1668, 1670..1672}')
+ >>> coll
+ MultipleDates: '{1667, 1668, 1670..1672}'
+ >>> coll.objects
+ (Date: '1667', Date: '1668', Consecutives: '1670..1672')
+The object returned by `parse_edtf()` is an instance of an `edtf.parser.parser_classes.EDTFObject` subclass, depending on the type of date that was parsed. These classes are:
+ # Level 0
+ Date
+ DateAndTime
+ Interval
+ # Level 1
+ UncertainOrApproximate
+ Unspecified
+ Level1Interval
+ LongYear
+ Season
+ # Level 2
+ PartialUncertainOrApproximate
+ PartialUnspecified
+ OneOfASet
+ MultipleDates
+ MaskedPrecision
+ Level2Interval
+ ExponentialYear
+All of these implement `upper/lower_strict/fuzzy()` methods to derive Python `date` objects.
+The `*Interval` instances have `upper` and `lower` properties that are themselves `EDTFObject` instances.
+`OneOfASet` and `MultipleDates` instances have an `objects` property that is a list of all of the EDTF dates parsed in the set or list.
+## EDTF Specification Inclusions
+The library includes implementation of levels 0, 1 and 2 of the EDTF spec.
+Test coverage includes every example given in the spec table of features.
+### Level 0 ISO 8601 Features
+* Date:
+ >>> parse_edtf('1979-08') # August 1979
+ Date: '1979-08'
+* Date and Time:
+ >>> parse_edtf('2004-01-01T10:10:10+05:00')
+ DateAndTime: '2004-01-01T10:10:10+05:00'
+* Interval (start/end):
+ >>> parse_edtf('1979-08-28/1979-09-25') # From August 28 to September 25 1979
+ Interval: '1979-08-28/1979-09-25'
+### Level 1 Extensions
+* Uncertain/Approximate dates:
+ >>> parse_edtf('1979-08-28~') # Approximately August 28th 1979
+ UncertainOrApproximate: '1979-08-28~'
+* Unspecified dates:
+ >>> parse_edtf('1979-08-uu') # An unknown day in August 1979
+ Unspecified: '1979-08-uu'
+ >>> parse_edtf('1979-uu') # Some month in 1979
+ Unspecified: '1979-uu'
+* Extended intervals:
+ >>> parse_edtf('1984-06-02?/2004-08-08~')
+ Level1Interval: '1984-06-02?/2004-08-08~'
+* Years exceeding four digits:
+ >>> parse_edtf('y-12000') # 12000 years BCE
+ LongYear: 'y-12000'
+* Season:
+ >>> parse_edtf('1979-22') # Summer 1979
+ Season: '1979-22'
+### Level 2 Extensions
+* Partial uncertain/approximate:
+ >>> parse_edtf('(2011)-06-04~') # year certain, month/day approximate.
+ # Note that the result text is normalized
+ PartialUncertainOrApproximate: '2011-(06-04)~'
+* Partial unspecified:
+ >>> parse_edtf('1979-uu-28') # The 28th day of an uncertain month in 1979
+ PartialUnspecified: '1979-uu-28'
+* One of a set:
+ >>> parse_edtf("[..1760-12-03,1762]")
+ OneOfASet: '[..1760-12-03, 1762]'
+* Multiple dates:
+ >>> parse_edtf('{1667,1668, 1670..1672}')
+ MultipleDates: '{1667, 1668, 1670..1672}'
+* Masked precision:
+ >>> parse_edtf('197x') # A date in the 1970s.
+ MaskedPrecision: '197x'
+* Level 2 Extended intervals:
+ >>> parse_edtf('2004-06-(01)~/2004-06-(20)~')
+ Level2Interval: '2004-06-(01)~/2004-06-(20)~'
+* Year requiring more than 4 digits - exponential form:
+ >>> parse_edtf('y-17e7')
+ ExponentialYear: 'y-17e7'
+### Natural language representation
+The library includes a basic English natural language parser (it's not yet smart enough to work with occasions such as 'Easter', or in other languages):
+ >>> from edtf import text_to_edtf
+ >>> text_to_edtf("circa August 1979")
+ '1979-08~'
+Note that the result is a string, not an `ETDFObject`.
+The parser can parse strings such as:
+ 'January 12, 1940' => '1940-01-12'
+ '90' => '1990' #implied century
+ 'January 2008' => '2008-01'
+ 'the year 1800' => '1800'
+ '10/7/2008' => '2008-10-07' # in a full-specced date, assume US ordering
+ # uncertain/approximate
+ '1860?' => '1860?'
+ '1862 (uncertain)' => '1862?'
+ 'circa Feb 1812' => '1812-02~'
+ 'c.1860' => '1860~' #with or without .
+ 'ca1860' => '1860~'
+ 'approx 1860' => '1860~'
+ # masked precision
+ '1860s' => '186x' #186x has decade precision, 186u has year precision.
+ '1800s' => '18xx' # without uncertainty indicators, assume century
+ # masked precision + uncertainty
+ 'ca. 1860s' => '186x~'
+ 'circa 1840s' => '184x~'
+ 'ca. 1860s?' => '186x?~'
+ 'c1800s?' => '180x?~' # with uncertainty indicators, use the decade
+ # unspecified parts
+ 'January 12' => 'uuuu-01-12'
+ 'January' => 'uuuu-01'
+ '7/2008' => '2008-07'
+ #seasons
+ 'Autumn 1872' => '1872-23'
+ 'Fall 1872' => '1872-23'
+ # before/after
+ 'earlier than 1928' => 'unknown/1928'
+ 'later than 1928' => '1928/unknown'
+ 'before January 1928' => 'unknown/1928-01'
+ 'after about the 1920s' => '192x~/unknown'
+ # unspecified
+ 'year in the 1860s' => '186u' #186x has decade precision, 186u has year precision.
+ ('year in the 1800s', '18xu')
+ 'month in 1872' => '1872-uu'
+ 'day in January 1872' => '1872-01-uu'
+ 'day in 1872' => '1872-uu-uu'
+ #centuries
+ '1st century' => '00xx'
+ '10c' => '09xx'
+ '19th century?' => '18xx?'
+ # just showing off now...
+ 'a day in about Spring 1849?' => '1849-21-uu?~'
+ # simple ranges, which aren't as accurate as they could be. The parser is
+ limited to only picking the first year range it finds.
+ '1851-1852' => '1851/1852'
+ '1851-1852; printed 1853-1854' => '1851/1852'
+ '1851-52' => '1851/1852'
+ '1856-ca. 1865' => '1856/1865~'
+ '1860s-1870s' => '186x/187x'
+ '1920s -early 1930s' => '192x/193x'
+ '1938, printed 1940s-1950s' => '1938'
+Generating natural text from an EDTF representation is a future goal.
+### What assumptions does the natural text parser make when interpreting an ambiguous date?
+* "1800s" is ambiguously a century or decade. If the given date is either uncertain or approximate, the decade interpretation is used. If the date is certain and precise, the century interpretation is used.
+* If the century isn't specified (`EDTF(natural_text="the '70s")`), we imply the century to be "19" if the year is greater than the current year, otherwise we imply the century to be the current century.
+* US-ordered dates (mm/dd/yyyy) are assumed by default in natural language. To change this, set `DAY_FIRST` to True in settings.
+* If a natural language groups dates with a '/', it's interpreted as "or" rather than "and". The resulting EDTF text is a list bracketed by `[]` ("one of these dates") rather than `{}` (all of these dates).
+## Converting to and from Python dates
+Since EDTF dates are often regions, and often imprecise, we need to use a few different Python dates, depending on the circumstance. Generally, Python dates are used for sorting and filtering, and are not displayed directly to users.
+### `struct_time` date representation
+Because Python's `datetime` module does not support dates out side the range 1 AD to 9999 AD we return dates as `time.struct_time` objects by default instead of the `datetime.date` or `datetime.datetime` objects you might expect.
+The `struct_time` representation is more difficult to work with, but can be sorted as-is which is the primary use-case, and can be converted relatively easily to `date` or `datetime` objects (provided the year is within 1 to 9999 AD) or to date objects in more flexible libraries like [astropy.time](http://docs.astropy.org/en/stable/time/index.html) for years outside these bounds.
+If you are sure you are working with dates within the range supported by Python's `datetime` module, you can get these more convenient objects using the `edtf.struct_time_to_date` and `edtf.struct_time_to_datetime` functions.
+NOTE: This library previously did return `date` and `datetime` objects from methods by default before we switched to `struct_time`. See ticket https://github.com/ixc/python-edtf/issues/26.
+### `lower_strict` and `upper_strict`
+These dates indicate the earliest and latest dates that are __strictly__ in the date range, ignoring uncertainty or approximation. One way to think about this is 'if you had to pick a single date to sort by, what would it be?'.
+In an ascending sort (most recent last), sort by `lower_strict` to get a natural sort order. In a descending sort (most recent first), sort by `upper_strict`:
+ >>> e = parse_edtf('1912-04~')
+ >>> e.lower_strict() # Returns struct_time
+ >>> time.struct_time(tm_year=1912, tm_mon=4, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=0, tm_yday=0, tm_isdst=-1)
+ >>> e.lower_strict()[:3] # Show only interesting parts of struct_time
+ (1912, 4, 01)
+ >>> from edtf import struct_time_to_date
+ >>> struct_time_to_date(e.lower_strict()) # Convert to date
+ datetime.date(1912, 4, 01)
+ >>> e.upper_strict()[:3]
+ (1912, 4, 30)
+ >>> struct_time_to_date(e.upper_strict())
+ datetime.date(1912, 4, 30)
+
+%prep
+%autosetup -n edtf-4.0.1
+
+%build
+%py3_build
+
+%install
+%py3_install
+install -d -m755 %{buildroot}/%{_pkgdocdir}
+if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi
+if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi
+if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi
+if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi
+pushd %{buildroot}
+if [ -d usr/lib ]; then
+ find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/lib64 ]; then
+ find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/bin ]; then
+ find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/sbin ]; then
+ find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+touch doclist.lst
+if [ -d usr/share/man ]; then
+ find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst
+fi
+popd
+mv %{buildroot}/filelist.lst .
+mv %{buildroot}/doclist.lst .
+
+%files -n python3-edtf -f filelist.lst
+%dir %{python3_sitelib}/*
+
+%files help -f doclist.lst
+%{_docdir}/*
+
+%changelog
+* Fri May 05 2023 Python_Bot <Python_Bot@openeuler.org> - 4.0.1-1
+- Package Spec generated
diff --git a/sources b/sources
new file mode 100644
index 0000000..8583124
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+7d1ca11ae8eea6ca7fd4b4c7fab76b52 edtf-4.0.1.tar.gz