Angular 4: Date pipe, UTC Time to local time: How

2019-04-08 04:38发布

We are using Angular 4 together with a MVC Application written in .net core. The data is received using a SignalR Service, the hub is written in C#. The database provides a Datetime2(7) Field (T-SQL), the content, that gets received, looks like this (for the date-field):

dueDt:"2017-10-02T08:54:00"

This time is a UTC Time. We are living in a +2 time zone. Now, in the CSHTML-File, we display this value like this:

 <small>Due: {{item.dueDt | date:'dd.MM.yy HH:mm'}}</small>

which display something like: 27.09.17 12:43 which is fine, the problem is just that our timezone is not +0 but +2, so it should display 14:43 as the time.

I have read somewhere that Angulars DatePipe uses the clients local timezone, but that doesnt seem to happen here. (I have tried this with chrome, firefox and Edge - there is no difference). Does anybody have an idea, why this happens or how I can tell Angular what the local timezone is? I have tried including angular-moment but it doesnt really work either. (I can detail that, if that seems important, but it is a different issue).

2条回答
戒情不戒烟
2楼-- · 2019-04-08 05:16

I have done something similar using moment.js, but the Locale it's actually specific to each user configuration for Locale and date pattern:

import { Injectable, Pipe, PipeTransform } from '@angular/core';
import * as moment from 'moment';
import { Observable } from 'rxjs/Rx';
import { UserService } from '../security/user/user.service';

@Pipe({
    name: 'formatDate'
})
@Injectable()
export class DateTimePipe implements PipeTransform {

    constructor(private userService: UserService) {

    }

    /**
     * Asynchronous pipe, transforms a date into a formatted date.
     * The transformation is based on the 'locale' and 'pattern' properties from the current user preferences.
     * Usage: this pipe need to be followed by the'async' pipe, since it returns an Observable.
     */
    transform(value: any, showTime?: boolean): Observable<string> {
        if (value) {
            return this.userService.getPreferences()
                .map(prefs => {
                    const locale = prefs.preferences.get('locale');

                    let pattern;
                    if (showTime) {
                        pattern = prefs.preferences.get('dateTimeFormat') || 'DD/MM/YYYY HH:mm';
                    } else {
                        pattern = prefs.preferences.get('dateFormat') || 'DD/MM/YYYY';
                    }

                    moment.locale(locale);

                    let date = value instanceof Date ? value : new Date(value);
                    return moment(date).format(pattern);
                });
        }
        return Observable.of(value);
    }
}

you can change local with moment as well

moment.locale('en_GB')

See full options here https://momentjs.com/

查看更多
再贱就再见
3楼-- · 2019-04-08 05:26

Setting Json Deserializer options to UTC does the trick.

The default DateTime Kind for Json deserializer is RoundTripKind. When the server side datetime object's Kind is set to Unspecified, RoundTripKind doesn't add the Z at the end of the deserialized string. I guess this is the right behaviour but if we assume all date objects are actually in UTC time than we can say to Json Deserializer to consider it.

And now date pipe actually gets that the time is in UTC and shows it in local time, by default apparently

services.AddMvc().AddJsonOptions(options =>
            {
                options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
            });

And strings like "2019-03-15T21:00:00" will become "2019-03-15T21:00:00Z"

See: Newtonsoft Json.Net DateTimeZoneHandling setting

查看更多
登录 后发表回答