【问题标题】:Date is one day back日期是前一天
【发布时间】:2020-01-10 01:46:28
【问题描述】:

我在我的 datepicker 中选择日期 May 01 1985 并将 dateOfBirth.value 发送到我的服务器,以便它可以存储在数据库中。

<mat-form-field>
  <label><input #dateOfBirth matInput (blur)="_update('personal', 'dateOfBirth', dateOfBirth.value)" (click)="picker.open()" [matDatepicker]="picker" placeholder="Choose a date" formControlName="dateOfBirth" autocomplete="off" [max]="maxDate" [min]="minDate"></label>
  <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
  <mat-datepicker touchUi #picker startView="multi-year"></mat-datepicker>
  <mat-error *ngIf="profileFormGroup.get('dateOfBirth').errors">Date is not valid</mat-error>
</mat-form-field>

每当我刷新页面时,所选日期应该仍然可见。

我的问题是,我选择了日期 05/01/1985,但我的日期选择器显示 4/30/1985。为什么?

private static _formatDate(timestamp: number): string {
  console.log(timestamp); // Returns 483746400000
  const date = new Date(+timestamp);
  console.log(date.getDay()); // Returns 3 but it should be 1
  return date.toISOString().substring(0, 10);
}

ngOnInit() {
  this.profileService.getEntities().subscribe(data => {
  this.profileFormGroup.get('dateOfBirth').patchValue(ProfileComponent._formatDate(data.dateOfBirth));
  });
}

这是我在数据库中存储时间戳的方式:

private _update(tableName: string, columnName: string, theValue: any) {
  // Set the correct value of dateOfBirth
  console.log(theValue); // Returns 5/1/1985
  if (columnName === 'dateOfBirth') {
    const splitDate = theValue.split('/');
    const newDate = `${splitDate[2]}/${splitDate[0]}/${splitDate[1]}`;
    theValue = new Date(newDate).getTime();
    console.log(theValue); // Returns 483746400000
  }

  const json = {
      table: tableName,
      column: columnName,
      value: theValue
  };

  this.profileService.update(json).subscribe(result => {
    console.log(result);
  });
}

我还检查了其他示例,例如 this one on Stackblitz。如果选择日期01/05/2020,输出将是2020-04-30T22:00:00.000Z,这是错误的。

【问题讨论】:

  • 为什么要除以 1000?如果将该结果保存为整数,则稍后将其乘以 1000 将不会恢复原始值;几分钟将丢失,这会将日期移至前一天。
  • 你为什么要跳1000?你能提供stalkbliz链接吗?
  • @ConnorsFan 好的,现在我不再划分它,但我仍然将它乘以 1000。我仍然得到错误的日期。如果我删除 * 1000,我会收到错误 RangeError: Invalid time value
  • @piyushjain 我已经更新了我的问题,你会看到一个指向 stackblitz 的链接。这不是我自己的代码,但问题可能是一样的。
  • 您可以尝试+timestamp,而不是timestamp * 1000,以避免出现异常,同时保持相同的日期/时间值。

标签: angular datepicker timestamp


【解决方案1】:

根据您所在的地区,五月属于夏令时。

如果您保留时区,则将日期设置为 1985 年 5 月 1 日应显示为 1985-05-01T00:00.000+1:00。

看起来正在发生的事情是您正在以 UTC 格式提取日期。这会将日期转换为 +0:00,从而将您带到1985-04-30T23:00.000+0.00 的前一天。

如果您尝试 Stackblitz,问题就得到了证明 - 选择 3 月底之前和 10 月底之后的日期 - 这些日期可以正常工作,因为它们不是夏令时。

您的格式日期函数使用.toISOString() 提取日期。根据 Mozzila (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) 的说法,这将始终返回 UTC 时间,并且您的日期会晚一小时,因为现在是午夜,所以它会回到前一天。

由于您只关心日期,并且日期选择器可能会以每种方式抵消最多 12 小时,我们可以检查这一点。

默认日期始终是午夜,因此在 UTC 之前的任何时间都可以,因为它将保持相同的日期。任何落后于 UTC 的时间都可以追溯到 12 小时,并一直持续到第二天。

在代码中,检查时区偏移会告诉我们是否落后。如果是这样,那么我们希望将小时数添加到 datetime 对象中,这样当我们使用 toISOString 时,我们仍然可以选择日期。

所以函数应该如下:

const date = new Date(+timestamp);
const offset = date.getTimezoneOffset();
if (offset < 0) {
    date.setHours(12,0,0);
}
return date.toISOString().substring(0,10);

【讨论】:

  • 感谢您的回答。我已经尝试过了,但现在结果是 1985-04-01。
  • 更新了答案。旧代码依赖于我们当前不同的时区。正确计算是一件很糟糕的事情。
  • 效果很好。正是我想要的。非常感谢!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-06
  • 1970-01-01
  • 2015-06-04
  • 2012-12-11
  • 1970-01-01
  • 2021-05-17
相关资源
最近更新 更多