Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Protected tokens consistency in format and parse functions (v3?) #2950

Closed
fturmel opened this issue Feb 4, 2022 · 6 comments
Closed

Protected tokens consistency in format and parse functions (v3?) #2950

fturmel opened this issue Feb 4, 2022 · 6 comments

Comments

@fturmel
Copy link
Member

fturmel commented Feb 4, 2022

How come the format and parse tokens Yand D are protected, but not all their lengths and variants?

I'm guessing it was put in place to help people migrate from other libraries, but the Y, YYYYY, YYYYYY are valid in moment too. DDD and DDDD behave the same in both, so it's probably not impactful for migration mistakes.

EDIT: not quite the same in terms of padding, though. Ex: Jan 3rd 2021:

token date-fns moment
DDD 003 3
DDDD 0003 003

I wouldn't rule out that this protection feature is also helping people that are simply just guessing the tokens without consulting the docs. If the output looks OK at first glance, it probably ships and creates weird bugs in many apps, especially Y.

See #2133

Just wanted to put this out there, and suggest that all variants should be protected in v3.

import { format } from "date-fns";

const now = new Date(2021, 11, 29);

const tokens = [
  "Yo",
  "Y",
  "YY",
  "YYY",
  "YYYY",
  "YYYYY",
  "YYYYYY",
  "Do",
  "D",
  "DD",
  "DDD",
  "DDDD",
  "DDDDD",
  "DDDDDD"
];

tokens.forEach((t) => {
  try {
    console.log(t, format(now, t));
  } catch (e) {
    console.log(t, "Range Error");
  }
});

// Yo 2022nd 
// Y 2022 
// YY Range Error 
// YYY 2022 
// YYYY Range Error 
// YYYYY 02022 
// YYYYYY 002022 

// Do 363rd 
// D Range Error 
// DD Range Error 
// DDD 363 
// DDDD 0363 
// DDDDD 00363 
// DDDDDD 000363 

Related:
https://date-fns.org/docs/format
https://date-fns.org/docs/parse
https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md

export function throwProtectedError(
token: string,
format: string,
input: string
): void {
if (token === 'YYYY') {
throw new RangeError(
`Use \`yyyy\` instead of \`YYYY\` (in \`${format}\`) for formatting years to the input \`${input}\`; see: https://git.io/fxCyr`
)
} else if (token === 'YY') {
throw new RangeError(
`Use \`yy\` instead of \`YY\` (in \`${format}\`) for formatting years to the input \`${input}\`; see: https://git.io/fxCyr`
)
} else if (token === 'D') {
throw new RangeError(
`Use \`d\` instead of \`D\` (in \`${format}\`) for formatting days of the month to the input \`${input}\`; see: https://git.io/fxCyr`
)
} else if (token === 'DD') {
throw new RangeError(
`Use \`dd\` instead of \`DD\` (in \`${format}\`) for formatting days of the month to the input \`${input}\`; see: https://git.io/fxCyr`
)
}
}

@Alanscut
Copy link

@pixelpax
Copy link

pixelpax commented Jan 3, 2024

I would really second this and I think it should be a priority.

While Y off-by-one-year is not a bug, in the sense that it's ISO compliant, it's 100% a usability bug in the sense that I would guess that almost no-one who is using it is actually intending to.

For example, my team used format(date, 'MMM d, Y') in a central part of our codebase which will display the date we intended ~362 days a year, and be off by a whole year for only three days around new years.

From our perspective, I think a dev either guessed or asked chat gpt for the format, it matched in ~5 unit tests, we looked at a data table full of a variety of dates and everything seemed good to go.

Yes, we should've read and memorized the documentation, but given how subtle the 'gotcha' is, it feels like something that many devs are likely to overlook.
Of course, this week ALL of the data our users were creating in our app was displayed off by a year and we had to run around with our heads on fire to figure it out.

Throwing a warning would be ideal behavior here. Something like, "HEY, Y is a niche usecase and almost definitely NOT what you want here" if the format string contains Y but not wo. I could honestly see just switching it to yyyy under the hood since "MMM d, Y" is something there's absolutely no usecase for.

/endrant thank you all for maintaining this library, it's truly the best-- just thought I'd share my experience around a rock that got caught in my shoe ;)

@kossnocorp
Copy link
Member

It was designed to have all tokens throw an error. I can't tell when the bug was introduced, but I can't bring the exceptions now and mess up people's code.

The solution is to add a warning to the console and hope people see it.

@kossnocorp
Copy link
Member

It was designed to have all tokens throw an error

For some reason, we made a decision to hand-pick tokens. In hindsight, it was a bad idea, but now I can do nothing.

I added warnings on such tokens of any length. I hope it will help.

Closed by a576d6e, coming in the next release

@kossnocorp
Copy link
Member

Shipped with date-fns@3.1.0

@fturmel
Copy link
Member Author

fturmel commented Jan 5, 2024

Shipped with date-fns@3.1.0

@kossnocorp Great! Looks like you forgot to handle the Do and Yo tokens in your implementation though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Shipped
Development

No branches or pull requests

4 participants