datetimepicker icon indicating copy to clipboard operation
datetimepicker copied to clipboard

Format "m/d/Y h:i a" changes hour onBlur

Open Sparkmasterflex opened this issue 8 years ago • 29 comments

I've recently upgraded to v2.5.4 and am now using the npm package and a strange bug has popped up that I cannot find any reason for. When the user selects a time and date the plugin populates the proper time/date in the input but when they click outside that input the time changes to an hour earlier.

I've changed the format to have no space between the time and the "AM" or "PM" and instead of changing the hour it changes from "PM" to "AM", every time.

Here's the code:

$('input.select-datetime').datetimepicker({
  format: "m/d/Y h:i a",
  formatTime: 'h:i a',
  formatDate: 'm/d/Y',
  step: 15,
  style: "min-width: 310px",
  onShow: function(current, $input) {
    var arr, date, options;
    if ($input.data('year') != null) {
      options = {};
      arr = $input.data('date').split('-');
      date = (arr[0] + "/" + (arr[1] - 1)) || "12/01";
      if ($input.data('year').min != null) {
        $.extend(options, {
          minDate: "-" + (1970 - $input.data('year').min) + "/" + date
        });
      }
      if ($input.data('year').max != null) {
        $.extend(options, {
          maxDate: "+" + (1970 + $input.data('year').max) + "/" + date
        });
      }
      return this.setOptions(options);
    }
  }
});

I've tried taking out the onShow and changing the formatTime/Date. The only thing that works is taking out the format option but this uses/inserts European format which does not work for my situation.

Sparkmasterflex avatar Aug 08 '17 19:08 Sparkmasterflex

This seems like a big issue. Im having the same problem. I would like to see this solved

leather-s avatar Sep 22 '17 01:09 leather-s

set option validateOnBlur to false. .datetimepicker({ validateOnBlur: false, format:'Y-m-d h:i A', formatTime: 'g:i A' });

leather-s avatar Sep 22 '17 01:09 leather-s

@leather-s I ended up having to downgrade the package to 2.5.3 to get it to work again. I know that's probably not the answer you're looking for. It definitely wasn't the one I wanted but it works

Sparkmasterflex avatar Oct 24 '17 02:10 Sparkmasterflex

I think the issue is in the DateFormatter, not specifically this function.

I downloaded the latest dateformatter code and replaced it in jquery.datetimepicker.full.js and the issue was resolved. There's a -1 in the current part of the JS that causes the issue but removing it causes issues with the meridiam flipping when you have 12 hour time and select midday or midnight.

Update the dateformatter code and it should be resolved, it's minified at the top of the final js file, but not listed in the codebase of this functionality.

Thomo87 avatar Oct 25 '17 05:10 Thomo87

@Thomo87 do you mean this package? https://github.com/xdan/datetimepicker/blob/master/package.json#L37

Would adding this with the proper version trickle down into this package you think?

Sparkmasterflex avatar Nov 09 '17 02:11 Sparkmasterflex

@Sparkmasterflex yeah that's the one.

Thomo87 avatar Nov 09 '17 02:11 Thomo87

That appears to be the latest version of that package. I just upgraded to version 2.5.11 and I'm still getting this issue.

I was satisfied with staying at 2.5.3 but I'm now seeing this error #612 and it turns out that somebody fixed it and the PR was merged in later versions of this package.

Sparkmasterflex avatar Nov 09 '17 19:11 Sparkmasterflex

I just downloaded the latest, and the issue is still present.

I ran a compare between the minified file from php-date-formatter git and the details in the latest version of the datetimepicker, and they differ.

I've attached them for reference, but it looks like it's not pulling the latest details correctly.

I've included the full js that I've tested and is working, the latest full js that I download directly from Git about 10 minutes ago, and the php-min file that I grabbed from their Git which has been manually included in the working full.

DateTimePicker.zip

Thomo87 avatar Nov 09 '17 23:11 Thomo87

I'm also seeing this. The root of the problem appears to be that npm install is pulling the wrong version of php-date-formatter which is missing this commit:

https://github.com/kartik-v/php-date-formatter/commit/7e5fa6842446b7ba2611c205fcec9679dfe726e3

It's super confusing, because the version in node_modules/php-date-formatter is labeled as 1.3.4 (the latest version) but isn't actually. I think probably the upstream maintainer started using the 1.3.4 version number in the source right after 1.3.3 was released, and what we're getting in node_modules is an earlier git commit.

Running these commands, gets me the proper version of php-date-formatter:

npm install
rm -rf node_modules/php-date-formatter/
(cd node_modules && wget https://github.com/kartik-v/php-date-formatter/archive/v1.3.4.tar.gz && tar -xzvf v1.3.4.tar.gz && rm v1.3.4.tar.gz && mv php-date-formatter-1.3.4 php-date-formatter)

And then I can rebuild via npm run build and everything starts working fine!

I really don't know how to make npm install get the right version which would be the right fix... I'll leave that to someone more knowledgeable!

dsnopek avatar Jan 23 '18 17:01 dsnopek

Another workaround is to use Moment.JS as the formatter:

jQuery.datetimepicker.setDateFormatter({
	parseDate: function (date, format) {
		var d = moment(date, format);
		return d.isValid() ? d.toDate() : false;
	},
	formatDate: function (date, format) {
		return moment(date).format(format);
	}
});

Sarke avatar Jan 23 '18 21:01 Sarke

I haven't had any luck with any fixes or workarounds so I've actually just have my company's app locked at 2.5.3 and started building my own in React.

It's getting close but not quite ready, if anyone's interested in forking or following the project. Since the app it's going to live in isn't a React app, but includes quite a few React components it's built to allow usage w/o requiring ReactDom in your JS app

https://github.com/Sparkmasterflex/tzolkin

Sparkmasterflex avatar Jan 26 '18 20:01 Sparkmasterflex

@Thomo87 is right, the issue is in the DateFormatter. Specifically this part:

f=t(h,p.meridiem[0])?0:t(h,p.meridiem[1])?12:-1,s>=1&&12>=s&&f>-1?y.hour=s+f-1:s>=0&&23>=s&&(y.hour=s);

That snippet checks to see if am/pm is used, and if it is converts to 12 hour time (if it isn't already).

Here's the whole (broken) chunk for the hour evaluation (I added in line breaks/spaces to make it easier to read):

case"g":
case"h":
    if (c = n.indexOf("a") > -1 ? n.indexOf("a") : n.indexOf("A") > -1 ? n.indexOf("A") : -1, h = a[c], c > -1) f = t(h, p.meridiem[0]) ? 0 : t(h, p.meridiem[1]) ? 12 : -1, s >= 1 && 12 >= s && f > -1 ? y.hour = s + f - 1 : s >= 0 && 23 >= s && (y.hour = s); else {
        if (!(s >= 0 && 23 >= s)) return null;
        y.hour = s
    }
    m = !0;
    break;

I "fixed" it locally just to see if I could pin point the exact part, this is what i ended up with. It's a bit rough but it doesn't screw up the time on blur.

case"g":
case"h":
    c = -1;
    //Find out where the meridian is, if there is one.
    if ( n.indexOf('a') > -1 || n.indexOf('A') > -1 ) {
        if ( n.indexOf('a') > -1 ) {
            c = n.indexOf('a');
        }
        else {
            c = n.indexOf('A');
        }
    }

    if ( c > -1 ) {
        //h is the meridian
        h = a[c];

        //If we're using a meridian, find out the hour offset
        f = t(h, p.meridiem[0]) ? 0 : t(h, p.meridiem[1]) ? 12 : -1;

        //Return if we have garbage data for the hour
        if (!(s >= 0 && 23 >= s)) return null;

        //Set existing value for hour
        y.hour = s;

        //Adjust hour if it's necessary
        if ( f > -1 ) {
            if ( f >= 12 ) {
                y.hour -= 12;
            }
        }
    }
    
    m = !0;
    break;

I haven't tried to forcibly upgrade my php-date-formatter package yet to see if that magically makes the existing logic work, that's going to be my next step.

lriggle-strib avatar Feb 01 '18 15:02 lriggle-strib

@lriggle-strib Forcing a proper upgrade of php-date-formatter does fix it - the logic there was rewritten in https://github.com/kartik-v/php-date-formatter/commit/7e5fa6842446b7ba2611c205fcec9679dfe726e3

dsnopek avatar Feb 01 '18 16:02 dsnopek

@leather-s Many thanks! your solution worked for me. simple!

achchu93 avatar Apr 05 '18 10:04 achchu93

i left a comment previously that above solution works. but now i need to validate it on blur too. I am not using any build tool to build the JS file. so if anyone already got working one please send me, please help me fix this. my email is achchu.zats@gmail.

Thanks in advance!

achchu93 avatar Apr 05 '18 10:04 achchu93

Same issue here.

I cannot use DateTimePicker for the US due to the AM/PM bug.

Is anyone able to fix this? It seems all the information to correct it is above.

First there is the 1 hour decrement bug on blur. Also, if you have 11:00 PM entered in your input box then open the DateTimePicker it opens with 11:00 AM selected. It's as if it is just looking for the first match on the hour and ignoring the AM/PM suffix.

So, currently the control is perfect for all locales apart from the US where AM/PM is used.

PapillonUK avatar Apr 18 '18 13:04 PapillonUK

@PapillonUK hey, try @Sarke solution. best for now. perfectly working.

achchu93 avatar Apr 18 '18 13:04 achchu93

Thanks @achchu93. I was trying to avoid the extra dependency, but it may come to that if there's no resolution. I'm also going to look at downgrading back to v2.5.3 as an easier solution - but I'll have to read through the releases first to see what could break if I do that! :-)

PapillonUK avatar Apr 18 '18 13:04 PapillonUK

The silly thing is that this bug is already fixed for a long time, it's just the npm build pulling in an older version of php-date-formatter for some inexplicable reason.

I'd highly recommend my solution above which just pulls in the right versions and doesn't require any new dependencies:

https://github.com/xdan/datetimepicker/issues/596#issuecomment-359866104

dsnopek avatar Apr 18 '18 13:04 dsnopek

Thanks @dsnopek - I'm not an npm user but I'll also have a read through your post and see if I can work out how to do that. That would obviously be the most pure solution.

PapillonUK avatar Apr 18 '18 13:04 PapillonUK

@dsnopek What do you think would be the best way to request the help of someone able to fix the npm issue? I could raise it as a new issue perhaps? But, not being au fait with npm how do you think I should phrase it? The issue could be titled "npm build is pulling in an old version of php-date-formatter"

PapillonUK avatar Apr 19 '18 11:04 PapillonUK

I've created this as a new, linked issue #657 in the hope the issue may get some fresh eyes.

PapillonUK avatar Apr 19 '18 13:04 PapillonUK

I like @Sarke's solution because I didn't have to build anything, which for me was a lot more complicated that I wanted to deal with. Make sure you include the format, formatDate, and formatTime options when creating the instance, like so:

        // manually use moment
	$.datetimepicker.setDateFormatter({
		parseDate: function (date, format) {
			var d = moment(date, format);
			return d.isValid() ? d.toDate() : false;
		},
		formatDate: function (date, format) {
			return moment(date).format(format);
		}
	});

        // or you can also set it this way
	$.datetimepicker.setDateFormatter('moment');

	$('input[name="datetime"]').datetimepicker({
		format:'M/D/YYYY h:mm a',
		formatDate: 'M/D/YYYY',
		formatTime: 'h:mm a',
		step: 5
	});

redtopia avatar May 24 '18 20:05 redtopia

Here is the fix. The Class which draws is xdsoft_current.

Old Buggy Code: Line 1891

if ((options.initTime || options.defaultSelect || datetimepicker.data('changed')) && current_time.getHours() === parseInt(h, 10) && ((!isALlowTimesInit && options.step > 59) || current_time.getMinutes() === parseInt(m, 10))) {

Fixed by Adding +1 after current_time.getHours()

if ((options.initTime || options.defaultSelect || datetimepicker.data('changed')) && current_time.getHours() +1 === parseInt(h, 10) && ((!isALlowTimesInit && options.step > 59) || current_time.getMinutes() === parseInt(m, 10))) {

sprograms avatar Feb 15 '19 07:02 sprograms

I was able to fix this issue by choosing a different dateformatter, specifically moment. The plugin has this option built in:

Make sure you have included both moment.js and the datepicker script.

<script type="text/javascript">
	$.datetimepicker.setDateFormatter('moment');
	$('.datepicker').datetimepicker({
		format: 'YYYY-MM-DD h:mm A',
		formatTime: 'h:mm A',
		formatDate: 'YYYY-MM-DD',
	});
</script>

oranges13 avatar Nov 09 '20 16:11 oranges13

I can't believe it's still not fixed in the end of 2020! Is this project abandoned?!

yuriy-vasilyev avatar Nov 25 '20 09:11 yuriy-vasilyev

I can't believe it's still not fixed in the end of 2020! Is this project abandoned?!

2 days of wracking my brains over this one. with custom onChangeDateTime handlers and more.... WHAT GIVES????

obxpete avatar Apr 08 '21 20:04 obxpete

If you use moment.js everything is fine.

oranges13 avatar Apr 08 '21 21:04 oranges13

I just downloaded the latest, and the issue is still present.

I ran a compare between the minified file from php-date-formatter git and the details in the latest version of the datetimepicker, and they differ.

I've attached them for reference, but it looks like it's not pulling the latest details correctly.

I've included the full js that I've tested and is working, the latest full js that I download directly from Git about 10 minutes ago, and the php-min file that I grabbed from their Git which has been manually included in the working full.

DateTimePicker.zip

this one worked. thanks

ashraf-kabir avatar Jun 01 '21 12:06 ashraf-kabir