Repository: jhipster/generator-jhipster
Pull request #7142 (2018-02-20 08:27:57)

WIP: 6984 - date handling with moment
This PR handle date using momentjs, as stated in the [ticket](https://github.com/jhipster/generator-jhipster/issues/6984) 

Are you ok with the approach used?
I plan to move the *moment*pipes to ng-jhipster and remove dateutil in a short term

- Please make sure the below checklist is followed for Pull Requests.

- [ ] [Travis tests](https://travis-ci.org/jhipster/generator-jhipster/pull_requests) are green
- [ ] Tests are added where necessary
- [x ] Documentation is added/updated where necessary
- [x ] Coding Rules & Commit Guidelines as per our [CONTRIBUTING.md document](https://github.com/jhipster/generator-jhipster/blob/master/CONTRIBUTING.md) are followed



Patch:
diff --git a/generators/client/files-angular.js b/generators/client/files-angular.js
index a9e28e121f..e0f06c218a 100644
--- a/generators/client/files-angular.js
+++ b/generators/client/files-angular.js
@@ -415,12 +415,15 @@ const files = {
                 'shared/shared-libs.module.ts',
                 'shared/shared-common.module.ts',
                 'shared/constants/error.constants.ts',
+                'shared/constants/input.constants.ts',
                 'shared/constants/pagination.constants.ts',
                 // models
                 'shared/util/request-util.ts',
                 // alert service code
                 'shared/alert/alert.component.ts',
-                'shared/alert/alert-error.component.ts'
+                'shared/alert/alert-error.component.ts',
+                // dates
+                'shared/util/datepicker-adapter.ts'
             ]
         },
         {
diff --git a/generators/client/templates/angular/package.json.ejs b/generators/client/templates/angular/package.json.ejs
index 9aefe19c1c..d8ab202f2d 100644
--- a/generators/client/templates/angular/package.json.ejs
+++ b/generators/client/templates/angular/package.json.ejs
@@ -34,10 +34,12 @@
     "@angular/platform-browser-dynamic": "5.2.0",
     "@angular/router": "5.2.0",
     "@ng-bootstrap/ng-bootstrap": "1.0.0",
+    "angular2-moment": "1.8.0",
     "bootstrap": "4.0.0",
     "core-js": "2.4.1",
     "font-awesome": "4.7.0",
     "jquery": "3.2.1",
+    "moment": "2.20.1",
     "ng-jhipster": "0.4.1",
     "ngx-cookie": "2.0.1",
     "ngx-infinite-scroll": "0.5.1",
diff --git a/generators/client/templates/angular/src/main/webapp/app/shared/constants/input.constants.ts.ejs b/generators/client/templates/angular/src/main/webapp/app/shared/constants/input.constants.ts.ejs
new file mode 100644
index 0000000000..c6ed7c532b
--- /dev/null
+++ b/generators/client/templates/angular/src/main/webapp/app/shared/constants/input.constants.ts.ejs
@@ -0,0 +1,19 @@
+<%#
+ Copyright 2013-2018 the original author or authors from the JHipster project.
+
+ This file is part of the JHipster project, see http://www.jhipster.tech/
+ for more information.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-%>
+export const DATE_TIME_FORMAT = 'YYYY-MM-DDThh:mm';
diff --git a/generators/client/templates/angular/src/main/webapp/app/shared/index.ts.ejs b/generators/client/templates/angular/src/main/webapp/app/shared/index.ts.ejs
index 95c255a186..25cc64f21f 100644
--- a/generators/client/templates/angular/src/main/webapp/app/shared/index.ts.ejs
+++ b/generators/client/templates/angular/src/main/webapp/app/shared/index.ts.ejs
@@ -1,13 +1,11 @@
 <%#
  Copyright 2013-2018 the original author or authors from the JHipster project.
-
  This file is part of the JHipster project, see http://www.jhipster.tech/
  for more information.
 
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
-
       http://www.apache.org/licenses/LICENSE-2.0
 
  Unless required by applicable law or agreed to in writing, software
@@ -18,6 +16,7 @@
 -%>
 export * from './constants/error.constants';
 export * from './constants/pagination.constants';
+export * from './constants/input.constants';
 export * from './alert/alert.component';
 export * from './alert/alert-error.component';
 export * from './auth/has-any-authority.directive';
@@ -34,3 +33,4 @@ export * from './social/social.component';
 export * from './shared-libs.module';
 export * from './shared-common.module';
 export * from './shared.module';
+export * from './util/datepicker-adapter';
diff --git a/generators/client/templates/angular/src/main/webapp/app/shared/shared-libs.module.ts.ejs b/generators/client/templates/angular/src/main/webapp/app/shared/shared-libs.module.ts.ejs
index 3f1d9c0803..fb771fba46 100644
--- a/generators/client/templates/angular/src/main/webapp/app/shared/shared-libs.module.ts.ejs
+++ b/generators/client/templates/angular/src/main/webapp/app/shared/shared-libs.module.ts.ejs
@@ -24,6 +24,7 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
 import { NgJhipsterModule } from 'ng-jhipster';
 import { InfiniteScrollModule } from 'ngx-infinite-scroll';
 import { CookieModule } from 'ngx-cookie';
+import { MomentModule } from 'angular2-moment';
 
 @NgModule({
     imports: [
@@ -37,6 +38,7 @@ import { CookieModule } from 'ngx-cookie';
             <%_ } _%>
         }),
         InfiniteScrollModule,
+        MomentModule,
         CookieModule.forRoot()
     ],
     exports: [
diff --git a/generators/client/templates/angular/src/main/webapp/app/shared/shared.module.ts.ejs b/generators/client/templates/angular/src/main/webapp/app/shared/shared.module.ts.ejs
index 9259287d91..0ba2f75078 100644
--- a/generators/client/templates/angular/src/main/webapp/app/shared/shared.module.ts.ejs
+++ b/generators/client/templates/angular/src/main/webapp/app/shared/shared.module.ts.ejs
@@ -17,7 +17,10 @@
  limitations under the License.
 -%>
 import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
+import { NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap';
+import { DateFormatPipe, ParsePipe } from 'angular2-moment';
 
+import { NgbDateMomentAdapter } from './util/datepicker-adapter';
 import {
     <%=angularXAppName%>SharedLibsModule,
     <%=angularXAppName%>SharedCommonModule,
@@ -44,7 +47,9 @@ import {
         <%_ } _%>
         HasAnyAuthorityDirective
     ],
-    providers: [],
+    providers: [ ParsePipe, DateFormatPipe,
+        { provide: NgbDateAdapter, useClass: NgbDateMomentAdapter},
+    ],
     <%_ if (authenticationType !== 'oauth2') { _%>
     entryComponents: [<%=jhiPrefixCapitalized%>LoginModalComponent],
     <%_ } _%>
diff --git a/generators/client/templates/angular/src/main/webapp/app/shared/util/datepicker-adapter.ts.ejs b/generators/client/templates/angular/src/main/webapp/app/shared/util/datepicker-adapter.ts.ejs
new file mode 100644
index 0000000000..7fe3c53fb1
--- /dev/null
+++ b/generators/client/templates/angular/src/main/webapp/app/shared/util/datepicker-adapter.ts.ejs
@@ -0,0 +1,39 @@
+<%#
+ Copyright 2013-2018 the original author or authors from the JHipster project.
+ This file is part of the JHipster project, see http://www.jhipster.tech/
+ for more information.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-%>
+
+/**
+ * Angular bootstrap Date adapter
+ */
+import { Injectable } from '@angular/core';
+import { NgbDateAdapter, NgbDateStruct } from '@ng-bootstrap/ng-bootstrap';
+import { Moment } from 'moment';
+import * as moment from 'moment';
+
+@Injectable()
+export class NgbDateMomentAdapter extends NgbDateAdapter<Moment> {
+
+    fromModel(date: Moment): NgbDateStruct {
+        if ( date != null && date.isValid() ) {
+            return { year: date.year(), month: date.month() + 1, day: date.date() };
+        }
+        return null;
+    }
+
+    toModel(date: NgbDateStruct): Moment {
+        return date ? moment(date.year + '-' + date.month + '-' + date.day, 'YYYY-MM-DD') : null;
+    }
+}
diff --git a/generators/client/templates/angular/src/main/webapp/app/shared/util/request-util.ts.ejs b/generators/client/templates/angular/src/main/webapp/app/shared/util/request-util.ts.ejs
index 7665eb727a..1c85ed8274 100644
--- a/generators/client/templates/angular/src/main/webapp/app/shared/util/request-util.ts.ejs
+++ b/generators/client/templates/angular/src/main/webapp/app/shared/util/request-util.ts.ejs
@@ -1,3 +1,19 @@
+<%#
+ Copyright 2013-2018 the original author or authors from the JHipster project.
+ This file is part of the JHipster project, see http://www.jhipster.tech/
+ for more information.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-%>
 import { HttpParams } from '@angular/common/http';
 
 export const createRequestOption = (req?: any): HttpParams => {
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-detail.component.html.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-detail.component.html.ejs
index aa30724073..ad3b76a6ac 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-detail.component.html.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-detail.component.html.ejs
@@ -37,10 +37,6 @@
                 </a>
                 {{<%= entityInstance %>.<%= fieldName %>ContentType}}, {{byteSize(<%= entityInstance %>.<%= fieldName %>)}}
             </div>
-            <%_ } else if (['Instant', 'ZonedDateTime'].includes(fieldType)) { _%>
-            <span>{{<%=entityInstance %>.<%= fieldName %> | date:'medium'}}</span>
-            <%_ } else if (fieldType === 'LocalDate') { _%>
-            <span>{{<%=entityInstance %>.<%= fieldName %> | date:'mediumDate'}}</span>
             <%_ } else if (['byte[]', 'ByteBuffer'].includes(fieldType) && fieldTypeBlobContent === 'any') { _%>
             <div *ngIf="<%= entityInstance %>.<%= fieldName %>">
                 <a (click)="openFile(<%= entityInstance %>.<%= fieldName %>ContentType, <%= entityInstance %>.<%= fieldName %>)" jhiTranslate="entity.action.open">open</a>
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-dialog.component.html.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-dialog.component.html.ejs
index c5f23214e0..2a9b0a0cdf 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-dialog.component.html.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-dialog.component.html.ejs
@@ -100,7 +100,7 @@ _%>
             </div>
             <%_ } else if (['Instant', 'ZonedDateTime'].includes(fieldType)) { _%>
             <div class="d-flex">
-                <input id="field_<%= fieldName %>" type="datetime-local" class="form-control" name="<%= fieldName %>" [(ngModel)]="<%= entityInstance %>.<%= fieldName %>"
+                <input id="field_<%= fieldName %>" type="datetime-local" class="form-control" name="<%= fieldName %>" [(ngModel)]="<%= fieldName %>"
                 <%- include ng_validators %>/>
             </div>
             <%_ } else if(fieldTypeBlobContent === 'text') { _%>
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-dialog.component.ts.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-dialog.component.ts.ejs
index a536795be7..dbc5aa076d 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-dialog.component.ts.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-dialog.component.ts.ejs
@@ -33,6 +33,10 @@ import { ActivatedRoute } from '@angular/router';
 import { HttpResponse, HttpErrorResponse } from '@angular/common/http';
 import { Observable } from 'rxjs/Observable';
 import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+<%_ if ( fieldsContainInstant || fieldsContainZonedDateTime ) { _%>
+import { DateFormatPipe, ParsePipe } from 'angular2-moment';
+import { DATE_TIME_FORMAT } from 'app/shared/constants/input.constants';
+<%_ } _%>
 import { JhiEventManager<% if (queries && queries.length > 0) { %>, JhiAlertService<% } %><% if (fieldsContainBlob) { %>, JhiDataUtils<% } %> } from 'ng-jhipster';
 
 import { I<%= entityAngularName %> } from 'app/shared/model/<%= entityModelFileName %>.model';
@@ -68,19 +72,21 @@ import { <%= uniqueRel.otherEntityAngularName%>Service } from '../<%= uniqueRel.
 })
 export class <%= entityAngularName %>DialogComponent implements OnInit {
 
-    <%= entityInstance %>: I<%= entityAngularName %>;
+    private _<%= entityInstance %>: I<%= entityAngularName %>;
     isSaving: boolean;
     <%_
-    for (const idx in variables) { %>
+    for ( const idx in variables ) { %>
     <%- variables[idx] %>
     <%_ } _%>
-    <%_ for (idx in fields) {
+    <%_ for ( idx in fields ) {
         const fieldName = fields[idx].fieldName;
         const fieldType = fields[idx].fieldType;
-        if (fieldType === 'LocalDate') { _%>
+        if ( fieldType === 'LocalDate' ) { _%>
     <%= fieldName %>Dp: any;
-        <%_ }
-    } _%>
+    <%_ } else if ( ['Instant', 'ZonedDateTime'].includes(fieldType) ) { _%>
+    <%= fieldName %>: string;
+      <%_ } _%>
+    <%_ } _%>
 
     constructor(
         public activeModal: NgbActiveModal,
@@ -100,6 +106,10 @@ export class <%= entityAngularName %>DialogComponent implements OnInit {
                 }
             }
         }); _%>
+        <%_ if (fieldsContainInstant || fieldsContainZonedDateTime) { _%>
+        private stringToMomentPipe: ParsePipe,
+        private momentToStringPipe: DateFormatPipe,
+        <%_ } _%>
         <%_ if (fieldsContainImageBlob) { _%>
         private elementRef: ElementRef,
         <%_ } _%>
@@ -140,6 +150,13 @@ export class <%= entityAngularName %>DialogComponent implements OnInit {
 
     save() {
         this.isSaving = true;
+        <%_ for (idx in fields) {
+            const fieldName = fields[ idx ].fieldName;
+            const fieldType = fields[idx].fieldType;
+            if ([ 'Instant', 'ZonedDateTime' ].includes(fieldType)) { _%>
+                this.<%= entityInstance %>.<%= fieldName %> = this.stringToMomentPipe.transform(this.<%= fieldName %>, DATE_TIME_FORMAT);
+        <%_ }
+        } _%>
         if (this.<%= entityInstance %>.id !== undefined) {
             this.subscribeToSaveResponse(
                 this.<%= entityInstance %>Service.update(this.<%= entityInstance %>));
@@ -193,6 +210,19 @@ export class <%= entityAngularName %>DialogComponent implements OnInit {
         return option;
     }
     <%_ } _%>
+    get <%= entityInstance %>() {
+        return this._<%= entityInstance %>;
+    }
+
+    set <%= entityInstance %>(<%= entityInstance %>: I<%= entityAngularName %>) {
+        this._<%= entityInstance %> = <%= entityInstance %>;
+    <%_ for (idx in fields) {
+        const fieldName = fields[idx].fieldName;
+        const fieldType = fields[idx].fieldType;
+        if (['Instant', 'ZonedDateTime'].includes(fieldType)) { _%>
+        this.<%= fieldName %> = this.momentToStringPipe.transform(<%= entityInstance %>.<%= fieldName %>);
+     <%_ } } _%>
+    }
 }
 
 @Component({
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-popup.service.ts.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-popup.service.ts.ejs
index 6f318649f1..d4d87f5ca5 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-popup.service.ts.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-popup.service.ts.ejs
@@ -20,9 +20,6 @@ import { Injectable, Component } from '@angular/core';
 import { Router } from '@angular/router';
 import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
 import { HttpResponse } from '@angular/common/http';
-<%_ if (fieldsContainInstant || fieldsContainZonedDateTime) { _%>
-import { DatePipe } from '@angular/common';
-<%_ } _%>
 import { I<%= entityAngularName %>, <%= entityAngularName %> } from 'app/shared/model/<%= entityModelFileName %>.model';
 import { <%= entityAngularName %>Service } from './<%= entityFileName %>.service';
 <%_
@@ -37,9 +34,6 @@ export class <%= entityAngularName %>PopupService {
     private ngbModalRef: NgbModalRef;
 
     constructor(
-        <%_ if (fieldsContainInstant || fieldsContainZonedDateTime) { _%>
-        private datePipe: DatePipe,
-        <%_ } _%>
         private modalService: NgbModal,
         private router: Router,
         private <%= entityInstance %>Service: <%= entityAngularName %>Service
@@ -59,23 +53,6 @@ export class <%= entityAngularName %>PopupService {
                 this.<%= entityInstance %>Service.find(id)
                     .subscribe((<%= entityInstance %>Response: HttpResponse<I<%= entityAngularName %>>) => {
                         const <%= entityInstance %>: I<%= entityAngularName %> = <%= entityInstance %>Response.body;
-                        <%_ if (hasDate) { _%>
-                            <%_ for (idx in fields) { _%>
-                                <%_ if (fields[idx].fieldType === 'LocalDate') { _%>
-                        if (<%= entityInstance %>.<%=fields[idx].fieldName%>) {
-                            <%= entityInstance %>.<%=fields[idx].fieldName%> = {
-                                year: <%= entityInstance %>.<%=fields[idx].fieldName%>.getFullYear(),
-                                month: <%= entityInstance %>.<%=fields[idx].fieldName%>.getMonth() + 1,
-                                day: <%= entityInstance %>.<%=fields[idx].fieldName%>.getDate()
-                            };
-                        }
-                                <%_ } _%>
-                                <%_ if (['Instant', 'ZonedDateTime'].includes(fields[idx].fieldType)) { _%>
-                        <%= entityInstance %>.<%=fields[idx].fieldName%> = this.datePipe
-                            .transform(<%= entityInstance %>.<%=fields[idx].fieldName%>, 'yyyy-MM-ddTHH:mm:ss');
-                                <%_ } _%>
-                        <%_ } _%>
-                        <%_ } _%>
                         this.ngbModalRef = this.<%= entityInstance %>ModalRef(component, <%= entityInstance %>);
                         resolve(this.ngbModalRef);
                     });
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity.model.ts.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity.model.ts.ejs
index 3336cb219f..9d6aaaeb43 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity.model.ts.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity.model.ts.ejs
@@ -21,6 +21,9 @@ const variablesWithTypes = generateEntityClientFields(pkType, fields, relationsh
 const typeImports = generateEntityClientImports(relationships, dto);
 const defaultVariablesValues = generateEntityClientFieldDefaultValues(fields);
 %>
+<%_ if (fieldsContainInstant || fieldsContainZonedDateTime || fieldsContainLocalDate) { _%>
+import { Moment } from 'moment';
+<%_ } _%>
 <%_ typeImports.forEach( (importedPath, importedType) => { _%>
 import { <%- importedType %> } from '<%- importedPath %>';
 <%_ }); _%>
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity.service.ts.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity.service.ts.ejs
index d23be0365b..62cace4c48 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity.service.ts.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity.service.ts.ejs
@@ -26,7 +26,7 @@ import { Injectable } from '@angular/core';
 import { HttpClient, HttpResponse } from '@angular/common/http';
 import { Observable } from 'rxjs/Observable';
 <%_ if (hasDate) { _%>
-import { JhiDateUtils } from 'ng-jhipster';
+import * as moment from 'moment';
 <%_ } _%>
 
 import { SERVER_API_URL } from 'app/app.constants';
@@ -44,7 +44,7 @@ export class <%= entityAngularName %>Service {
     private resourceSearchUrl = SERVER_API_URL + '<% if (applicationType === 'gateway' && locals.microserviceName) { %><%= microserviceName.toLowerCase() %>/<% } %>api/_search/<%= entityApiUrl %>';
     <%_ } _%>
 
-    constructor(private http: HttpClient<% if (hasDate) { %>, private dateUtils: JhiDateUtils<% } %>) { }
+    constructor(private http: HttpClient) { }
     <%_ if (entityAngularName.length <= 30) { _%>
 
     create(<%= entityInstance %>: I<%= entityAngularName %>): Observable<EntityResponseType> {
@@ -111,17 +111,13 @@ export class <%= entityAngularName %>Service {
      * Convert a returned JSON object to <%= entityAngularName %>.
      */
     private convertItemFromServer(<%= entityInstance %>: I<%= entityAngularName %>): I<%= entityAngularName %> {
-        const copy: I<%= entityAngularName %> = Object.assign({}, <%= entityInstance %>);
+        const copy: I<%= entityAngularName %> = Object.assign({}, <%= entityInstance %>, {
         <%_ for (idx in fields) { _%>
-        <%_ if (fields[idx].fieldType === 'LocalDate') { _%>
-        copy.<%=fields[idx].fieldName%> = this.dateUtils
-            .convertLocalDateFromServer(<%= entityInstance %>.<%=fields[idx].fieldName%>);
-        <%_ } _%>
-        <%_ if (['Instant', 'ZonedDateTime'].includes(fields[idx].fieldType)) { _%>
-        copy.<%=fields[idx].fieldName%> = this.dateUtils
-            .convertDateTimeFromServer(<%= entityInstance %>.<%=fields[idx].fieldName%>);
+        <%_ if ( ['Instant', 'ZonedDateTime', 'LocalDate'].includes(fields[idx].fieldType) ) { _%>
+        <%=fields[idx].fieldName%>: <%= entityInstance %>.<%= fields[idx].fieldName %> != null ? moment(<%= entityInstance %>.<%= fields[idx].fieldName %>) : <%= entityInstance %>.<%= fields[idx].fieldName %>,
             <%_ } _%>
         <%_ } _%>
+        });
         return copy;
     }
 
@@ -129,13 +125,11 @@ export class <%= entityAngularName %>Service {
      * Convert a <%= entityAngularName %> to a JSON which can be sent to the server.
      */
     private convert(<%= entityInstance %>: I<%= entityAngularName %>): I<%= entityAngularName %> {
-        const copy: I<%= entityAngularName %> = Object.assign({}, <%= entityInstance %>);
-        <%_ for (idx in fields){ if (fields[idx].fieldType === 'LocalDate') { _%>
-        copy.<%=fields[idx].fieldName%> = this.dateUtils
-            .convertLocalDateToServer(<%= entityInstance %>.<%=fields[idx].fieldName%>);
-        <%_ } if (['Instant', 'ZonedDateTime'].includes(fields[idx].fieldType)) { %>
-        copy.<%=fields[idx].fieldName%> = this.dateUtils.toDate(<%= entityInstance %>.<%=fields[idx].fieldName%>);
+        const copy: I<%= entityAngularName %> = Object.assign({}, <%= entityInstance %>, {
+        <%_ for (idx in fields){ if ( ['Instant', 'ZonedDateTime', 'LocalDate'].includes(fields[idx].fieldType) ) { _%>
+        <%= fields[idx].fieldName %>: <%= entityInstance %>.<%= fields[idx].fieldName %> != null && <%= entityInstance %>.<%= fields[idx].fieldName %>.isValid() ? <%= entityInstance %>.<%= fields[idx].fieldName %>.toJSON() : null,
         <%_ } } _%>
+        });
         return copy;
     }
 }
diff --git a/generators/generator-base-private.js b/generators/generator-base-private.js
index dcd84ae60e..f282c9598f 100644
--- a/generators/generator-base-private.js
+++ b/generators/generator-base-private.js
@@ -802,6 +802,8 @@ module.exports = class extends Generator {
                 tsType = 'number';
             } else if (fieldType === 'String' || fieldType === 'UUID') {
                 tsType = 'string';
+            } else if (['LocalDate', 'Instant', 'ZonedDateTime'].includes(fieldType)) {
+                tsType = 'Moment';
             } else { // (fieldType === 'byte[]' || fieldType === 'ByteBuffer') && fieldTypeBlobContent === 'any' || (fieldType === 'byte[]' || fieldType === 'ByteBuffer') && fieldTypeBlobContent === 'image' || fieldType === 'LocalDate'
                 tsType = 'any';
                 if (['byte[]', 'ByteBuffer'].includes(fieldType) && field.fieldTypeBlobContent !== 'text') {
@@ -858,11 +860,9 @@ module.exports = class extends Generator {
      */
     generateEntityClientImports(relationships, dto) {
         const typeImports = new Map();
-
         relationships.forEach((relationship) => {
             const relationshipType = relationship.relationshipType;
             let toBeImported = false;
-
             if (relationshipType === 'one-to-many' || relationshipType === 'many-to-many') {
                 toBeImported = true;
             } else if (dto === 'no') {
@@ -874,7 +874,6 @@ module.exports = class extends Generator {
                     toBeImported = true;
                 }
             }
-
             if (toBeImported) {
                 const otherEntityAngularName = relationship.otherEntityAngularName;
                 const importType = `I${otherEntityAngularName}`;


Test patch:
diff --git a/generators/entity-client/templates/angular/src/test/javascript/e2e/entities/entity.spec.ts.ejs b/generators/entity-client/templates/angular/src/test/javascript/e2e/entities/entity.spec.ts.ejs
index cf621b41d7..9883f575b6 100644
--- a/generators/entity-client/templates/angular/src/test/javascript/e2e/entities/entity.spec.ts.ejs
+++ b/generators/entity-client/templates/angular/src/test/javascript/e2e/entities/entity.spec.ts.ejs
@@ -16,7 +16,7 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -%>
-import { browser } from 'protractor';
+import { browser, <% if ( fieldsContainInstant || fieldsContainZonedDateTime ) { %>protractor<% } %> } from 'protractor';
 import { NavBarPage } from './../../<%= entityParentPathAddition %>page-objects/jhi-page-objects';
 import { <%= entityClass %>ComponentsPage, <%= entityClass %>DialogPage } from './<%= entityFileName %>.page-object';
 <%_ let fieldHasByte = false;
@@ -107,8 +107,8 @@ describe('<%= entityClass %> e2e test', () => {
         <%= entityInstance %>DialogPage.set<%= fieldNameCapitalized %>Input('2000-12-31');
         expect(<%= entityInstance %>DialogPage.get<%= fieldNameCapitalized %>Input()).toMatch('2000-12-31');
         <%_ } else if (['Instant', 'ZonedDateTime'].includes(fieldType)) { _%>
-        <%= entityInstance %>DialogPage.set<%= fieldNameCapitalized %>Input(12310020012301);
-        expect(<%= entityInstance %>DialogPage.get<%= fieldNameCapitalized %>Input()).toMatch('2001-12-31T02:30');
+        <%= entityInstance %>DialogPage.set<%= fieldNameCapitalized %>Input('01/01/2001' + protractor.Key.TAB + '02:30AM');
+        expect(<%= entityInstance %>DialogPage.get<%= fieldNameCapitalized %>Input()).toContain('2001-01-01T02:30');
         <%_ } else if (fieldType === 'Boolean') { _%>
         <%= entityInstance %>DialogPage.get<%= fieldNameCapitalized %>Input().isSelected().then((selected) => {
             if (selected) {
diff --git a/generators/entity-client/templates/angular/src/test/javascript/spec/app/entities/entity-management-dialog.component.spec.ts.ejs b/generators/entity-client/templates/angular/src/test/javascript/spec/app/entities/entity-management-dialog.component.spec.ts.ejs
index c7b4b099ac..345691680c 100644
--- a/generators/entity-client/templates/angular/src/test/javascript/spec/app/entities/entity-management-dialog.component.spec.ts.ejs
+++ b/generators/entity-client/templates/angular/src/test/javascript/spec/app/entities/entity-management-dialog.component.spec.ts.ejs
@@ -25,6 +25,7 @@ import { HttpResponse } from '@angular/common/http';
 import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
 import { Observable } from 'rxjs/Observable';
 import { JhiEventManager } from 'ng-jhipster';
+import { DateFormatPipe, ParsePipe } from 'angular2-moment';
 
 import { <%=angularXAppName%>TestModule } from '../../../<%= entityParentPathAddition %>test.module';
 import { <%= entityAngularName %>DialogComponent } from 'app/entities/<%= entityFolderName %>/<%= entityFileName %>-dialog.component';
@@ -66,16 +67,16 @@ describe('Component Tests', () => {
             TestBed.configureTestingModule({
                 imports: [<%=angularXAppName%>TestModule],
                 declarations: [<%= entityAngularName %>DialogComponent],
-                providers: [
-                    <%_ Object.keys(differentRelationships).forEach(key => {
-                        if (differentRelationships[key].some(rel => rel.relationshipType !== 'one-to-many')) {
-                            const uniqueRel = differentRelationships[key][0];
-                            if (uniqueRel.otherEntityAngularName !== entityAngularName) { _%>
+                providers: [ParsePipe, DateFormatPipe,
+    <%_ Object.keys(differentRelationships).forEach(key => {
+        if (differentRelationships[key].some(rel => rel.relationshipType !== 'one-to-many')) {
+            const uniqueRel = differentRelationships[key][0];
+            if (uniqueRel.otherEntityAngularName !== entityAngularName) { _%>
                     <%= uniqueRel.otherEntityAngularName %>Service,
-                    <%_
-                            }
-                        }
-                    }); _%>
+    <%_
+            }
+        }
+    }); _%>
                     <%= entityAngularName %>Service
                 ]
             })
diff --git a/generators/entity-client/templates/angular/src/test/javascript/spec/app/entities/entity-management.service.spec.ts.ejs b/generators/entity-client/templates/angular/src/test/javascript/spec/app/entities/entity-management.service.spec.ts.ejs
index 18e0637964..e1aec7ac1c 100644
--- a/generators/entity-client/templates/angular/src/test/javascript/spec/app/entities/entity-management.service.spec.ts.ejs
+++ b/generators/entity-client/templates/angular/src/test/javascript/spec/app/entities/entity-management.service.spec.ts.ejs
@@ -22,8 +22,7 @@ _%>
 /* tslint:disable max-line-length */
 import { TestBed, getTestBed } from '@angular/core/testing';
 import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
-import { JhiDateUtils } from 'ng-jhipster';
-
+import { DateFormatPipe, ParsePipe } from 'angular2-moment';
 import { <%= entityAngularName %>Service } from 'app/entities/<%= entityFolderName %>/<%= entityFileName %>.service';
 import { <%= entityAngularName %> } from 'app/shared/model/<%= entityModelFileName %>.model';
 import { SERVER_API_URL } from 'app/app.constants';
@@ -41,8 +40,7 @@ describe('Service Tests', () => {
                     HttpClientTestingModule
                 ],
                 providers: [
-                    JhiDateUtils,
-                    <%= entityAngularName %>Service
+                    ParsePipe, DateFormatPipe, <%= entityAngularName %>Service
                 ]
             });
             injector = getTestBed();
diff --git a/test/utils/expected-files.js b/test/utils/expected-files.js
index 92ddba4d32..b70b7c8537 100644
--- a/test/utils/expected-files.js
+++ b/test/utils/expected-files.js
@@ -309,6 +309,7 @@ const expectedFiles = {
         `${CLIENT_MAIN_SRC_DIR}app/core/auth/state-storage.service.ts`,
         `${CLIENT_MAIN_SRC_DIR}app/core/auth/user-route-access-service.ts`,
         `${CLIENT_MAIN_SRC_DIR}app/shared/constants/error.constants.ts`,
+        `${CLIENT_MAIN_SRC_DIR}app/shared/constants/input.constants.ts`,
         `${CLIENT_MAIN_SRC_DIR}app/shared/constants/pagination.constants.ts`,
         `${CLIENT_MAIN_SRC_DIR}app/shared/index.ts`,
         `${CLIENT_MAIN_SRC_DIR}app/shared/language/find-language-from-key.pipe.ts`,
@@ -319,6 +320,7 @@ const expectedFiles = {
         `${CLIENT_MAIN_SRC_DIR}app/shared/login/login.component.ts`,
         `${CLIENT_MAIN_SRC_DIR}app/core/login/login.service.ts`,
         `${CLIENT_MAIN_SRC_DIR}app/shared/util/request-util.ts`,
+        `${CLIENT_MAIN_SRC_DIR}app/shared/util/datepicker-adapter.ts`,
         `${CLIENT_MAIN_SRC_DIR}app/shared/shared-common.module.ts`,
         `${CLIENT_MAIN_SRC_DIR}app/shared/shared-libs.module.ts`,
         `${CLIENT_MAIN_SRC_DIR}app/shared/shared.module.ts`,
diff --git a/travis/samples/.jhipster/FieldTestEntity.json b/travis/samples/.jhipster/FieldTestEntity.json
index b01aeb306f..cb0f648577 100644
--- a/travis/samples/.jhipster/FieldTestEntity.json
+++ b/travis/samples/.jhipster/FieldTestEntity.json
@@ -181,7 +181,7 @@
             "fieldType": "Instant"
         },
         {
-            "fieldName": "instanteRequiredTom",
+            "fieldName": "instantRequiredTom",
             "fieldType": "Instant",
             "fieldValidateRules": [
                 "required"