Angular:日期时区全局参数设置

5

我正在寻找一种方法来

  • Convert all-new Dates upon construction/declaration to Pacific Standard time. (Without every developer in team manually setting the timezone)

  • Additionally, dates displayed should be showed in Pacific Timezone when displaying in HTML, console.log, etc

    let test = new Date(2019, 3, 5);
    console.log(test);
    
这怎么做呢?Angular 里有全局参数可以设置吗?也许在配置文件中?
我们的代码库中有500行日期代码需要进行全局转换。有时候,当人们在不同的时区工作时,应用程序会呈现不同的时区日期。需要更正之前人的代码。
目前无法将这些行转换为 Moment,在当前的代码库中使用 Date。
另外,这是否是一个适当的解决方案?刚刚在 Google 上了解到 tzutil /s "Pacific Standard Time"

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


这个链接有帮助吗? - sharp
嗨@arcticwhite,我需要更新500行代码,尽可能地寻找一种全局的方法。 - user12425844
嗨@AdeshKumar,目前我们正在使用Date,尚未转换为Moment。 - user12425844
实际上,日期完全依赖于机器。 - Adesh Kumar
你尝试过覆盖日期构造函数吗?(可能在index.html中) https://dev59.com/fWox5IYBdhLWcg3w3YD-:~:text=%2F%2F%20create%20a%20date%20object%20for%20this%20Friday%3A%20var%20d%2C%20now%20%3D%20new%20Date()%20console. - LogicBlower
显示剩余2条评论
5个回答

5
我完全同意 @Adrian Brand 的观点。同时,这不是一个 Angular 问题,更像是关于如何处理应用程序中的日期时间。
从我的经验来看,使用 JavaScript 内置的 Date 对象进行日期时间处理总是比较棘手的。
此外,要处理太平洋时间,您可能需要考虑夏令时,这又是另一个独立的问题。
引用:
太平洋时区(PT)是一个跨越加拿大西部,美国西部和墨西哥西部部分地区的时区。该地区通过将协调世界时减去8小时来观察标准时间(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。因为新加坡位于UTC+08:00,比协调世界时间提前8小时。
所以,如果您希望始终使用 PST 时间创建新的 Date 对象,即:
  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 在 UTC-08:00,比协调世界时间晚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的时间。我认为你可能需要考虑这个因素,因为如果你的应用程序不断发展,修复这种问题将变得更加困难。

我在我的博客中写了如何处理时区和语言环境。在我的使用例子中,我使用moment.js,同时服务器端也需要支持我这么做。如果你想要更多的想法,可以看一下我的博客。


嗨,这个行得通吗?刚学习到这个,tzutil /s "太平洋标准时间",在谷歌上。 - user12425844
我不知道它如何适用于您的用例。这只是我的想法,没有进行任何实际测试 :) - trungk18

3

与日期打交道可能会让你发疯。在客户端处理日期的最大问题是你必须依赖于客户机正确设置日期、时间和时区。最好始终在服务器上创建日期,这样你可以控制时钟。

拥有一个返回日期的API端点是最可靠的选择。即使需要往返一次服务器也非常值得。


那么可能就没有解决方案了吗?有全局参数吗?谢谢。 - user12425844
你已经说过你不想使用moment,虽然这是你最简单的客户端解决方案,但你仍然依赖于客户机器上准确的时钟。一个解决方案是将客户端日期转换为UTC,然后应用太平洋时区偏移量。这将给你太平洋时区的日期,但只有在客户端时钟设置正确时才有用。如果仅用于不重要的显示目的,则可能可以接受,但任何像创建订单之类的事情都必须使用服务器时间,否则您无法信任它。 - Adrian Brand
1
@Artportraitdesign1,这解决了你的问题吗?https://dev59.com/4WYr5IYBdhLWcg3wOXsQ - user12504785
你好,这个行得通吗?刚学到了这个,在谷歌上看到的 tzutil /s "Pacific Standard Time"。 - user12425844

1
这应该可以解决。
传入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
}

0
在我的情况下,我添加了UTC,如下所示: this.tM01CNKD.signDate = new Date(this.tM01CNKD.signDate +'UTC') 这样就可以工作了。

1
目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community

0

最好使用ISO 8601格式的日期和时间。请看看为什么以及使用ISO-8601日期格式有哪些好处。https://www.iso.org/iso-8601-date-and-time-format.html

完整文章在这里 在Angular中实现ISO 8601日期时间格式

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;
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接