{"id":18728776,"url":"https://github.com/rubyonworld/edtf-ruby","last_synced_at":"2025-11-12T05:30:20.090Z","repository":{"id":174007906,"uuid":"542156166","full_name":"RubyOnWorld/edtf-ruby","owner":"RubyOnWorld","description":"😆 A variation of EDTF will part of the upcoming ISO 8601-2 standard. EDTF-Ruby does not support this new version of EDTF yet, but if you are curious, EDTF.js, an ES6 implementation is already available.","archived":false,"fork":false,"pushed_at":"2022-09-27T17:08:25.000Z","size":361,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-12-28T14:26:31.454Z","etag":null,"topics":["8601-2","edtf","iso","ruby","standard","support","upcoming"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RubyOnWorld.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-27T15:25:27.000Z","updated_at":"2024-05-31T13:51:22.000Z","dependencies_parsed_at":"2024-01-28T04:21:31.337Z","dependency_job_id":null,"html_url":"https://github.com/RubyOnWorld/edtf-ruby","commit_stats":null,"previous_names":["rubyonworld/edtf-ruby"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RubyOnWorld%2Fedtf-ruby","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RubyOnWorld%2Fedtf-ruby/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RubyOnWorld%2Fedtf-ruby/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RubyOnWorld%2Fedtf-ruby/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RubyOnWorld","download_url":"https://codeload.github.com/RubyOnWorld/edtf-ruby/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239599040,"owners_count":19665911,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["8601-2","edtf","iso","ruby","standard","support","upcoming"],"created_at":"2024-11-07T14:24:19.226Z","updated_at":"2025-11-12T05:30:19.996Z","avatar_url":"https://github.com/RubyOnWorld.png","language":"Ruby","readme":"EDTF-Ruby\n=========\n[![ci](https://github.com/inukshuk/edtf-ruby/actions/workflows/ci.yml/badge.svg)](https://github.com/inukshuk/edtf-ruby/actions/workflows/ci.yml)\n[![Coverage Status](https://coveralls.io/repos/github/inukshuk/edtf-ruby/badge.svg?branch=main)](https://coveralls.io/github/inukshuk/edtf-ruby?branch=main)\n\nEDTF-Ruby comprises a parser and an API implementation of the [Extended\nDate/Time Format standard](http://www.loc.gov/standards/datetime/).\n\n\nCompatibility\n-------------\nEDTF-Ruby parser implements all levels and features of the EDTF specification\n(version September 16, 2011). With the following known caveats:\n\n* In the latest revision of the EDTF specification alternative versions of\n  partial uncertain/approximate strings were introduced (with or without\n  nested parentheses); EDTF-Ruby currently uses the version that tries to\n  reduce parentheses for printing as we find that one easier to read; the\n  parser accepts all valid dates using this approach, plus some dates using\n  nested expressions (the parser will not accept some of the more complex\n  examples, though).\n\nEDTF-Ruby has been confirmed to work on the following Ruby implementations:\n2.1, 2.0, 1.9.3, Rubinius, and JRuby (1.8.7 and 1.9.2 were originally supported\nbut we are not testing compatibility actively anymore). Active Support's date\nextensions are currently listed as a dependency, because of many functional\noverlaps (version 3.x and 4.x are supported).\n\n### ISO 8601-2\n\nA variation of EDTF will part of the upcoming ISO 8601-2 standard. EDTF-Ruby\ndoes not support this new version of EDTF yet, but if you are curious,\n[EDTF.js](https://github.com/inukshuk/edtf.js), an ES6 implementation is already available.\n\nQuickstart\n----------\nEDTF Ruby is implemented as an extension to the regular Ruby date/time classes.\nYou can parse EDTF strings either using `Date.edtf` or `EDTF.parse`\n(both methods come with an alternative bang! version, that will raise an error\nif the string cannot be parsed instead of silently returning nil); if\ngiven a valid EDTF string the return value will either be an (extended) `Date`,\n`EDTF::Interval`, `EDTF::Set`, `EDTF::Epoch` or `EDTF::Season` instance.\n\nGiven any of these instances, you can print the corresponding EDTF string\nusing the `#edtf` method.\n\n### Dates\n\nMost of the EDTF features deal with dates; EDTF-Ruby implements these by\nextending Active Support's version of the regular Ruby Date class. The library\nintends to be transparent to Ruby's regular API, i.e., every Date instance\nshould act as you would normally expect but provides additional functionality.\n\nMost, notably, EDTF dates come in day, month, or year precision. This is a\nsubtle difference that determines how many other methods work. For instance:\n\n    \u003e Date.today.precision\n    =\u003e :day\n    \u003e Date.today\n    =\u003e Thu, 10 Nov 2011\n    \u003e Date.today.succ\n    =\u003e Fri, 11 Nov 2011\n    \u003e Date.today.month_precision!.succ\n    =\u003e Sat, 10 Dec 2011\n\nAs you can see, dates have day precision by default; after setting the date's\nprecision to month, however, the natural successor is not the next day, but\na day a month from now. Always keep precision in mind when comparing dates,\ntoo:\n\n    \u003e Date.new(1966).year_precision! == Date.new(1966)\n    =\u003e false\n\nThe year 1966 is not equal to the January 1st, 1966. You can set a date's\nprecision directly, or else use the dedicated bang! methods:\n\n    \u003e d = Date.new(1993)\n    \u003e d.day_precision?   # -\u003e true\n    \u003e d.edtf\n    =\u003e \"1993-01-01\"\n    \u003e d.month_precision!\n    \u003e d.edtf\n    =\u003e \"1993-01\"\n    \u003e d.year_precision!\n    \u003e d.edtf\n    =\u003e \"1993\"\n    \u003e d.day_precision?    # -\u003e false\n    \u003e d.year_precision?   # -\u003e true\n\nIn the examples above, you also see that the `#edtf` method will print a\ndifferent string depending on the date's current precision.\n\nThe second important extension is that dates can be uncertain and or\napproximate. The distinction between the two may seem somewhat contrived,\nbut we have come to understand it as follows:\n\nAssume you take a history exam and have to answer one of those dreaded\nquestions that require you to say exactly in what year a certain event\nhappened; you studied hard, but all of a sudden you are *uncertain*: was\nthat the year 1683 or was it 1638? This is what uncertainty is in the\nparlance of EDTF: in fact, you would write it just like that \"1638?\".\n\nApproximate dates are similar but slightly different. Lets say you want\nto tell a story about something that happened to you one winter; you\ndon't recall the exact date, but you know it must have been sometime\nbetween Christmas and New Year's. Come to think of it, you don't\nremember the year either, but you must have been around ten years old.\nUsing EDTF, you could write something like \"1993~-12-(27)~\": this\nindicates that both the year and the day are approximations: perhaps\nthe day is not the 27th but it is somewhere close.\n\nThis is the main difference between uncertain and approximate in\nEDTF (in our opinion at least): approximate always means close to the\nactual number, whilst uncertain could be something completely different\n(just as there is a large temporal distance between 1638 and 1683).\n\nHere are a few examples of how you can access the uncertain/approximate\nstate of dates in Ruby:\n\n    \u003e d = Date.edtf('1984?')\n    \u003e d.uncertain?\n    =\u003e true\n    \u003e d.uncertain? :year\n    =\u003e true\n    \u003e d.uncertain? :day\n    =\u003e false\n    \u003e d.approximate!\n    \u003e d.edtf\n    =\u003e \"1984?~\"\n    \u003e d.month_precision!\n    \u003e d.approximate! :month\n    \u003e d.edtf\n    =\u003e \"1984?-01~\"\n\nAs you can see above, you can use the bang! methods to set individual date\nparts.\n\nIn addition, EDTF supports *unspecified* date parts. EDTF-Ruby provides parsing\nfor both the draft and finalized EDTF specifications, with output meeting the\nrequirements of the final specification:\n\n    \u003e d = Date.edtf('1999-03-XX')\n    \u003e d.unspecified?\n    =\u003e true\n    \u003e d.unspecified? :year\n    =\u003e false\n    \u003e d.unspecified? :day\n    =\u003e true\n    \u003e d.unspecified! :month\n    \u003e d.edtf\n    =\u003e \"1999-XX-XX\"\n\n    \u003e draft_d = Date.edtf('1999-03-uu')\n    \u003e draft_d.edtf\n    =\u003e \"1999-03-XX\"\n\nAll three, uncertain, approximate, and unspecified attributes do not factor\ninto date calculations (like comparisons or successors etc.).\n\nEDTF long or scientific years are mapped to normal date instances.\n\n    \u003e Date.edtf('y-17e7').year\n    =\u003e -170000000\n\nWhen printing date strings, EDTF-Ruby will try to avoid nested parentheses:\n\n    \u003e Date.edtf(\"(1999-(02)~-23)?\").edtf\n    =\u003e \"1999?-(02)?~-23?\"\n\n\n### Intervals\n\nIf you parse an EDTF interval, the EDTF-Ruby parser will return an instance\nof `EDTF::Interval`; intervals mimic regular Ruby ranges, but offer additional\nfunctionality.\n\n    \u003e d = Date.edtf('1984-06?/2004-08?')\n    \u003e d.from.uncertain?\n    =\u003e true\n    \u003e d.include?(Date.new(1987,04,13))\n    =\u003e false\n\nThe day is not included because interval has month precision. However:\n\n    \u003e d.cover?(Date.new(1987,04,13))\n    =\u003e true\n\nThe day is still covered by the interval. In general, optimized in the\nsame way that Ruby optimizes numeric ranges. Additionally, precision\nplays into the way intervals are enumerated:\n\n    \u003e d.length\n    =\u003e 243\n\nThere are 243 months between 1984-06-01 and 2004-08-31.\n\n    \u003e d.step(36).map(\u0026:year)\n    =\u003e [1984, 1987, 1990, 1993, 1996, 1999, 2002]\n\nHere we iterate through the interval in 36-month steps and map each date to\nthe year.\n\n    \u003e Date.edtf('1582-10-01/1582-10-31').length\n    =\u003e 21\n\nThis interval has day precision, so 21 is the number of days in October 1582,\nwhich was cut short because of the Gregorian calendar reform.\n\nIntervals can be open or have unknown start or end dates.\n\n    \u003e Date.edtf('2004/open').open?\n    =\u003e true\n    \u003e Date.edtf('2004/open').cover?(Date.today)\n    =\u003e true\n\n### Sets\n\nEDTF supports two kind of sets: choice lists (meaning one date out of a list),\nor inclusive lists. In EDTF-Ruby, these are covered by the class `EDTF::Set`\nand the `choice` attribute.\n\n    \u003e s = Date.edtf('{1667,1668, 1670..1672}')\n    \u003e s.choice?\n    =\u003e false\n    \u003e s.choice!\n    \u003e s.edtf\n    =\u003e \"[1667,1668,1670..1672]\"\n\nAs you can see above, EDTF-Ruby remembers which parts of the set were\nspecified as a range; ranges are however enumerated for membership tests:\n\n    \u003e s.include?(Date.edtf('1669'))\n    =\u003e false\n    \u003e s.include?(Date.edtf('1671'))\n    =\u003e true\n\nEven though we're still aware that the year 1671 was is not directly an\nelement of the set:\n\n    \u003e s.length\n    =\u003e 3\n\nWhen in doubt, you can always map the set to an array. This will also\nenumerate all ranges:\n\n    \u003e s.map(\u0026:year)\n    =\u003e [1667,1668,1670,1671,1672] # when enumerated there are 5 elements\n\nEDTF sets also feature an `#earlier?` and `#later?` attribute:\n\n    \u003e s.earlier?\n    =\u003e false\n    \u003e s.earlier!\n    \u003e s.edtf\n    =\u003e \"[..1667,1668,1670..1672]\"\n\n\n### Decades and Centuries\n\nThe EDTF specification supports so called masked precision strings to define\ndecades or centuries. EDTF-Ruby maps these to dedicated intervals which\nalways cover 10 or 100 years, respectively.\n\n    \u003e d = Date.edtf!('196x')\n    =\u003e 196x\n    \u003e d.class\n    =\u003e EDTF::Decade\n    \u003e d.class\n    =\u003e EDTF::Decade\n    \u003e d.min\n    =\u003e Fri, 01 Jan 1960\n    \u003e d.max\n    =\u003e Wed, 31 Dec 1969\n    \u003e d.map(\u0026:year)\n    =\u003e [1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969]\n\n### Seasons\n\nFinally, EDTF covers seasons. Again, EDTF-Ruby provides a dedicated class\nfor this. Note that EDTF does not make any assumption about the specifics\n(which months etc.) of the season and you don't have to either; however\nEDTF-Ruby defines method aliases which allow you to access the seasons\nby the names spring, summer, autumn (or fall), and winter, respectively.\nYou can also use the more neutral taxonomy of first, second, third,\nfourth.\n\n    \u003e w = Date.edtf!('2003-24')\n    \u003e w.winter?\n    =\u003e true\n    \u003e s = w.succ\n    \u003e s.spring?\n    =\u003e true\n    \u003e s.year\n    =\u003e 2004\n    \u003e s.min\n    =\u003e Mon, 01 Mar 2004\n    \u003e s.max\n    =\u003e Mon, 31 May 2004\n    \u003e s.to_a.length\n    =\u003e 92\n    005:0\u003e w.to_a.length\n    =\u003e 91\n\nAs you can see, spring 2004 lasted one day longer than winter 2003 (note\nthat spring and winter here do not relate to the astronomical seasons\nbut strictly to three month periods).\n\nOf course you can print seasons to EDTF strings, too. Finally, seasons can\nbe uncertain/approximate.\n\n    \u003e s.edtf\n    =\u003e \"2004-21\"\n    \u003e s.approximate!.edtf\n    =\u003e \"2004-21\"\n\n\nFor additional features, please take a look at the documentation or the\nextensive list of rspec examples.\n\n\nContributing\n------------\nThe EDTF-Ruby source code is [hosted on GitHub](https://github.com/inukshuk/edtf-ruby).\nYou can check out a copy of the latest code using Git:\n\n    $ git clone https://github.com/inukshuk/edtf-ruby.git\n\nTo get started, generate the parser and run all tests:\n\n    $ cd edtf-ruby\n    $ bundle install\n    $ bundle exec rspec spec\n    $ bundle exec cucumber\n\nIf you've found a bug or have a question, please open an issue on the\n[EDTF-Ruby issue tracker](https://github.com/inukshuk/edtf-ruby). Or, for extra\ncredit, clone the EDTF-Ruby repository, write a failing example, fix the bug\nand submit a pull request.\n\n\nCredits\n-------\nEDTF-Ruby was written by Sylvester Keil and Ilja Srna.\n\nPublished under the terms and conditions of the FreeBSD License; see LICENSE\nfor details.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frubyonworld%2Fedtf-ruby","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frubyonworld%2Fedtf-ruby","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frubyonworld%2Fedtf-ruby/lists"}