【问题标题】:Angular: Date Timezone Global parameter settingAngular:日期时区全局参数设置
【发布时间】:2023-11-27 20:17:01
【问题描述】:

我正在寻找一种方法

  • 将全新的建造/申报日期转换为太平洋标准时间。 (无需团队中的每个开发人员手动设置时区)

  • 此外,当以 HTML、console.log 等显示时,显示的日期应以太平洋时区显示

    let test = new Date(2019, 3, 5);
    console.log(test);
    

如何做到这一点? Angular 中是否有一个全局参数来设置它,也许在配置文件中?

*我们在代码库中有 500 行日期代码,需要进行全局转换。有时当人们在不同的时区工作时,应用程序会呈现不同的时区日期。需要更正以前人的代码。

目前无法将这些行转换为 Moment,在当前代码库中使用 Date。

另外,这是一个合适的解决方案吗? tzutil /s "Pacific Standard Time",刚刚在google上了解到这个

https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/hh875624(v=ws.11)

【问题讨论】:

  • this 有用吗?
  • 嗨@arcticwhite我必须用这个更新500行代码,如果可能的话,试图找到一种全局方式
  • 可以使用 moment 设置全球时区
  • 嗨 @AdeshKumar 目前我们正在使用 Date,并且尚未转换为 Moment

标签: javascript angular typescript angular8 angular9


【解决方案1】:

我完全同意@Adrian Brand 的观点。此外,这不是 Angular 问题。这更像是您在应用程序中处理日期时间的方式。

根据我的经验。使用内置的 JavaScript Date 来做这些日期时间的事情总是很棘手。

此外,为了处理太平洋时间,您可能需要处理夏令时。这本身就是另一个问题。

太平洋时区 (PT) 是一个包含加拿大西部、美国西部和墨西哥西部部分地区的时区。该区域中的地点通过从协调世界时(UTC−08:00) 中减去八小时来遵守标准时间。在夏令时期间,使用UTC−07:00 的时间偏移量。

我假设您仍然将数据以ISO 格式发送到服务器。


所以我在新加坡,请看下面的普通 Date 构造函数的结果。

  1. var date = new Date(2019, 3, 5)。 //Fri Apr 05 2019 00:00:00 GMT+0800 (Singapore Standard Time)
  2. date.toISOString() //2019-04-04T16:00:00.000Z。因为新加坡位于+08:00,比世界标准时间早 8 小时。

因此,如果您希望始终执行 new Date 以导致 PST 时间,这意味着

  1. var date = new Date(2019, 3, 5) // Fri Apr 05 2019 00:00:00 GMT-0700 (Pacific Standard Time)
  2. date.toISOString() //2019-04-05T08:00:00.000Z。因为 PST 位于 -08:00,比 UTC 晚 8 小时。 -07:00的夏令时话题,留给你吧。

你要么需要

  1. 重写 Date 构造函数,完全不推荐。
  2. 向 Date 构造添加新方法以显示或为您提供正确的 ISO 格式,但请考虑 PST 时区。这涉及一些字符串替换和一些用于偏移计算的数学。

添加在 PST 中显示字符串的方法

如果您使用var date = new Date(2019, 3, 5) 的确切日期执行构造函数。您只需添加一个新方法调用toPSTString() 并使用正则表达式将() 中的文本替换为Pacific Standard Time 并将GMT+xxx 替换为GMT-08:00,因为日期的值是绝对的。

Date.prototype.toPSTString = function () {
  let date = this.toString();
  //date.replace.... easy part, you could use Regex to do it
  return date;
};

但是,如果您在构造函数中传递了 ISO 字符串格式的日期或毫秒数。处理起来会非常棘手。比如你做new Date("2019-04-05T07:00:00.000Z"),你想看什么?

请参阅下文,了解如何根据偏移差异输出 ISO 字符串。它可能会给你一些想法/

添加一个方法来获取考虑 PST -08:00 时区的 ISO 格式的字符串

new Date 将始终在您的本地机器时区工作。所以如果我在新加坡,我会选择new Date(2019, 3, 5).toISOString(),它总是会给我2019-04-04T16:00:00.000Z,而不是你所期望的2019-04-05T08:00:00.000Z

您也可以覆盖 JS 函数以输出 UTC 日期,但要考虑 PST 时间。

Date.prototype.toPSTString = function () {
  function convertMinuteToMillisecond(mins) {
    return mins * 60 * 1000;
  }
  let localDateOffsetToUtc = this.getTimezoneOffset(); //the offset between the user local timezone with UTC. In my use case of Singapore, it give me -480.
  const offSetBetweenPSTAndUTC = 480;
  let offsetBetweenPSTAndLocal = offSetBetweenPSTAndUTC - localDateOffsetToUtc;
  let newDate = new Date(
    this.getTime() + convertMinuteToMillisecond(offsetBetweenPSTAndLocal)
  );
  return newDate.toISOString();
};

var date = new Date(2019, 3, 5);
date.toISOString(); //"2019-04-04T16:00:00.000Z" Singapore
date.toPSTString(); //"2019-04-05T08:00:00.000Z" PST

输出看起来正确。我还没有真正测试过,但希望你能明白。


但通常,如果您在新加坡,您希望查看新加坡时区的日期。没有人关心 PST 时区。如果您在伦敦也一样,您不想看到新加坡或 PST 时区的时间。我想你可能想考虑一下。因为如果您的应用程序正在成长,解决此类问题会变得越来越困难。

我写了我如何handle the timezone and locale in my blog。在我的用例中,我使用moment.js,而且服务器端需要支持我。如果你想了解更多,也可以去看看。

【讨论】:

  • 嗨,这行得通吗?刚刚在谷歌了解了这个, tzutil /s "Pacific Standard Time"
  • 我不知道它如何适合您的用例。它只是在没有任何实际测试的情况下从我脑海中浮现出来:)
【解决方案2】:

处理日期会让你发疯。使用日期客户端的最大问题是您必须依赖正确设置日期、时间和时区的客户端机器。你总是最好在你的服务器上创建日期,这样你就可以控制时钟。

拥有一个为您返回日期的 api 端点是最可靠的选择。往返服务器的开销非常值得。

【讨论】:

  • 那么可能没有解决方案?有一个全局参数?谢谢
  • 您已经说过您不想使用时刻,那将是您最简单的客户端解决方案,但您仍然依赖客户端计算机上的准确时钟。一种解决方案是将客户日期转换为 UTC,然后对其应用太平洋时区偏移量。这将为您提供太平洋时区的日期,但仅当客户的时钟设置正确时才有用。如果它是用于不重要的显示目的,那么它可能没问题,但是像创建订单这样的事情你必须使用服务器时间,否则你不能信任它。
  • @Artportraitdesign1 这能解决您的问题吗? *.com/questions/13854105/…
  • 嗨,这行得通吗?刚刚在谷歌了解了这个, tzutil /s "Pacific Standard Time"
【解决方案3】:

应该这样做。

传入null获取太平洋日期now,或传入任何日期以将其转换为太平洋:

pacificTimeOfDate(d:Date=null) {
  if (!d)
    d = new Date();
  var year = d.getUTCFullYear();
  var month = d.getUTCMonth();
  var day = d.getUTCDate();
  var hours = d.getUTCHours();
  var minutes = d.getUTCMinutes();
  var seconds = d.getUTCSeconds();
  var utcDate = new Date(year, month, day, hours, minutes, seconds);
  utcDate.setMinutes(utcDate.getMinutes() - 420);
  return utcDate
}

【讨论】:

    【解决方案4】:

    最好使用 ISO 8601 格式的日期时间。请查看使用 ISO-8601 日期格式的原因和好处。 https://www.iso.org/iso-8601-date-and-time-format.html

    完整的帖子在这里Implementing ISO 8601 date time format in Angular

    任何想要使用标准化方法的人都可以使用 ISO 8601 介绍:

    日期,
    一天中的时间,
    协调世界时 (UTC),
    日期和时间,
    时间间隔,
    重复的时间间隔

    您可以使用此代码以您想要的方式使用格式。我希望这会有所帮助。

    export interface HashTable<T> {
      [key: string]: T;
    }
    
    import { Injectable } from '@angular/core';
    import { HashTable } from './hash-table';
    
    type FormatFunc = (date: Date) => string;
    @Injectable({
      providedIn: 'root'
    })
    export class DateFormat {
      formattingTokenFunc: HashTable<FormatFunc> = {};
    
      private formattingTokens = /(HH?|HH?|hh?|mm?|ss?|MM?|dd?|yy?y?y?|.)/g;
    
      constructor() {
        // add years function
        const getYearFunc = (date: Date) => date.getFullYear().toString();
    
        // Year, no leading zero (e.g. 2015 would be 15)
        this.addFormatToken('y', 0, (date: Date) =>
          (date.getFullYear() % 100).toString()
        );
        this.addFormatToken('yyy', 0, getYearFunc);
        this.addFormatToken('yyyy', 0, getYearFunc);
        // Year, leading zero (e.g. 2015 would be 015)
        this.addFormatToken('yy', 3, (date: Date) =>
          (date.getFullYear() % 100).toString()
        );
    
        // add months function
        const getMonthFunc = (date: Date) => (date.getMonth() + 1).toString();
    
        this.addFormatToken('M', 0, getMonthFunc);
        this.addFormatToken('MM', 2, getMonthFunc);
    
        // add day function
        const getDayFunc = (date: Date) => date.getDate().toString();
    
        this.addFormatToken('d', 0, getDayFunc);
        this.addFormatToken('dd', 2, getDayFunc);
    
        // add hours function
        const get12HrFunc = (date: Date) => (date.getHours() % 12).toString();
    
        // 12-hour clock, with a leading 0 eg (e.g. 06)
        this.addFormatToken('hh', 2, get12HrFunc);
        // 12-hour clock hour
        this.addFormatToken('h', 0, get12HrFunc);
    
        const get24HrFunc = (date: Date) => date.getHours().toString();
    
        this.addFormatToken('HH', 2, get24HrFunc);
        this.addFormatToken('H', 0, get24HrFunc);
    
        // add minute function
        const getMinFunc = (date: Date) => date.getMinutes().toString();
        this.addFormatToken('m', 0, getMinFunc);
        // Minutes with a leading zero
        this.addFormatToken('mm', 2, getMinFunc);
    
        // add seconds function
        const getSecFunc = (date: Date) => date.getSeconds().toString();
        this.addFormatToken('s', 0, getSecFunc);
        this.addFormatToken('ss', 2, getSecFunc);
      }
    
      formatToISO8601Date(date: Date | string): string {
        return this.format(date, 'yyyy-MM-dd');
      }
    
      format(date: Date | string, format: string): string {
        const finalDate = date instanceof Date ? date : new Date(date);
    
        const matches = format.match(this.formattingTokens);
        let result = '';
    
        matches.forEach(match => {
          // const hasFunc = this.formattingTokenFunc.hasOwnProperty('match');
          const formatFunc = this.formattingTokenFunc[match];
    
          result += formatFunc ? formatFunc(finalDate) : match;
        });
    
        return result;
      }
    
      prefixZero(length: number, input: string): string {
        return `${Math.pow(10, length)}${input}`.slice(-1 * length);
      }
    
      prefixZeroFunc(length: number, formatFunc: FormatFunc): FormatFunc {
        return (c: Date) => this.prefixZero(length, formatFunc(c));
      }
    
      private addFormatToken(
        token: string,
        addZeroesLength: number,
        // formatFunc: ((date: Date) => string)
        formatFunc: FormatFunc
      ): void {
        this.formattingTokenFunc[token] =
          addZeroesLength > 0
            ? this.prefixZeroFunc(addZeroesLength, formatFunc)
            : formatFunc;
      }
    }
    

    【讨论】: