You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular报错NG02100:DatePipe无效日期参数转换问题排查

Angular DatePipe 报错 NG02100 排查修复

异常现象

异常信息:NG02100: InvalidPipeArgument: 'Unable to convert "Wed Jun 29 2022 10:19:00 GM" into a date' for pipe 'DatePipe' - Angular

每次点击项目条目时都会抛出该错误,无法定位触发异常的具体位置,初步判断和字符串转日期逻辑相关,但未找到根因。
错误截图

关联代码

组件逻辑代码

@Component({
  selector: 'bookmark-history',
  templateUrl: './history.component.html',
  styleUrls: ['./history.component.scss']
})
export class HistoryComponent{

  Contents$:Observable<History[]>;
  ContentsInOrder$:Observable<Content[]>;
  Histories$=this.facade.Histories$;
  histo:History[];
  Date= new Date;
  
  showTrash = false;

  constructor(private historyService : HistoryService, private contentService : ContentService, private _snackBar: MatSnackBar, private facade:HistoryFacade, private dialogService:DialogService,
    private dialog:MatDialog) {
    this.Contents$=this.contentService.getContent();
    this.ContentsInOrder$=this.contentService.getContentInOrder();
    this.ContentsInOrder$ = this.ContentsInOrder$.pipe(map((result => result.sort((a,b) => b.points - a.points))))
    this.Histories$ = this.Histories$.pipe(map((rallies => rallies.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()))))
    this.facade.loadHistoryList();
    
    this.Histories$.subscribe(history => {
        this.histo = history as History[];
    }) 
   }

  onDeleteHistory(history:History){
    this.facade.deleteHistory(history);
  }

  onAddHistory(content:Content){
    const histo : History ={
      id : Math.floor(Math.random() * 999999999),
      SNS:content.SNS,
      title:content.title,
      DMC:content.DMC,
      date : new Date(),
      showTrash : false
    }
    this.facade.addHistory(histo);
    this.facade.loadHistoryList();
  }

  onDeleteAll(){
    this.historyService.deleteAllHistory(this.histo);
  }

  @Output() click: EventEmitter<void> = new EventEmitter();

  onclick(){
    this.click.emit();
  }

  openDialog(){
    this.dialog.open(DialogComponent);
  }
}

@Pipe({ name: 'groupByDay' })
export class GroupByDayPipe implements PipeTransform {
  constructor(private facade:HistoryFacade) {}
  Histories$=this.facade.Histories$;
  transform(items: any[]): any[] {
    const groups = items.reduce((groups, game) => {
      const date = game.date.toString().split('T')[0];
      if (!groups[date]) {
        groups[date] = [];
      }
      groups[date].push(game);
      return groups;
    }, {});
    const groupArrays = Object.entries(groups);
    console.log(groupArrays);
    return groupArrays;
  }
}

组件模板代码

<mat-tab-group mat-align-tabs="start" class="leftSide">
    <mat-tab label="Recent Document View">
        <div class="scroll">
            <div mat-subheader *ngIf="(Histories$ | async).length===0">The documents you visit will show here</div>
       
            <ng-container *ngIf="Histories$ | async">
                <ng-container *ngFor="let group of Histories$ | async | groupByDay">
                  <strong>{{ group[0] | date: 'EEEE, MMMM d, YYYY' }}</strong>
                  <br />
                  <br />
              
                  <div *ngFor="let history of group[1]">
                    <mat-list-item  class="historyClicking" (mouseover)="history.showTrash=true" (mouseout)="history.showTrash=false" (click)="onclick()">
                      <div class="block">
                        <div matList>{{history.SNS}}</div>
                        <div matList>{{history.title}}</div>
                        <div matList>{{history.DMC}}</div>
                        <div matLine class="onit" >
                            <button *ngIf="history.showTrash" mat-icon-button  (click)="onDeleteHistory(history)">
                            <mat-icon>delete_outline</mat-icon>
                            </button>
                            <div *ngIf="!history.showTrash">{{history.date | date:"mediumTime"}}</div>
                        </div>
                      </div>
                    </mat-list-item>
                  </div>  
                </ng-container>
            </ng-container>
        </div>
    </mat-tab>
</mat-tab-group>

根因定位

报错和你怀疑的*ngFor="let history of group[1]"代码行无关,核心问题是传入DatePipe的日期值是非法非标准格式:

  • GroupByDayPipe里生成分组key的逻辑错误:当game.date是Date对象时,调用toString()返回的是类似Wed Jun 29 2022 10:19:00 GMT+0800 (中国标准时间)的本地时间字符串,这个字符串里根本没有字符T,用split('T')[0]切割拿到的是残缺的字符串(就是报错里的Wed Jun 29 2022 10:19:00 GM),把这个残缺字符串传给{{ group[0] | date: 'EEEE, MMMM d, YYYY' }}的DatePipe时,就会抛出解析失败的错误。
  • 模板中多次重复订阅Histories$ | async,会导致流多次执行,放大异常出现的概率。

修复方案

  1. 重写GroupByDayPipe的分组key生成逻辑,不要依赖toString()切割,统一生成标准YYYY-MM-DD格式的日期key:
transform(items: any[]): any[] {
  const groups = items.reduce((groups, game) => {
    // 先统一转Date对象做兼容,不管传入的是时间戳、字符串还是Date实例
    const gameDate = new Date(game.date);
    // 生成标准YYYY-MM-DD格式的分组key,确保DatePipe可以正常解析
    const dateKey = `${gameDate.getFullYear()}-${String(gameDate.getMonth() + 1).padStart(2, '0')}-${String(gameDate.getDate()).padStart(2, '0')}`;
    if (!groups[dateKey]) {
      groups[dateKey] = [];
    }
    groups[dateKey].push(game);
    return groups;
  }, {});
  return Object.entries(groups);
}
  1. 优化模板的async订阅,用as关键字存局部变量,避免重复订阅触发冗余计算:
<ng-container *ngIf="Histories$ | async as histories">
  <ng-container *ngFor="let group of histories | groupByDay">
    <!-- 原有模板内容不变 -->
  </ng-container>
</ng-container>
  1. 所有传给DatePipe的日期值,确保是Angular支持的三类合法值:Date实例、毫秒级时间戳、ISO 8601标准日期字符串(如2022-06-29T10:19:00.000Z),不要传入非标准的残缺日期字符串。

内容的提问来源于stack exchange,提问作者Picolo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 19:15:30