8

I am using a datepicker in a modal window in my Bootstrap application. I am using the original Datepicker from Stefan Petre. I built it where it works in a desktop and mobile using a mouse and it works fine.

Recently I had a user request to allow it to also work with a keyboard. I removed the readonly property to allow the user to enter a date in the input field. The date-format is set to 'mm/dd/yyyy'.

When I enter a date like today for example like this "12/11/13" then it will default to 1913. This isn't a huge deal as I could just train the users to use 4 digits, but I would rather just have it default to this century.

Note: This only seems to happen for the date-format with a 4 digit year. This also seems to happen in the same manner in the newer forks of Stefan's code.

Note: I am using Bootstrap 2.0.4. I am testing with Firefox.

Here is what it looks like:

enter image description here

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
Steve Zavocki
  • 1,840
  • 4
  • 21
  • 35

7 Answers7

15

In JavaScript, set the datepicker's assumeNearbyYear attribute to true, like this:

$("#dp").datepicker({
    assumeNearbyYear: true
});
Josh
  • 2,790
  • 26
  • 30
4

This happens because the Bootstrap datepicker is using JavaScript Date objects. When you create a new Date object and pass in a two digit year it will output 1900+year (see Why does Javascript evaluate a 2-digit year of 00 as 1900 instead of 2000?)

You could try to tweak the datepicker source code, but that might be too complicated.

From what I can see on http://www.eyecon.ro/bootstrap-datepicker/ there is no option to set a range for the selectable dates, but you could change the format to use two digit years.

On your screenshot I can see, that you are using the datepicker for "Arrival Date" which I assume is in the future. On the website there is an example on how to disable dates in the past.

I hope that helps.


UPDATE

I have written an event handler for your problem which should do the trick.

Javascript on http://jsfiddle.net/pCYbd/1/

$("#dp").datepicker();

$("#dp").on("keyup", function(e) {
  var date, day, month, newYear, value, year;
  value = e.target.value;
  if (value.search(/(.*)\/(.*)\/(.*)/) !== -1) {
    date = e.target.value.split("/");
    month = date[0];
    day = date[1];
    year = date[2];
    if (year === "") {
      year = "0";
    }
    if (year.length < 4) {
      newYear = String(2000 + parseInt(year));
      $(this).datepicker("setValue", "" + month + "/" + day + "/" + newYear);
      if (year === "0") {
        year = "";
      }
      return $(this).val("" + month + "/" + day + "/" + year);
    }
  }
});

CoffeeScript on http://jsfiddle.net/pCYbd/2/

$("#dp").datepicker()
$("#dp").on "keyup", (e) ->
  value = e.target.value
  if value.search(/(.*)\/(.*)\/(.*)/) != -1
    date = value.split("/")
    month = date[0]
    day = date[1]
    year = date[2]      
    year = "0" if year == ""
    if year.length < 4
      newYear = String(2000 + parseInt(year))
      $(@).datepicker("setValue", "#{month}/#{day}/#{newYear}")
      year = "" if year == "0"
      $(@).val("#{month}/#{day}/#{year}")

My JavaScript skills are not the best, but this should work.

Community
  • 1
  • 1
cantonic
  • 1,033
  • 7
  • 12
  • Thanks, I was afraid of this. It would take me a whole day to really understand what the javascript is doing, so I don't think that it is worth it. I am going to leave this open, and see if anyone else knows, and then accept it after a few days if I don't get any more answers. Thanks! – Steve Zavocki Dec 12 '13 at 03:22
  • I do know that you can exclude past values, but the datepicker still goes to the last century, even though you cannot select anything. I am going to add that, if I decide to stay with this datepicker. – Steve Zavocki Dec 12 '13 at 03:28
  • from where did you download the datepicker? There are actually two versions: the original one of from Stefan Petre on http://www.eyecon.ro/bootstrap-datepicker/ and a forked and improved version on http://bootstrap-datepicker.readthedocs.org/en/latest/ . – cantonic Dec 12 '13 at 04:11
  • I am using the original from Stefan Petre, I actually built this last June, and I am not sure there was an alternative then. Today, I considered using the newer bootstrap-datepicker but it has the same problem. I might make it so the user pushes a button to see the datepicker, currently I load it on clicking into the field. I find this more mobile friendly, but I got to find a happy medium. – Steve Zavocki Dec 12 '13 at 04:25
  • Awesome, thanks for the code. I will give it a try later today. Much appreciated! – Steve Zavocki Dec 12 '13 at 15:02
  • 1
    As a heads up, you declare your `value` variable, but then don't use it again. Once inside the loop, you go back and reference `e.target.value` once more. – krillgar Jun 13 '14 at 12:30
2

Updating bootstrap-datepicker.js as shown in this post solved it for me https://github.com/eternicode/bootstrap-datepicker/pull/1461/commits/2ea16adad27cbc4d4dfa20b924addfb480e5b036

yyyy: function(d,v){                      
   if (format.parts.indexOf('yyyy') > -1 && v < 1000) v = 2000+v; // this line ***
   return d.setUTCFullYear(v);
},
Nick W
  • 877
  • 2
  • 15
  • 30
1

I'm using bootstrap-datepicker v1.5.1 and if you look around line 1741 where it does the year mapping, you will notice this:

 yyyy: function (d, v) {
     return d.setUTCFullYear(v);
 },
 yy: function (d, v) {
     return d.setUTCFullYear(2000 + v);
 },

When you specify that the control uses a four year date "yyyy", it will only do the return d.setUTCFullYear(v);, which will get you the previous century that JavaScript gives you. When you specify that it use the two year date "yy", it will do the correct 2000+ that you need for the current century.

So if you want the correct two year date to be 2016, 2017, etc., you need to set your datepicker to use the "yy" like so:

  $('#tbPurchaseDate').datepicker({
      format: 'mm/dd/yy',
      autoclose: true,
      todayBtn: 'linked',
      todayHighlight: true,
      orientation: 'bottom auto'
  });

Or you can change the "yyyy" setting in the bootstrap-datepicker.js to match the "yy" version, but then you'd have to remember to do that every time you update the datepicker js file via nuget. It's much easier to just change your format setting.

Of course, if you want the full 4 digit year to display in the control, then you might want to try one of the elaborate fixes listed here or just set the "yyyy" to what the "yy" is in the js file.

Or just update your code to the latest version (1.6.4 right now) and "yyyy" and "yy" are the same and you use assumeNearbyYear: true as noted in another answer here.

Barry Franklin
  • 1,781
  • 1
  • 27
  • 45
0

For me, the best solution was to customize parseDate function in bootstrap-datepicker.js file directly. Inside a function, there is variable setters_map with yyyy property which I modified a bit. Here is my solution:

yyyy: function(d,v) {
    if (v.toString().length == 2 && v <= 30) {
        v = 2000 + parseInt(v);
    }
    return d.setUTCFullYear(v);
},

In my case it was needed to convert only years that are less or equals 30.

0

In the update function of bootstrap-datepicker.js I added this block of code:

var str = this.element.prop('value');
var defaulted = false;
if (str.lastIndexOf("/") >= 0 && (str.match(/\//g) || []).length == 2)
{
    var yr = str.substring(str.lastIndexOf("/") + 1);
    if (yr.length <= 2)
    defaulted = true;
}   
if (this.date.getFullYear() < 2000 && defaulted) {
    this.date.setFullYear(this.date.getFullYear() + 100);
}

right before the viewdate is set on this line:

this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0);
ShameWare
  • 193
  • 7
0

It will work 100% if you update below two line in UTCDate() of bootstrap-datepicker.js core file:

function UTCDate(){

/* Date defaulted date from 2000 if entered date year less than 4 degit*/
if(arguments!=null && arguments[0].toString().length<4) arguments[0] = 2000 + arguments[0];

     return new Date(Date.UTC.apply(Date, arguments));

}