soulim/ember-cli-bootstrap-datepicker

Selected date is one day behind

Opened this issue · 4 comments

Hi @soulim , I think this could be probably connected with #18 but I'm using 0.5.3 and the problem persists.

I'm actually using this:

{{bootstrap-datepicker value=model.started_at placeholder="Data di avvio" class="form-control" id="projectStartedAt" autoclose=true format="dd/mm/yyyy" language="it" startView="decade" weekStart=1 todayBtn=true}}

I select a date, e.g. 06/07/2015 but model.started_at has the value "2015-07-05T22:00:00.000Z".
Also if I select the "Today" button, the selected day is yesterday.

I tried removing various options, with same results. This has the same problem:

{{bootstrap-datepicker value=model.started_at}}

ember-cli-bootstrap-datepicker sets value (at least if you are using a recent version) to a Date object (or an array of Date objects if you are using multiple option). "2015-07-05T22:00:00.000Z" seems to be the conversion of this Date object to an ISO 8601 string in UTC timezone (like toISOString method of Date does it).

bootstrap-datepicker supports setting date to midnight in locale timezone (getDate) or UTC (getUTCDate). ember-cli-bootstrap-datepicker switched to using locale timezone by replacing getUTCDate by getDate a while ago (8058147). This was due to a bug reported in #15. I think this one was much more related to using value as ISO string at that time in ember-cli-bootstrap-datepicker. This is also changed in recent ember-cli-bootstrap-datepicker version (as described above).

So when you select a day in ember-cli-bootstrap-datepicker the Date object is set to midnight in your timezone. If you convert that Date object to UTC the day might be some hours before or after that date - depending on your timezone offset.

You could reproduce this issue easily.

var date = new Date(2015, 7, 1);
date.toString(); // "Sat Aug 01 2015 00:00:00 GMT+0200 (CEST)"
date.toISOString(); // "2015-07-31T22:00:00.000Z"
date.getTimezoneOffset(); // 120

Perhaps it should be configurable if ember-cli-bootstrap-datepicker uses getDate or getUTCDate method since both use cases are reasonable.

Thanks for the answer.

The option could really be a great solution. Also something like onlyDate: <boolean> because, like in this case, it's possible that the user needs only the Date, not DateTime, so locale-related problems are out of his focus. I know that js uses DateTime, but the plugin could "hide" the time with a specific option.

Back to the problem, the conversion is implicitly made by Ember while assigning the value to the model attribute. This is really annoying because the only way I found is to convert the value and set it to the attribute, like this:

actions: {
    saveObject: function() {
      var model = this.modelFor('projects/edit');

      if(model.get('started_at')) {
        var started_at = model.get('started_at');
        model.set('started_at', new Date(started_at.getFullYear(), started_at.getMonth(), started_at.getDate()+1, 0, 0, 0));
      }

      model.save();
    }
  }

This code appears really really bad to me, but I tried various options and this seems the easier solution (also the less elegant...). Not to mention the fact that this works only for UTC+ locales, not for UTC-

Visually the conversion also has a ugly effect: when hitting save the date immediately changes to yesterday, than changes after the conversion.

I really appreciate any suggestion :)

I think this addon should stick to Bootstrap Datepicker behaviour. Bootstrap Datepicker returns a Date object (or an array of Date objects) which is just fine. There could be an option if it should use Bootstrap Datepicker method getDate or getUTCDate but should not convert the Date object to a String.

You should just use a computed property as your value for bootstrap-datepicker if the model property should be an ISO 8601 date string:

export default Ember.View.create({
  bootstrapDateObject: Ember.computed('model.dateString', {
     get: function() {
        // ECMAScript 5 interprets ISO 8601 string without time zone as UTC
        // therefore we just split it up and use it as parameters
        // these behaviour changes in ECMAScript 6
        var date = this.get('model.dateString').split('-')
        return new Date(date[0], date[1] - 1, date[2]);

        // of if you are using momentJS
        return moment(this.get('model.dateString'));
     },
     set: function(key, newDate) {
        return this.set('model.dateString', newDate.format('YYYY-mm-dd'));
     }
  })
});

Update: JavaScript Date constructor counts month beginning with 0 for January.

is this project still maintained?