{"action":"created","issue":{"url":"https://api.github.com/repos/ng-bootstrap/ng-bootstrap/issues/2634","repository_url":"https://api.github.com/repos/ng-bootstrap/ng-bootstrap","labels_url":"https://api.github.com/repos/ng-bootstrap/ng-bootstrap/issues/2634/labels{/name}","comments_url":"https://api.github.com/repos/ng-bootstrap/ng-bootstrap/issues/2634/comments","events_url":"https://api.github.com/repos/ng-bootstrap/ng-bootstrap/issues/2634/events","html_url":"https://github.com/ng-bootstrap/ng-bootstrap/issues/2634","id":352626586,"node_id":"MDU6SXNzdWUzNTI2MjY1ODY=","number":2634,"title":"Stack overflow exception when implementing a custom NgbDateAdapter","user":{"login":"AbakumovAlexandr","id":6968009,"node_id":"MDQ6VXNlcjY5NjgwMDk=","avatar_url":"https://avatars0.githubusercontent.com/u/6968009?v=4","gravatar_id":"","url":"https://api.github.com/users/AbakumovAlexandr","html_url":"https://github.com/AbakumovAlexandr","followers_url":"https://api.github.com/users/AbakumovAlexandr/followers","following_url":"https://api.github.com/users/AbakumovAlexandr/following{/other_user}","gists_url":"https://api.github.com/users/AbakumovAlexandr/gists{/gist_id}","starred_url":"https://api.github.com/users/AbakumovAlexandr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AbakumovAlexandr/subscriptions","organizations_url":"https://api.github.com/users/AbakumovAlexandr/orgs","repos_url":"https://api.github.com/users/AbakumovAlexandr/repos","events_url":"https://api.github.com/users/AbakumovAlexandr/events{/privacy}","received_events_url":"https://api.github.com/users/AbakumovAlexandr/received_events","type":"User","site_admin":false},"labels":[{"id":263376143,"node_id":"MDU6TGFiZWwyNjMzNzYxNDM=","url":"https://api.github.com/repos/ng-bootstrap/ng-bootstrap/labels/component:%20datepicker","name":"component: datepicker","color":"ffffff","default":false},{"id":260883883,"node_id":"MDU6TGFiZWwyNjA4ODM4ODM=","url":"https://api.github.com/repos/ng-bootstrap/ng-bootstrap/labels/needs:%20investigation","name":"needs: investigation","color":"eb6420","default":false},{"id":260884034,"node_id":"MDU6TGFiZWwyNjA4ODQwMzQ=","url":"https://api.github.com/repos/ng-bootstrap/ng-bootstrap/labels/needs:%20plunkr%20/%20stackblitz","name":"needs: plunkr / stackblitz","color":"eb6420","default":false},{"id":260885636,"node_id":"MDU6TGFiZWwyNjA4ODU2MzY=","url":"https://api.github.com/repos/ng-bootstrap/ng-bootstrap/labels/type:%20bug","name":"type: bug","color":"fc2929","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":{"url":"https://api.github.com/repos/ng-bootstrap/ng-bootstrap/milestones/65","html_url":"https://github.com/ng-bootstrap/ng-bootstrap/milestone/65","labels_url":"https://api.github.com/repos/ng-bootstrap/ng-bootstrap/milestones/65/labels","id":3578219,"node_id":"MDk6TWlsZXN0b25lMzU3ODIxOQ==","number":65,"title":"3.2.0","description":"","creator":{"login":"maxokorokov","id":8074436,"node_id":"MDQ6VXNlcjgwNzQ0MzY=","avatar_url":"https://avatars0.githubusercontent.com/u/8074436?v=4","gravatar_id":"","url":"https://api.github.com/users/maxokorokov","html_url":"https://github.com/maxokorokov","followers_url":"https://api.github.com/users/maxokorokov/followers","following_url":"https://api.github.com/users/maxokorokov/following{/other_user}","gists_url":"https://api.github.com/users/maxokorokov/gists{/gist_id}","starred_url":"https://api.github.com/users/maxokorokov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/maxokorokov/subscriptions","organizations_url":"https://api.github.com/users/maxokorokov/orgs","repos_url":"https://api.github.com/users/maxokorokov/repos","events_url":"https://api.github.com/users/maxokorokov/events{/privacy}","received_events_url":"https://api.github.com/users/maxokorokov/received_events","type":"User","site_admin":false},"open_issues":15,"closed_issues":7,"state":"open","created_at":"2018-08-17T08:30:03Z","updated_at":"2018-08-29T18:47:26Z","due_on":null,"closed_at":null},"comments":9,"created_at":"2018-08-21T16:52:20Z","updated_at":"2018-08-30T08:08:30Z","closed_at":null,"author_association":"NONE","body":"### Bug description:\r\nThis is a custom `NgbDateAdapter` implementation:\r\n```\r\n@Injectable()\r\nexport class DateNativeAdapter extends NgbDateAdapter<Date> {\r\n    public fromModel(date: Date | null): NgbDateStruct | null {\r\n        return isDate(date) ?\r\n            { year: date.getFullYear(), month: date.getMonth() + 1, day: date.getDate() }\r\n            : null;\r\n    }\r\n\r\n    public toModel(date: NgbDateStruct | null): Date | null {\r\n        return date !== null && date.year !== null && date.month !== null\r\n            ? new Date(Date.UTC(date.year, date.month - 1, date.day))\r\n            : null;\r\n    }\r\n}\r\n```\r\nWhen used in an app:\r\n```\r\n@NgModule({\r\n  providers: [\r\n    { provide: NgbDateAdapter, useClass: DateNativeAdapter }\r\n  ]\r\n})\r\n```\r\n, it leads to an exception when selecting any day in the popup:\r\n\r\n> ERROR RangeError: Maximum call stack size exceeded\r\n\r\n### Link to minimally-working plunker that reproduces the issue:\r\n[Stackblitz](https://stackblitz.com/edit/ngb-custom-date-adapter-test)\r\n\r\n### Version of Angular, ng-bootstrap, and Bootstrap:\r\n\r\nAngular: 6.1.2\r\n\r\nng-bootstrap: 3.0.0\r\n\r\nBootstrap: 4.1.1\r\n"},"comment":{"url":"https://api.github.com/repos/ng-bootstrap/ng-bootstrap/issues/comments/417229197","html_url":"https://github.com/ng-bootstrap/ng-bootstrap/issues/2634#issuecomment-417229197","issue_url":"https://api.github.com/repos/ng-bootstrap/ng-bootstrap/issues/2634","id":417229197,"node_id":"MDEyOklzc3VlQ29tbWVudDQxNzIyOTE5Nw==","user":{"login":"divdavem","id":1152706,"node_id":"MDQ6VXNlcjExNTI3MDY=","avatar_url":"https://avatars1.githubusercontent.com/u/1152706?v=4","gravatar_id":"","url":"https://api.github.com/users/divdavem","html_url":"https://github.com/divdavem","followers_url":"https://api.github.com/users/divdavem/followers","following_url":"https://api.github.com/users/divdavem/following{/other_user}","gists_url":"https://api.github.com/users/divdavem/gists{/gist_id}","starred_url":"https://api.github.com/users/divdavem/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/divdavem/subscriptions","organizations_url":"https://api.github.com/users/divdavem/orgs","repos_url":"https://api.github.com/users/divdavem/repos","events_url":"https://api.github.com/users/divdavem/events{/privacy}","received_events_url":"https://api.github.com/users/divdavem/received_events","type":"User","site_admin":false},"created_at":"2018-08-30T08:08:30Z","updated_at":"2018-08-30T08:08:30Z","author_association":"CONTRIBUTOR","body":"All adapters should have the following basic requirement, for every valid NgbDate `date`: the following expression should return true:\r\n```js\r\ndate.equals(fromModel(toModel(date)))\r\n```\r\nIf this basic requirement is not fulfilled, the Datepicker will not behave correctly: when reading a date from the model, it will interpret it differently than when writing it in the model.\r\n\r\nIn this case, `fromModel` uses the local (non UTC) date, whereas `toModel` creates a UTC date...\r\nso in timezones where creating a date at midnight (UTC time) results in a different local date, calling `fromModel(toModel(date))` returns a different date than the initial date.\r\nSo the Datepicker will set a UTC date in the model, but when it reads it from the model, it will interpret it as a local date which will trigger the model to be set again as a different UTC date.\r\nNote that I think that re-setting the date in the model while interpreting the value from the model is probably something wrong to change (to avoid triggering an infinite loop when there is an invalid adapter such as this one).\r\n"}}
{"actor":{"display_login":"divdavem"}}