Coder Social home page Coder Social logo

inukshuk / edtf.js Goto Github PK

View Code? Open in Web Editor NEW
63.0 9.0 12.0 579 KB

Extended Date Time Format (ISO 8601-2 / EDTF) Parser for JavaScript

License: BSD 2-Clause "Simplified" License

JavaScript 93.62% Nearley 6.38%
edtf iso8601 date time javascript parser earley

edtf.js's Introduction

EDTF.js

Build Status codecov NPM version

An Extended Date Time Format (EDTF) / ISO 8601-2 parser and toolkit for date/time hackers and enthusiasts.

Compatibility

EDTF / ISO 8601-2

EDTF.js fully implements EDTF levels 0, 1, and 2 as specified by ISO 8601-2 with the following exceptions:

  1. Seasons in intervals are supported at the experimental/non-standard level 3. To enable season intervals, enable seasonIntervals in defaults or when passing constraints to the parse function.

ESM

Since version 4.0 EDTF.js uses Nodes.js native ESM module implementation. Since version 4.1 EDTF.js is published as a dual-package.

Installation

$ npm install edtf

Manual

EDTF.js exports a top-level function which takes either a string (with optional parser constraints), a parse result, a regular or any of the extended date objects and returns a new, extended date object as appropriate.

import edtf, { Date, Interval } from 'edtf'

edtf('2016-XX')          #-> returns a EDTF Date
edtf(new Date())         #-> returns a EDTF Date
edtf('2016-04~/2016-05') #-> returns a EDTF Interval

For a list of all types supported by EDTF.js see:

import * as types from 'edtf/types'
Object.keys(types)
#-> ['Date', 'Year', 'Decade', 'Century', 'Season', 'Interval', 'List', 'Set']

Each type provides at least the following properties: the date's corresponding EDTF string, its minimum and maximum numeric value, its type, as well as its date part values.

edtf('2016?').edtf         #-> '2016?'

edtf('2016-02').min        #-> 1454284800000, i.e. 2016-02-01T00:00:00Z
edtf('2016-02').max        #-> 1456790399999, i.e. 2016-02-29T23:59:59Z

edtf('2016-02-2X').min     #-> 1455926400000, i.e. 2016-02-20T00:00:00Z
edtf('2016-02-2X').max     #-> 1456790399999, i.e. 2016-02-29T23:59:59Z

edtf('[..2016,2017]').min  #-> -Infinity
edtf('[..2016,2017]').max  #-> 1514764799999, i.e. 2017-12-31T23:59:59Z

edtf('2016-34').min        #-> 1459468800000, i.e. 2016-04-01T00:00:00Z
edtf('2016-34').max        #-> 1467331199999, i.e. 2016-06-30T23:59:59Z

edtf('2016?-02').values    #-> [2016, 1]
edtf('2016-05').values     #-> [2016, 4]

A date's min value is also used as its primitive value for numeric coercion. Because this is the case for all EDTF.js classes, comparison semantics tend to align well with common-sense expectations -- but be careful, as always, when type coercion is at play.

Unspecified, uncertain, and approximate dates

EDTF.js keeps track of qualified dates using bitmasks. If you are interested in binary yes or no, you can always convert a bitmask's value to boolean. For more fine-grained information, the Bitmask class provides a convenient interface for accessing these states:

 edtf('2016-05?').uncertain.value        #-> 63 / yes
 edtf('2016-05?').approximate.value      #-> 0  / no

 edtf('2016-05?').uncertain.is('year')   #-> 15 / yes
 edtf('2016-05?').uncertain.is('month')  #-> 48 / yes
 edtf('2016-05?').uncertain.is('day')    #-> 0  / no

 edtf('2016-?05').uncertain.is('year')   #-> 0  / no
 edtf('2016-?05').uncertain.is('month')  #-> 48 / yes

 edtf('201X-XX').unspecified.value       #-> 56 / yes
 edtf('201X-XX').unspecified.is('year')  #-> 8  / yes
 edtf('201X-XX').unspecified.is('month') #-> 48 / yes
 edtf('201X-XX').unspecified.is('day')   #-> 0  / no

Instead of year, month, and day, you can also query a string-based representation of the bitmask:

 edtf('201X-XX').unspecified.test('XXYYMMDD') #-> 0  / no
 edtf('201X-XX').unspecified.test('YYYXMMDD') #-> 8  / yes

When printing qualified dates, EDTF.js will try to find an optimal rendtition of qualification symbols. For that reason, you can use EDTF.js to normalize EDTF strings:

 edtf('?2016-?05-31').edtf   #-> 2016-05?-31
 edtf('?2016-?05~-31').edtf  #-> 2016-05%-31

Because every extended date object has a min and max value, you can always test if one date covers another one:

 edtf('2016-06/2016-09').covers(edtf('2016-08-24')) #-> true
 edtf('2016-06/2016-09').covers(edtf('2016-05-31')) #-> false

Iterable dates offer an includes() test as well which returns true only if a given date is part of the iteration. For example:

 edtf('2016-06/2016-09').includes(edtf('2016-08-24')) #-> false

August 24, 2016 is covered by the interval '2016-06/2016-09' but is not included in it, because the interval has month precision and can be iterated as:

 [...edtf('2016-06/2016-09')]
 #-> [2016-06, 2016-07, 2016-08, 2016-09]

Enumerating dates

EDTF.js dates offer iterators to help measure the duration between two dates. These iterators are dependent on a date's precision:

 edtf('2016').next()        #-> 2017
 edtf('2016-05').next()     #-> 2016-06
 edtf('2016-02-28').next()  #-> 2016-02-29
 edtf('2017-02-28').next()  #-> 2017-03-01

Careful, if your date has no precision, next will return the next second!

The generator *between() returns all the dates, by precision, between two dates; similarly, *until() returns all dates in between and includes the first of the two dates; to generate the full range inluding both dates, use *through().

 [...edtf('2016-05').between(edtf('2016-07'))]
 #-> [2016-06]

 [...edtf('2016-05').until(edtf('2016-07'))]
 #-> [2016-05, 2016-06]

 [...edtf('2016-05').through(edtf('2016-07'))]
 #-> [2016-05, 2016-06, 2016-07]

Note, that all range generators also work in reverse order:

 [...edtf('2016-07').through(edtf('2016-05'))]
 #-> [2016-07, 2016-06, 2016-05]

 [...edtf('2016-07').until(edtf('2016-05'))]
 #-> [2016-07, 2016-06]

 [...edtf('2016-07').between(edtf('2016-05'))]
 #-> [2016-06]

Iterators

The EDTF.js classes Date, Interval, List, and Set (lists model EDTF's 'multiple dates', while sets model 'one of a set') are iterable. Dates are iterable.

 [...edtf('2015/2018')]
 #-> [2015, 2016, 2017, 2018]

Note that this also works with varying precisions:

 [...edtf('2015-10/2016')]
  #-> [2015-10, 2015-11, 2015-12, 2016-01, 2016-02, 2016]

Consecutive dates in lists and sets are expanded during an iteration:

 [...edtf('{2015,2018..2020}')]
 #-> [2015, 2018, 2019, 2020]

Parser

To use EDTF.js' date parser directly, call parse() with an input string and optional parser constraints. The parser will always return plain JavaScript objects which you can pass to edtf() for conversion to extended date object, or to your own post-processing.

import { parse } from 'edtf'
parse('2016-02')
#-> { type: 'Date', level: 0, values: [2016, 1] }

As you can see, the parser output includes the compatibility level of the date parsed; the values array contains the individual date parts in a format compatible with JavaScript's Date semantics (months are a zero-based index).

Unspecified, uncertain, or approximate dates are returned as a numeric value representing a bitmask; refer to the Bitmask class for details.

parse('2016?-~02')
#-> { type: 'Date', level: 2, values: [2016, 1], uncertain: 15, approximate: 48 }

parse('20XX-02')
#-> { type: 'Date', level: 2, values: [2000, 1], unspecified: 12 }

Note that unspecified date values will always return the least possible value, e.g., '2000' for '20XX'. Note, also, that EDTF.js will not parse impossible unspecified dates. For instance, none of the following examples can be valid dates:

parse('2016-02-3X') #-> A day in February cannot start with a 3
parse('2016-2X-XX') #-> There are only 12 months
parse('2016-XX-32') #-> No month has 32 days

Intervals, Sets, and Lists will contain their parsed constituent dates in the values array:

parse('2015/2016')
#-> { type: 'Interval', level: 0, values: [{..}, {..}] }

Tuning parser compliance

By passing level or types constraints to the parser, you can ensure EDTF.js will accept only dates supported by your application.

parse('2016?', { level: 0 }) #-> parse error
parse('2016?', { level: 1 }) #-> ok

parse('2016?-02', { level: 1 }) #-> parse error
parse('2016?-02', { level: 2 }) #-> ok

parse('2016-21', { types: ['Date'] })           #-> parse error
parse('2016-21', { types: ['Date', 'Season'] }) #-> ok

parse('2016?', { level: 0, types: ['Date'] })   #-> parse error
parse('2016?', { level: 1, types: ['Date'] })   #-> ok

Specific features can be enabled, regardless of level or types constraints.

parse('2016-21/2016-22', { level: 1 })          #-> parse error
parse('2016-21/2016-22', {
  level: 1,
  seasonIntervals: true
})                                              #-> ok

You can review or change the parser's default constraints via the defaults object.

import { defaults } from 'edtf'
defaults.level = 1

Generator

EDTF.js can generate random EDTF strings for you. Simply add randexp to your NPM dependencies and import edtf/sample to create a new iterator:

import { sample } from 'edtf/sample'
let it = sample()

it.next() #-> { value: '0097-26', done: false }
it.next() #-> { value: '0000-09-30T22:50:54-07', done: false }
...

For a finite iterator, simply pass a count:

[...sample({ count: 3 })]
#-> ['-003%', '-0070-07-31%', '[-0080-10..]']

You can also generate strings at a given compatibility level:

[...sample({ count: 3, level: 0 })]
#-> ['0305/0070-04-30', '-07', '0000/0013']

[...sample({ count: 3, level: 1 })]
#-> ['00XX', 'Y80105', '0000~']

[...sample({ count: 3, level: 2 })]
#-> ['Y1E30', '-8110S2', '{%0401}']

Note that some grammar rules at levels 1 and 2 may, potentially, generate strings at a lower level (but never higher).

Finally, at each level you can also limit the generated strings to a given type (you must specify a level for this to work):

[...sample({ count: 3, level: 2, type: 'Decade' })]
#-> ['003', '030~', '000']

Credits

The EDTF.js parser is based on the awesome nearley parser generator.

The EDTF.js sample generator uses the ingenious randexp.

License

EDTF.js is licensed under the terms of the BSD-2-Clause license.

edtf.js's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

edtf.js's Issues

Usage in closed-source commercial product

We're developing an application that is only accessible to our customers. We are in need of a EDTF implementation in javascript, and found this repository which matches our needs exactly. We've also looked at edtfy but that misses some functioanlity we need.

Our code is closed-source, which due to the AGPL3 license of this repository means that we are unable to use it.

Would it be possible to discuss some specific alternate license that allows commercial use without having to open everything under AGPL3?

JSON-schema validator

I'd like to prepare a PR for a JSON-schema validator, but it'd be convenient if the season-interval option could be a separate option to parse rather than the level 3 option before getting to it.

import into ES6 project unclear

Hey,
this edtf module is somehow differently exported than all other packages on npmjs, and I don't quite get why. it says it's written in ES6, but from what I can tell, it's really using commonjs module imports. I expected to be able to do imports like this in ES6:

import {parse} from 'edtf'

That is working will all other packages, except this one. Is there some other ways to import it in ES6?

Inconsistent behavior for iterators on unspecified dates

Using EDTF.js v2.7.0, I am getting weird results with the next() iterator when applying it on unspecified years:

> edtf('201X').next().edtf // expecting "202X"... good
"202X"
> edtf('201X').prev().edtf // expecting "200X"... wrong
"201X"
> edtf('-22XX').next().edtf // expecting "-21XX"... wrong
"23XX"
> edtf('-22XX').prev().edtf // expecting "-23XX"... wrong
"22XX"

Not sure if unspecified years are supposed to be iterable, but the fact that the first test works makes me think they are.

global is not defined

My apologies, but I cannot tell if this is a problem with the configuration of my React application or the packaging of edtf.js.

Using version 4.1.0 and 4.0.0, I get when running the application in a browser:

Uncaught ReferenceError: global is not defined
    js date.js:17

However, with 3.1.0 no error is received and edtf.js works as expected.

The webpack config is:

// Copyright 2019 Stanford University see LICENSE for license

/* eslint node/no-unpublished-require: ["off"] */
const path = require("path")
const webpack = require("webpack")
const HtmlWebpackPlugin = require("html-webpack-plugin")

module.exports = {
  entry: "./src/index.js",
  module: {
    noParse: /bad_json/,
    rules: [
      {
        test: /\.(js|jsx)$/,
        include: path.resolve(__dirname, "./src"),
        exclude: /node_modules/,
        use: ["babel-loader"],
      },
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.(scss)$/,
        use: [
          {
            // inject CSS to page
            loader: "style-loader",
          },
          {
            // translates CSS into CommonJS modules
            loader: "css-loader",
          },
          {
            // Run postcss actions
            loader: "postcss-loader",
            options: {
              // `postcssOptions` is needed for postcss 8.x;
              // if you use postcss 7.x skip the key
              postcssOptions: {
                // postcss plugins, can be exported to postcss.config.js
                plugins() {
                  return [require("autoprefixer")]
                },
              },
            },
          },
          {
            // compiles Sass to CSS
            loader: "sass-loader",
          },
        ],
      },
      {
        test: /\.(png|jpe?g|gif|svg|eot|ttf|woff|woff2)$/i,
        // More information here https://webpack.js.org/guides/asset-modules/
        type: "asset",
      },
    ],
  },
  resolve: {
    extensions: ["*", ".js", ".jsx"],
    fallback: {
      fs: false,
      stream: require.resolve("stream-browserify"),
      crypto: require.resolve("crypto-browserify"),
    },
  },
  output: {
    path: path.join(__dirname, "/dist"),
    publicPath: "/dist/",
    filename: "bundle.js",
  },
  plugins: [
    new webpack.ProvidePlugin({
      Buffer: ["buffer", "Buffer"],
      process: "process/browser",
    }),
    new HtmlWebpackPlugin({
      template: "index.html",
      filename: "index.html",
      hash: true,
    }),
    new webpack.EnvironmentPlugin({
      USE_FIXTURES: null,
      SINOPIA_API_BASE_URL: null,
      SINOPIA_GROUP: null,
      SINOPIA_ENV: null,
      SINOPIA_URI: null,
      AWS_COGNITO_DOMAIN: null,
      COGNITO_CLIENT_ID: null,
      COGNITO_USER_POOL_ID: null,
      INDEX_URL: null,
      SEARCH_HOST: null,
      EXPORT_BUCKET_URL: null,
      HONEYBADGER_API_KEY: null,
      HONEYBADGER_REVISION: null,
    }),
  ],
  devtool: "source-map",
  devServer: {
    static: "./dist",
    historyApiFallback: true,
    hot: true,
    port: 8888,
    proxy: {
      "/api/search": "http://localhost:8000",
    },
  },
}

Thanks in advance for your assistance.

Lists with continuations not parsing correctly

Description

According to the EDTF Specification, the string {..1984} should mean "The year 1984 and all earlier years" (See Example 9 under Set representation here.). Instead, it throws a parser error. Same with the trailing "on or after" .. indicator. Both work fine with square bracketed Set types.

Versions

edtf v3.0.1 on node v14.8.0

Expected Behavior

> edtf.parse('{..1984}')
{
  values: [ { type: 'Date', level: 0, values: [Array] } ],
  level: 2,
  type: 'List',
  earlier: true
}

Actual Behavior

> edtf.parse('{..1984}')
Uncaught Error: Syntax error at line 1 col 2:

1 {..1984}
   ^

Unexpected ".". Instead, I was expecting to see one of the following:
[... 2451 lines deleted ...]
for "{..1984}"
    at Parser.feed (/Users/mbk836/Workspace/meadow/priv/edtf/node_modules/nearley/lib/nearley.js:343:27)
    at Function.parse (/Users/mbk836/Workspace/meadow/priv/edtf/node_modules/edtf/src/parser.js:37:32) {
  offset: 1,
  token: { value: '.' }
}

Day not considered unspecified in month-precision Level 0 date

Hi, I’m unsure whether this is expected behaviour, but I noticed that constructing a month-precision date by omitting the day part yields a different result compared to a day-precision date when filling the day part with XX:

> const edtf = require('edtf')
> edtf.default('1963-12').unspecified.is('day')
0
> edtf.default('1963-12-XX').unspecified.is('day')
192

I would expect the method to tell me that the day is unspecified in the first case, too.
If this is working correctly, what is the intended way of determining that there is no day part?

Year > 9999?

EDTF L1 (not the WD) accepts y170000002 as a valid date, how must I pass that to edtf.js? I've tried removing the leading y but that doesn't do it.

Date.date

I'm trying to get the day-of-month value from a parsed date, but I'm getting some things I didn't expect:

edtf('2016-07-18T20:26:06+10:00').date = 19
edtf('-0876').date = 1

I sort of get the first, but I'd still prefer to have a way to get 18 out. The 2nd, I had expected undefined rather than 1.

Provide transpiled version/variant for Node < 4.6

Hey,
this is not really a bug, but likely an issue that others may run into: The nodejs version that is shipping with the latest ubuntu (4.2.6) does not seem to include harmony flags to cover all the features you are using. So one really needs to transpile in order to use your package when using it on a standard server with one of the Ubuntu LTS releases. Or do you have any other information?

unknown/open

I'm getting errors parsing these dates:

  • */2006
  • 2004-06-01/*
  • 2004-01-01/

-1XXX has incorrect min / max

var test = '-1XXX'
var d = edtf(test)

console.log(new Date(d.min))
// -001000-01-01T00:00:00.000Z  << expect -1999 ? 
console.log(new Date(d.max))
// -001000-12-31T23:59:59.999Z << correct ?

I think this is a bug.

Thanks for making this module, I'm using it to help create indigenous genealogy + history recording in New Zealand. Being able to record dates as humans have remembered them is a total gift ❤️

License acquisition

Greetings!

Thanks so much for your work on this. I would like to include your module in my production code at work to take EDTF values and get the min/max values for them to display approximate ages. As your code is APGL-3.0 licensed (and not MIT or Apache) I'm uncertain what the restrictions are. My goal is to include this in our bundle which gets minified and uglified. Do you have a process I can go through to acquire a license? Or recommendations on alternatives in the space that might solve the same problems?

Thanks,
Michael

locale load can't be bundled anymore

This snippet

const load = (locale) =>
  JSON.parse(fs.readFileSync(new URL(`../locale-data/${locale}.json`, (typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('index.cjs', document.baseURI).href)))));

can't be bundled. I can work around it by using a compile-time patch, but what is the benefit of loading this way over a require('../locale-data/en.json')?

Invalid upper bound with dates before 1970-01-01

Hi!
I notice that if i try to add an interval with an unknown start it fails it the "end" is lower than 1970. Doing "../1960" works but has another meaning.

Looking at the code it seems like there is a missing check for this.lower being null?

edtf.js/src/interval.js

Lines 93 to 94 in 36f756f

if (this.lower !== Infinity && value <= this.lower)
throw new RangeError(`invalid upper bound: ${value}`)

minimal node example not loading

I just tried the example code at the top with node.js, but getting this error.

import edtf, { Date, Interval } from 'edtf'
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at internalCompileFunction (node:internal/vm:73:18)
    at wrapSafe (node:internal/modules/cjs/loader:1176:20)
    at Module._compile (node:internal/modules/cjs/loader:1218:27)
    at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
    at Module.load (node:internal/modules/cjs/loader:1117:32)
    at Module._load (node:internal/modules/cjs/loader:958:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
    at node:internal/main/run_main_module:23:47

Node.js v18.15.0

If I add the import line to my typescript project, I get this:

npx tsc
src/reference.ts:3:38 - error TS7016: Could not find a declaration file for module 'edtf'. '/home/bruce/Code/csl-next.js/node_modules/edtf/dist/index.cjs' implicitly has an 'any' type.
  Try `npm i --save-dev @types/edtf` if it exists or add a new declaration (.d.ts) file containing `declare module 'edtf';`

3 import edtf, { Date, Interval } from 'edtf'

What am I doing wrong?

Year zero not treated as a leap year

Using v2.7.1.

Creating another issue for this, since it happens regardless of the "unspecified" value (currently scratching my head over it by the way):

> edtf('0000-02-29').edtf // expecting '0000-02-29'... wrong
'0000-03-01'
> edtf('0000-02-28').next().edtf // expecting '0000-02-29'... wrong
'0000-03-01'
> edtf('0000-03-01').prev().edtf // expecting '0000-02-29'... wrong
'0000-02-28'

AssertionError when calling edtf("{1978,1988}") in prod

it's ok when calling parse("{1978,1988}"), I get:

{
    "values": [
        {
            "type": "Date",
            "level": 0,
            "values": [
                1978
            ]
        },
        {
            "type": "Date",
            "level": 0,
            "values": [
                1988
            ]
        }
    ],
    "level": 2,
    "type": "List"
}

but next line, calling edtf("{1978,1988}"), I get this error:

{
    "name": "AssertionError",
    "actual": "n",
    "expected": "List",
    "operator": "==",
    "message": "'n' == 'List'",
    "generatedMessage": true,
    "stack": "AssertionError: 'n' == 'List'\n    at new n (https://editor.bdrc.io/static/js/2.0f6ebddd.chunk.js:2:630854)\n    at V (https://editor.bdrc.io/static/js/2.0f6ebddd.chunk.js:2:633514)\n    at https://editor.bdrc.io/static/js/main.f531b37e.chunk.js:1:13265\n    at set (https://editor.bdrc.io/static/js/2.0f6ebddd.chunk.js:2:79522)\n    at set (https://editor.bdrc.io/static/js/2.0f6ebddd.chunk.js:2:70876)\n    at ht (https://editor.bdrc.io/static/js/2.0f6ebddd.chunk.js:2:25475)\n    at At (https://editor.bdrc.io/static/js/2.0f6ebddd.chunk.js:2:26952)\n    at https://editor.bdrc.io/static/js/2.0f6ebddd.chunk.js:2:27806\n    at Object.replaceState (https://editor.bdrc.io/static/js/2.0f6ebddd.chunk.js:2:43869)\n    at Nt (https://editor.bdrc.io/static/js/2.0f6ebddd.chunk.js:2:27703)"

}

this error only occurs after build, in a react app deployed in prod
not on a dev server running locally
which makes it hard to track in minified built code...

not sure how but this could be related to some trouble I had importing the edtf library
I ended up using this line to make it work:

import edtf, { parse } from "edtf/dist/../index.js" /

because I got this error:

Attempted import error: 'parse' is not exported from 'edtf'.

when using the regular one:

import edtf, { parse } from "edtf"

Parse error on trailing zeros

Hi there,

Thanks for this great library!
I was trying to parse 2020-05-18T22:39:24.422000Z, but it throws an error because it doesn't expect the trailing zeros. However, I think this should be valid? at least for new Date() it is.

Cheers,

Miel

Max property of masked dates incorrect

As far as I understand it, the maximum possible extent of 20XX would be the last second of the year 2099. However it's parse as if it has year precision, so next() gives the year 2001, and .max gives you the year 2001 - 1 millisecond.

> new Date(edtf('20XX').max)
2000-12-31T23:59:59.999Z
> new Date(edtf('20XX').min)
2000-01-01T00:00:00.000Z

Looking at the code, I think this would need a bit of a refactor, with the introduction of a secondary notion of precision. Whereas currently it just knows "how many date parts we have provided" it would need to know which the most precise digit before any unknown ones is. So in this case, 20XX feels like it ought to be treated as a century instead of a year, whilst 201X would be a decade.

Mismatches for XXXX-X2-<29+>

(Sorry for spamming issues, I swear I'm actually trying to work on fixes ':D)

Using v2.7.1

Since X2 sets the inner date to February by default, any value for days above 28 (29 on leap years) on an X2 month will get replaced by March 1rst or February 29th:

> edtf('2019-X2-31').edtf
"2019-X3-01"
> edtf('2020-X2-31').edtf
"2020-X2-29"

Then again, we can assume this is not a big deal since if you select X2-30 and above, you obviously meant to select December... The rest basically boils down to #20

allowing uaSymbol on undefined dates

First, thanks for this very useful library!

Currently the code allows 18? to represent "19th century, uncertain", but not 18XX?, as exemplified in this sandbox. I can't really see 18XX? allowed or forbidden in part2 of the draft, but neither can I see 18? forbidden or allowed (even in the grammar at the end)... is there a reason one works and not the other?

February 29th on unspecified year

Using v2.7.1, here is another tricky corner case:

> edtf('21XX-02-29').edtf // expecting '21XX-02-29'
'21XX-03-01'

Since some unspecified year components can match leap years, the library should not move that date to March.

But then we should be careful! Because some other unspecified years such as "21X3" never match a leap year and should therefore behave accordingly.

But right now, the behavior is basically depending on whether the "chosen builtin date" is a leap year, which gives inconsistent results:

> edtf('24XX-02-29').edtf // expecting '24XX-02-29'... good
'24XX-02-29'
> edtf('21XX-02-29').edtf // expecting '21XX-02-29'... wrong
'21XX-03-01'

Would it be possible to check whether there is a matching leap year among the ones matching the year component, and set the Date element to the first occuring leap year?

Add variants to .between() and .until()

[...edtf('2016-05').between('2016-07')]
#-> [2016-06]

[...edtf('2016-05').until('2016-07')]
#-> [2016-05, 2016-06, 2016-07]

.between() and .until() return a closed/exclusive and and open/inclusive interval, respectively. Maybe it would be useful to add two methods that return a half-open interval:

#-> [2016-05, 2016-06]

#-> [2016-06, 2016-07]

Obvious possible additions in English are .from(), .since(), .through(), .till(),.unto(), .to(), .by(), unless a name is already used or reserved. As a non-native speaker, I’ll refrain from suggesting exact semantics for these.

While .between() should work no matter the temporal order of EDTFs, .until() should arguably not.

[...edtf('2016-07').between('2016-06')]
#-> [2016-06]

[...edtf('2016-07').until('2016-05')]
#-> null

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.