uNmAnNeR / imaskjs

vanilla javascript input mask
https://imask.js.org
MIT License
4.95k stars 257 forks source link

Bug with a custom pattern on Date mask #100

Closed caiotarifa closed 6 years ago

caiotarifa commented 6 years ago

The user can't type the last number when I change the pattern to d/m/Y.

new IMask(element, { mask: Date, pattern: 'd/m/Y' })

Browser: Safari 11 Demo: https://jsfiddle.net/p2Lt5j3b/1/

uNmAnNeR commented 6 years ago

@caiotarifa you have to provide your custom format and parse options. Please take a look at examples in guide. There are a lot of date formats and it's not possible to handle them all in library. So this is application side task.

caiotarifa commented 6 years ago

Yes, I read the documentation. I only want to replace the . by the / or -, the two most common separators for dates in the world.

uNmAnNeR commented 6 years ago

@caiotarifa Still It does not make sense to put it into mask library. Btw I believe that I even should not had to add default pattern with dots. I try to keep library size as small as possible and who does not care about size almost always use moment or luxon and it's very easy to provide date formatters.

TonyE73 commented 6 years ago

Hi, I am having the same problem despite adding parse and format returns '2018-10-2' in input. Always leaves the last digit off. Other than this I am very impressed with the program

mask: Date, parse: function (str) {var yearMonthDay = str.split('-'); return new Date(yearMonthDay[0], yearMonthDay[1] - 1, yearMonthDay[2]); }, pattern: "Y-m-d", dateFormat:"Y-m-d"

uNmAnNeR commented 6 years ago

@TonyE73 please also provide your format option. Please also check example in guide, it should work and very similar to your code.

TonyE73 commented 6 years ago

OK, it is sorted. I just followed your instructions

mask: Date, pattern: 'Y-m-d', format: function (date) { var day = date.getDate(); var month = date.getMonth() + 1; var year = date.getFullYear(); if (day < 10) day = "0" + day; if (month < 10) month = "0" + month; return [year, month, day].join('-'); }, parse: function (str) { var yearMonthDay = str.split('-'); return new Date(yearMonthDay[0], yearMonthDay[1] - 1, yearMonthDay[2]); }

uNmAnNeR commented 6 years ago

@TonyE73 Check it works https://jsfiddle.net/o9gaydq8/

evanjmg commented 5 years ago

@uNmAnNeR this solution is a hack and does not work like the other behaviour - please reopen and say this is a temporary workaround

jaderss commented 4 years ago

The problem still exists. I have the same problem with the date pattern right now.

la-costa commented 3 years ago

Hi,

This setting using luxon works for me.

It seems that the problem of last digit when an error occurs during the format or parse function.

import { DateTime } from "luxon";
const patternDate = 'dd/LL/yyyy';
const mask = {
    mask: Date,
    pattern: patternDate,
    format: function (date) {
      return date.toLocaleString(patternDate);
    },
    parse: function (str) {
      return DateTime.fromFormat(str, patternDate);
    },
    blocks: {
      yyyy: {
        mask: IMask.MaskedRange,
        from: 1900,
        to: 2090,
      },
      LL: {
        mask: IMask.MaskedRange,
        from: 1,
        to: 12,
      },
      dd: {
        mask: IMask.MaskedRange,
        from: 1,
        to: 31,
      },
    },
};
marcoskichel commented 3 years ago

Why is this issue closed if the problem is not fixed?

echelonka commented 3 years ago

Just got the same issue in react-native-imask but with pattern mm/dd/yyyy. Managed to fix it via date-fns:

import { IMaskTextInput } from 'react-native-imask';
import { format, parse } from 'date-fns';

const DateInput = () => {
  return (
    <IMaskTextInput
      mask={Date}
      pattern="m{/}`d{/}`Y"
      format={(date: Date): string => format(date, 'MM/dd/yyyy')}
      parse={(value: string): Date => parse(value, 'MM/dd/yyyy', new Date())}
    />
  );
};

Hope it will help someone!

greenomac commented 1 year ago

I solved it by changing the imask-6.4.3.js file, starting from line 2766 to 2784.

New code:

  MaskedDate.DEFAULTS = {
    pattern: 'd{/}`m{/}`Y',
    format: function format(date) {
      if (!date) return '';
      var day = String(date.getDate()).padStart(2, '0');
      var month = String(date.getMonth() + 1).padStart(2, '0');
      var year = date.getFullYear();
      return [day, month, year].join('/');
    },
    parse: function parse(str) {
      var _str$split = str.split('/'),
        _str$split2 = _slicedToArray(_str$split, 3),
        day = _str$split2[0],
        month = _str$split2[1],
        year = _str$split2[2];

      return new Date(year, month - 1, day);
    }
  };
fellipefreiire commented 1 year ago

keeps closing with the problem not being solved...

uNmAnNeR commented 1 year ago

@fellipefreiire i feel like the only problem here is that people are just do not want to read the docs. There is a way to extend the mask with any date/time pattern but instead of trying to figure it out people prefer to blame in the comments to make me do their work. Let me know if i am wrong and you or someone else has a real issue related to the library facilities that does not allow you to solve your problem. Otherwise i will continue to respectfully ignore these throws.

ezze commented 12 months ago

I faced the similar issue and found this thread. If I got it right, the problem is that if I provide any custom pattern for date mask I also need to specify format and parse functions corresponding to it otherwise results will be unexpected like mentioned above.

@uNmAnNeR Maybe, docs should be a little bit more specific on this. Wouldn't it better to add typings constraints disallowing to pass non-default pattern without format and parse functions and throw an error if it's been passed?

uNmAnNeR commented 11 months ago

@ezze good idea about types, will check

lets make it red ? :) image

ezze commented 11 months ago

lets make it red ? :)

@uNmAnNeR Ha-ha, some lads including me should buy vision glasses. :) Although I was pretty sure that read the docs carefully.

Just for reference: https://imask.js.org/guide.html#masked-date

jafar-alphaeon commented 6 months ago

I see where the confusion was, in the parse function you also have to realign your split date string accordingly. Typing the variables also helps, especially for date logic. Although, I used :any when passing into format

      <IMaskInput 
              mask={Date}
              pattern={'m/d/Y'}
              parse={ function (str) {
                var fullDate:string[] = str.split('/');
                  return new Date(
                    Number(fullDate[2]), // Year
                    Number(fullDate[0])-1,  // Month
                    Number(fullDate[1]),  // Day
                );
              }}
              format={(date:any)=>{
                var day:string = date.getDate().toString();
                var month:string = String(date.getMonth() + 1);
                var year = date.getFullYear();
                if (Number(day) < 10) day = "0" + day;
                if (Number(month) < 10) month = "0" + month;
               return [month, day, year].join('/')
              }}

              min={new Date(1950, 0, 1)}
              max={new Date(2020, 0, 1)}
              lazy={false}
              unmask={true}
            />
asadulloh-pro commented 6 months ago

Hi.

I prefer use dayjs for format and parse:

import dayjs from "dayjs";
import { IMask, IMaskInput } from "react-imask";

const configDate = () => ({
  d: {
    mask: IMask.MaskedRange,
    from: 1,
    to: 31,
    maxLength: 2,
  },
  m: {
    mask: IMask.MaskedRange,
    from: 1,
    to: 12,
    maxLength: 2,
  },
  Y: {
    mask: IMask.MaskedRange,
    from:  1919,
    to: 2030,
    maxLength: 4,
  },
});
const configTime = () => ({
  H: {
    mask: IMask.MaskedRange,
    from: 0,
    to: 23,
  },
  i: {
    mask: IMask.MaskedRange,
    from: 0,
    to: 59,
  },
});

const momentFormat = "YYYY-MM-DD HH:mm";

const DateTimeInput = () => {

const date = configDate( );

  const time = configTime();

  const dateBlocks = {
    ...date,
    separator: "-",
  };

  const timeBlocks = {
    ...time,
    separator: ":",
  };

return (
<IMaskInput
            mask={Date as any}
            inputRef={ref}
            lazy={false}
            pattern="Y-m-d H:i"
            autofix={true}
            blocks={{
              ...dateBlocks,
              ...timeBlocks,
            }}
            onAccept={onChange}
            value={value}
            format={(date) => dayjs(date).format(momentFormat)}
            parse={(str) => dayjs(str, momentFormat)}
            placeholder={placeholder}
          />
)

}