0

I'm using angular material 13 and asp.net core 5 and use nswag to generate client type script class. also i customize dateadapter for angular material datepicker.

I have problem with sending date value to api because when I select a date for example "Feb 20 2022" I see the correct date in the field in chrome console but, when I call api and send the object to api i get the day before the date I have selected:

[client code]

ngOnInit(): void {
    this.frmCreateOvertimeSetting = this._formBuilder.group({
      effectiveDate: [null, Validators.required],
      description: [null],
    });
  }

  addOvertimeSetting() {
    let obj: CreateOvertimeSettingDTO = new CreateOvertimeSettingDTO();
    obj.effectiveDate = this.frmCreateOvertimeSetting.value.effectiveDate;
    obj.description = this.frmCreateOvertimeSetting.value.description;

    this.overtimeSettingIsProcessing = true;

    this._overtimeSettingService.create(obj).subscribe({
      next: (overtimeSettingId) => {

      },
    });
  }

api code

this is my adapter

import {DateAdapter} from "@angular/material/core";
import * as jalaliMoment from 'jalali-moment'; /*  npm i jalali-moment */

export const PERSIAN_DATE_FORMATS = {
  parse: {
    dateInput: 'jYYYY/jMM/jDD'
  },
  display: {
    dateInput: 'jYYYY/jMM/jDD',
    monthYearLabel: 'jYYYY jMMMM',
    dateA11yLabel: 'jYYYY/jMM/jDD',
    monthYearA11yLabel: 'jYYYY jMMMM'
  }
};

export class CustomDateAdapter extends DateAdapter<jalaliMoment.Moment> {

  constructor() {
    super();
    super.setLocale('fa');
  }

  getYear(date: jalaliMoment.Moment): number {
    return this.clone(date).jYear();
  }

  getMonth(date: jalaliMoment.Moment): number {
    return this.clone(date).jMonth();
  }

  getDate(date: jalaliMoment.Moment): number {
    return this.clone(date).jDate();
  }

  getDayOfWeek(date: jalaliMoment.Moment): number {
    return this.clone(date).day();
  }

  getMonthNames(style: 'long' | 'short' | 'narrow'): string[] {
    switch (style) {
      case 'long':
      case 'short':
        return jalaliMoment.localeData('fa').jMonths().slice(0);
      case 'narrow':
        return jalaliMoment.localeData('fa').jMonthsShort().slice(0);
    }
  }

  getDateNames(): string[] {
    const valuesArray = Array(31);
    for (let i = 0; i < 31; i++) {
      valuesArray[i] = String(i + 1);
    }
    return valuesArray;
  }

  getDayOfWeekNames(style: 'long' | 'short' | 'narrow'): string[] {
    switch (style) {
      case 'long':
        return jalaliMoment.localeData('fa').weekdays().slice(0);
      case 'short':
        return jalaliMoment.localeData('fa').weekdaysShort().slice(0);
      case 'narrow':
        return ['ی', 'د', 'س', 'چ', 'پ', 'ج', 'ش'];
    }
  }

  getYearName(date: jalaliMoment.Moment): string {
    return this.clone(date).jYear().toString();
  }

  getFirstDayOfWeek(): number {
    return jalaliMoment.localeData('fa').firstDayOfWeek();
  }

  getNumDaysInMonth(date: jalaliMoment.Moment): number {
    return this.clone(date).jDaysInMonth();
  }

  clone(date: jalaliMoment.Moment): jalaliMoment.Moment {
    return date.clone().locale('fa');
  }

  createDate(year: number, month: number, date: number): jalaliMoment.Moment {
    if (month < 0 || month > 11) {
      throw Error(
        `Invalid month index "${month}". Month index has to be between 0 and 11.`
      );
    }
    if (date < 1) {
      throw Error(`Invalid date "${date}". Date has to be greater than 0.`);
    }
    const result = jalaliMoment()
      .jYear(year).jMonth(month).jDate(date)
      .hours(0).minutes(0).seconds(0).milliseconds(0)
      .locale('fa');

    if (this.getMonth(result) !== month) {
      throw Error(`Invalid date ${date} for month with index ${month}.`);
    }
    if (!result.isValid()) {
      throw Error(`Invalid date "${date}" for month with index "${month}".`);
    }
    return result;
  }

  today(): jalaliMoment.Moment {
    return jalaliMoment().locale('fa');
  }

  parse(value: any, parseFormat: string | string[]): jalaliMoment.Moment | null {
    if (value && typeof value === 'string') {
      return jalaliMoment(value, parseFormat, 'fa');
    }
    return value ? jalaliMoment(value).locale('fa') : null;
  }

  format(date: jalaliMoment.Moment, displayFormat: string): string {
    date = this.clone(date);
    if (!this.isValid(date)) {
      throw Error('JalaliMomentDateAdapter: Cannot format invalid date.');
    }
    return date.format(displayFormat);
  }

  addCalendarYears(date: jalaliMoment.Moment, years: number): jalaliMoment.Moment {
    return this.clone(date).add(years, 'jYear');
  }

  addCalendarMonths(date: jalaliMoment.Moment, months: number): jalaliMoment.Moment {
    return this.clone(date).add(months, 'jmonth');
  }

  addCalendarDays(date: jalaliMoment.Moment, days: number): jalaliMoment.Moment {
    return this.clone(date).add(days, 'jDay');
  }

  toIso8601(date: jalaliMoment.Moment): string {
    return this.clone(date).format();
  }

  isDateInstance(obj: any): boolean {
    return jalaliMoment.isMoment(obj);
  }

  isValid(date: jalaliMoment.Moment): boolean {
    return this.clone(date).isValid();
  }

  invalid(): jalaliMoment.Moment {
    return jalaliMoment.invalid();
  }

  override deserialize(value: any): jalaliMoment.Moment | null {
    let date;
    if (value instanceof Date) {
      date = jalaliMoment(value);
    }
    if (typeof value === 'string') {
      if (!value) {
        return null;
      }
      date = jalaliMoment(value).locale('fa');
    }
    if (date && this.isValid(date)) {
      return date;
    }
    return super.deserialize(value);
  }
}

and this is my module

providers: [
    
    { provide: DateAdapter, useClass: CustomDateAdapter },
    { provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true } },
    {provide: MAT_DATE_FORMATS, useValue: PERSIAN_DATE_FORMATS}
  ],

Could anyone help me?

1 Answers1

0

Look, I know it's a weird cause, but I faced something similar before and I think your issue is related to the timezone converting.

let me explain that:

If we wanna create a new Date of string value without a time, we'll get this:

new Date("2022-03-14")
// the result is: Mon Mar 14 2022 03:00:00 GMT+0300 (GMT+03:00)

Try now to convert it to toISOString:

new Date('2022-03-14').toISOString()
// the result: '2022-03-14T00:00:00.000Z'

if you noticed, the time before converting it to was 3, and after converting it ISOString becomes 0 (12 AM).

Same way, if you create a new Date with no hours or (12 AM), like:

new Date('2022-03-14 00:00')
// the result: Mon Mar 14 2022 00:00:00 GMT+0300 (GMT+03:00)

the result will be one day before, because it was (12 AM), converting to GMT (3 hrs before) it will be the previous day, like:

new Date('2022-03-14 00:00').toISOString()
// the result: '2022-03-13T21:00:00.000Z' -- one day before!!

What I'm trying to say, is you need to debug and log your date as ISOString to make sure it's not related to the timezone issue.

Nimer Awad
  • 3,967
  • 3
  • 17
  • 31