【问题标题】:Angular Material 2 (MatDatepickerModule) - The date selected in the date picker is off by 1 dayAngular Material 2 (MatDatepickerModule) - 在日期选择器中选择的日期关闭了 1 天
【发布时间】:2018-03-08 04:38:22
【问题描述】:

我正在使用 Angular Material Beta 11 版本开发 Angular 应用程序 (v4.4.3)。在 beta 11 中,日期选择器接受 ISOformat 字符串中的日期。但是,在我的应用中,日期选择器模块中的日期相差 1 天,如下图所示:

我的应用程序中的日期流程如下,应用程序从 Mysql 数据库接收 Unix 纪元时间的日期,我将该纪元时间日期转换为 ISOString 字符串格式并将该 ISO 日期返回给 matDatePicker。

/**
 * This method takes the key, which is a epoch time in string format and convert into JS Date object.
 * @param key {string} - the epoch time
 * @return {string} - Date Object.
 */
private static dateHelper(key: string): any {
    const dateObj = new Date(+key * 1000);
    // Need to return ISOString format date as accepted by Material DatePicker component
    return dateObj.toISOString().substring(0, 10);

}

我还有日期选择器模块,以自定义格式显示日期:

import {NgModule} from '@angular/core';
import {MdDatepickerModule, MdNativeDateModule, NativeDateAdapter, DateAdapter, MD_DATE_FORMATS} from '@angular/material';

// extend NativeDateAdapter's format method to specify the date format.
export class CustomDateAdapter extends NativeDateAdapter {
    format(date: Date, displayFormat: Object): string {
        if (displayFormat === 'input') {
            const day = date.getUTCDate();
            const month = date.getUTCMonth() + 1;
            const year = date.getFullYear();
            return `${year}-${month}-${day}`;
        } else {
            return date.toDateString();
        }
    }
}

const MY_DATE_FORMATS = {
    parse: {
        dateInput: {month: 'short', year: 'numeric', day: 'numeric'}
    },
    display: {
        dateInput: 'input',
        monthYearLabel: {year: 'numeric', month: 'short'},
        dateA11yLabel: {year: 'numeric', month: 'long', day: 'numeric'},
        monthYearA11yLabel: {year: 'numeric', month: 'long'},
    }
};

@NgModule({
    declarations: [],
    imports: [],
    exports: [MdDatepickerModule, MdNativeDateModule],
    providers: [
        {
            provide: DateAdapter, useClass: CustomDateAdapter
        },
        {
            provide: MD_DATE_FORMATS, useValue: MY_DATE_FORMATS
        }
    ]
})

export class DatePickerModule {

}

日期选择器:

    <mat-form-field>
            <input matInput
                   [matDatepicker]="myDate"
                   placeholder="Start Date"                       
                   [(ngModel)]="date"
                   name="start_date" required>
            <mat-datepicker-toggle matSuffix [for]="myDate"></mat-datepicker-toggle>
            <mat-datepicker #myDate></mat-datepicker>
            <mat-error>This field is required!</mat-error>
        </mat-form-field>

我对此进行了谷歌搜索,并且有一些与此问题相关的帖子,但我无法完全关注它们。对此的任何输入将不胜感激。谢谢!

【问题讨论】:

    标签: javascript angular typescript datepicker angular-material2


    【解决方案1】:

    如果您在自定义日期适配器的 format 方法中使用 date.getDate()date.getMonth()not date.getUTCDate()date.getUTCMonth(),它应该可以工作。

    尝试告诉我们:

    export class CustomDateAdapter extends NativeDateAdapter {
        format(date: Date, displayFormat: Object): string {
               if (displayFormat == "input") {
                   let day = date.getDate();
                   let month = date.getMonth() + 1;
                   let year = date.getFullYear();
                   return `${year}-${month}-${day}`
               } else {
                   return date.toDateString();
               }
           }
    }
    

    【讨论】:

    • 嘿Fetra...感谢您的意见。如果我这样做,那么来自自定义适配器的日期与我在另一个函数中从 Epoch 时间获得的 ISO 格式日期不同(休息 1 天)。所以为了匹配它们..我使用的是 UTC 日期。
    • @mrsan22 格式方法是在 datepicker 中选择日期后显示日期,所以我认为最适合您的是在您提到的另一个函数中使用该 iso 格式?
    • 不确定我是否明白你的意思。当我从 db 收到日期(以 Epoch 格式)格式时,我使用toISOformat 方法获取与 DatePicker 兼容的日期(它与 db 中的日期匹配),并且我可以使用此 ISO 格式日期填充 DatePicker。输入中的日期以format 方法中描述的格式正确显示,但在日历中显示为 1 天。
    【解决方案2】:

    解决了。感谢大家的投入。

    因此,在这里进行了一些讨论并浏览了 Angular Material 2 Github 问题和帖子之后,我得到了一些将 Date 分配给 DatePicker 组件的想法和方法。在 Material beta 11 中,DatePicker 组件可以采用DateISOString 格式的日期。我在使用 ISOString 格式时遇到了问题。我刚刚将其更新为正常的Date 格式,如下所示。

    我的问题中更新的代码 sn-ps:

     /**
     * This method takes the key, which is a epoch time in string format and 
     * convert into JS Date object.
     * @param key {string} - the epoch time
     * @return {string} - Date Object.
     */
    private static dateHelper(key: string): any {
        const dateObj = new Date(+key * 1000);
        // Need to return Date object/ISOString format date as accepted by Material DatePicker component
        return new Date(dateObj.getFullYear(), dateObj.getUTCMonth(), dateObj.getUTCDate());;
    
    }
    

    这是我为匹配 mdInput 中的日期和日历所做的唯一更改。当我使用ISOString 格式时,我仍然不确定问题的原因。另外,我意识到我不需要使用任何CustomDateAdapter,因为它主要用于外观目的。

    【讨论】:

      【解决方案3】:

      如果不在控制台中进行调试,某处的日期很可能会用时区表示。并且表示的时区与 UTC 相差 1 天。

      可能是 date.toDataString()。

      this

      【讨论】:

        【解决方案4】:

        我不太确定这一点,但我怀疑Date 转换的纪元时间和时区对它的影响。尝试this的方式转换DB时间。

        最有可能在这一行,

        const dateObj = new Date(+key * 1000);
        

        Date 构造函数可能会根据您的本地(系统)TZ 初始化日期,这可能会抵消 UTC 时间。

        编辑

        好的,深入一点。我想我已经找到了这个问题的原因。您可能还必须在您的CustomDateAdapter 中自定义parse() 方法,因为它实际上将给定的date (UTC) 转换为本地时间(区域)日期,根据this 内置parse() 方法。

        尝试在您的 CustomDateAdapter 中添加一些效果,

        parse(value: any): Date | null {
         if (typeof value == 'number') {
          return new Date(value); // not likely to enter here as your date is in 'string' format
         }
         return value ? new Date(Date.parse(value + ' GMT')) : null; //forces Time Zone to GMT/UTC and converts it
        }
        

        看看它是否能解决你的问题。

        【讨论】:

        • 嘿@amal..感谢您的意见。我尝试了您提到的方法,但是,我仍然遇到同样的问题。我读过一些相关的问题,人们也提到过时区,但我不确定..时区影响是如何以及在哪里发生的。
        • 更新了我的答案,看看是否对你有任何启示。至少尝试 console.log 两种情况,看看它们是否不同。尝试使用new Date(+key * 1000); 和其他new Date(Date.UTC(+key * 1000));
        • 嘿Amal..我会试试这个,让你知道。
        • Date.UTC() 不占用 Epoch 时间。此外,DateAdapter 的 format 方法提供了正确的日期,因为 mdInput 中的日期已正确填充,它是日历关闭了 1 天。
        • 能否请您也添加相应的组件代码。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-07-23
        • 2019-09-28
        • 1970-01-01
        • 1970-01-01
        • 2018-07-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多