Skip to content

Instantly share code, notes, and snippets.

@martinobordin
Last active September 22, 2023 08:23
Show Gist options
  • Star 37 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save martinobordin/39bb1fe3400a29c1078dec00ff76bba9 to your computer and use it in GitHub Desktop.
Save martinobordin/39bb1fe3400a29c1078dec00ff76bba9 to your computer and use it in GitHub Desktop.
An Angular interceptor to parse string dates (ISO8601 format) from server response to JS Date Object. There are both RxJs 5 and RxJs 6 versions
import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpErrorResponse, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';
@Injectable()
export class AngularDateHttpInterceptor implements HttpInterceptor {
// Migrated from AngularJS https://raw.githubusercontent.com/Ins87/angular-date-interceptor/master/src/angular-date-interceptor.js
iso8601 = /^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(\.\d+)?(([+-]\d\d:\d\d)|Z)?$/;
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).do((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
const body = event.body;
this.convertToDate(body);
}
}, (err: any) => {
if (err instanceof HttpErrorResponse) {
if (err.status === 401) {
}
}
});
}
convertToDate(body) {
if (body === null || body === undefined) {
return body;
}
if (typeof body !== 'object') {
return body;
}
for (const key of Object.keys(body)) {
const value = body[key];
if (this.isIso8601(value)) {
body[key] = new Date(value);
} else if (typeof value === 'object') {
this.convertToDate(value);
}
}
}
isIso8601(value) {
if (value === null || value === undefined) {
return false;
}
return this.iso8601.test(value);
}
}
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
HttpErrorResponse,
HttpResponse
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
export class AngularDateHttpInterceptor implements HttpInterceptor {
// Migrated from AngularJS https://raw.githubusercontent.com/Ins87/angular-date-interceptor/master/src/angular-date-interceptor.js
iso8601 = /^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(\.\d+)?(([+-]\d\d:\d\d)|Z)?$/;
public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).pipe(
tap((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
const body = event.body;
this.convertToDate(body);
}
}, (err: any) => {
if (err instanceof HttpErrorResponse) {
if (err.status === 401) {
}
}
}),
);
}
convertToDate(body) {
if (body === null || body === undefined) {
return body;
}
if (typeof body !== 'object') {
return body;
}
for (const key of Object.keys(body)) {
const value = body[key];
if (this.isIso8601(value)) {
body[key] = new Date(value);
} else if (typeof value === 'object') {
this.convertToDate(value);
}
}
}
isIso8601(value) {
if (value === null || value === undefined) {
return false;
}
return this.iso8601.test(value);
}
}
@Al-Sharif
Copy link

Worked as expected. Thank you.

@arcturuscom
Copy link

do you think that this interceptor will not cause some performance problems ? say, we have an http response that contains a list of 1000 iso date

@danielhgasparin
Copy link

Stared!

Wondering if a solution to this problem already exists in core Angular. Maybe in latest or future versions.

@Clemzd
Copy link

Clemzd commented Jul 1, 2019

Can't believe there isn't an embedded solution with Angular...

@giangpham05
Copy link

This rescured my life. Thank you very much mate.

@ssougnez
Copy link

I think I'm on love <3
I can't believe I worked without this interceptor so far.

Thanks a lot dude ;-)

@unitrix0
Copy link

unitrix0 commented Jan 2, 2020

Can anybody confirm this is working in Angular > 7?

@Totati
Copy link

Totati commented Jan 24, 2020

Can anybody confirm this is working in Angular > 7?

It uses the legacy RxJS syntax, so it won't work out of the box. There's this fork that works.

@martinobordin
Copy link
Author

I added also the RxJs6+ syntax (used pipe method & tap operator instead of do)

@PaulARoy
Copy link

Thank you so much man!!
I don't understand how that's not a core feature…

@sobelfallcayor
Copy link

sobelfallcayor commented Jul 1, 2020

For each request, it process all fields and make/try a conversion. Dit someone check for performance ? i'm sure it is performance issue that Angular team do not include it on core.

@mattjanssen
Copy link

Thanks for these useful snippets!

Just a heads up...the return body; statements in convertToDate() aren't ever used, and don't match up with the final return (void) later on.

@LAlves91
Copy link

Thank you for this!
One thing I think would be good to add is a type check inside the isIso8601 method:

isIso8601(value) {
        if (value === null || value === undefined) {
            return false;
        }
        if (typeof value === 'string') {
            return this.iso8601.test(value);
        }
        return false;
}

This way, we can avoid checking at least some of the fields. I've tested this interceptor, and the worst case I've got so far is a 1ms time difference between beginning and ending conversion.

@datze
Copy link

datze commented Jul 9, 2021

@aml360
Copy link

aml360 commented Aug 3, 2021

I have refactored by making it "type-safe", useful for those using strict typescript mode
Here is the code: https://gist.github.com/aml360/7e8efc275b0adb46bd5bb1b555b42467

@LAlves91
Copy link

LAlves91 commented Aug 3, 2021

For those, like me, who are using Java backends, there's one thing to be aware: the regex used works with LocalDateTime but if any DTO uses LocalDate, those fields won't be converted. I added another regex in order for them to be intercepted aswell.

@jbrychka
Copy link

jbrychka commented Feb 4, 2022

Glad I found your code but I have one issue on my end. I'm using SpringBoot in the middle tier. How do I have my web service send a ISO8601 format string date in the JSON output? Right now its coming across as a number. I do want keep the field in the pojo as a java.util.Date class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment