首页
Preview

JavaScript 中处理时区的方法

最近,我在我的团队管理的 JavaScript 日历库 TOAST UI Calendar 上工作,为其添加时区功能。我非常清楚 JavaScript 中的时区支持相当有限,但我希望通过抽象现有数据对象来轻松解决许多问题。

然而,我的希望是错的,随着进一步的进展,我发现在 JavaScript 中处理时区非常困难。实现超出简单时间格式化和使用复杂操作计算时间数据(例如日历)的时区功能是一项真正艰巨的任务。因此,我有了解决问题并导致更多问题的宝贵而激动人心的经验。

本文的目的是讨论使用 JavaScript 实现时区功能时涉及的问题和解决方案。在撰写这篇相当长的文章时,我突然意识到我的问题根源在于我对时区领域的理解不足。因此,我将首先详细讨论与时区相关的定义和标准,然后再谈论 JavaScript。

什么是时区?

时区是遵循国家合法规定的统一本地时间的地区。许多国家拥有其独特的时区,一些大国,例如美国或加拿大,甚至拥有多个时区。有趣的是,尽管中国足够大,可以拥有多个时区,但她只使用一个时区。这有时会导致一个尴尬的情况,即在中国西部地区太阳在上午10:00升起。

GMT、UTC 和偏移量

GMT

韩国的本地时间通常为 GMT +09:00。GMT 是 Greenwich Mean Time(格林威治标准时间)的缩写,它是位于经度0的英国格林威治皇家天文台的时钟时间。GMT 系统开始在1925年2月5日传播,并一直成为世界时间标准,直到1972年1月1日。

UTC

许多人认为 GMT 和 UTC 是相同的东西,并且在许多情况下可以互换使用,但它们实际上是不同的。UTC 在1972年建立,以弥补地球自转速度减缓的问题。这个时间系统基于国际原子时间,使用铯原子频率来设置时间标准。换句话说,UTC 是 GMT 的更精确的替代系统。尽管两者之间的实际时间差异微小,但对于软件开发人员来说,UTC 是更准确的选择。

当该系统仍在开发中时,英语国家想将该系统命名为 CUT(协调世界时),而法语国家想将其命名为 TUC(世界协调时间)。然而,两边都没有赢得这场斗争,所以他们达成了使用 UTC 的协议,因为它包含了所有必要的字母(C、T 和 U)。

偏移量

UTC+09:00 中的 +09:00 表示当地时间比 UTC 标准时间快9个小时。 这意味着当 UTC 地区是下午12:00时,韩国是晚上9:00。UTC 标准时间和当地时间之间的时间差称为“偏移量”,用这种方式表示:+09:00-03:00等。

许多国家通常使用其自己的独特名称命名其时区。例如,韩国的时区称为 KST(Korea Standard Time),并具有特定的偏移值,其表示为 KST = UTC+09:00。然而,+09:00 偏移量不仅被韩国使用,还被日本、印度尼西亚和许多其他国家使用,这意味着偏移量和时区名称之间的关系不是 1:1,而是 1:N。 +09:00 偏移量中国家的列表可以在 UTC+09:00 中找到。

一些偏移量不是严格按小时计算的。例如,朝鲜使用 +08:30 作为其标准时间,而澳大利亚根据地区使用 +08:45+09:30

完整的 UTC 偏移量及其名称列表可以在 UTC 时间偏移列表 中找到。

时区!= 偏移量?

正如我之前提到的,我们使用时区名称(KST、JST)和偏移量互换使用,而不加以区分。但是,由于以下原因,将某个地区的时间和偏移量视为相同是不正确的:

夏令时(DST)

虽然这个术语对一些国家来说可能不太熟悉,但世界上许多国家采用了夏令时。 “夏令时”是英国和其他欧洲国家最常用的术语。在国际上,通常称为夏令时(DST)。这意味着在夏季期间将时钟推进一个小时的标准时间。

例如,美国加利福尼亚州在冬季使用太平洋标准时间(PST),夏季使用太平洋夏令时(PDT,UTC-07:00)。使用这两个时区的地区统称为太平洋时间(PT),这个名称被美国和加拿大的许多地区采用。

然后,下一个问题是夏天开始和结束的确切时间。实际上,DST 的开始和结束日期各不相同,因国家而异。例如,在美国和加拿大,DST 曾经是从每年 4 月第一个星期日的上午 02:00 到每年 10 月最后一个星期日的上午 12:00,但自 2007 年以来,DST 从每年 3 月第二个星期日的上午 02:00 开始,到每年 11 月第一个星期日的上午 02:00 结束。在欧洲,夏令时在国家范围内统一适用,而 DST 则逐步应用于各个时区的州。

时区会改变吗?

正如我之前简要提到的,每个国家都有权确定使用哪个时区,这意味着其时区可能会因任何政治和/或经济原因而改变。例如,在美国,DST 的期限在 2007 年因乔治·布什总统签署的 2005 年能源政策而改变。埃及和俄罗斯曾经使用 DST,但自 2011 年以来已停止使用。

在某些情况下,一个国家不仅可以更改其 DST,还可以更改其标准时间。例如,萨摩亚曾经使用 UTC-10:00 偏移量,但后来改为 UTC+14:00 偏移量,以减少萨摩亚和澳大利亚和新西兰之间的时差造成的贸易损失。这个决定导致该国错过了 2011 年 12 月 30 日的整个一天,并且这个消息登上了全球各地的报纸。荷兰曾经使用+0:19:32.13的偏移量,这种精度在1909年以后就没有必要了,但是在1937年改为了+00:20的偏移量,然后在1940年又改为了+01:00的偏移量,一直沿用至今。

时区1: 偏移量N

总的来说,一个时区可以有一个或多个偏移量。一个国家在某个时刻使用哪个偏移量作为标准时间可能会因为政治或经济原因而发生变化。在日常生活中这不是一个大问题,但是在尝试根据规则对其进行系统化时就会变得非常重要。想象一下,如果你想为你的智能手机使用一个偏移量来设置标准时间,如果你生活在一个应用了夏令时的地区,那么当夏令时开始和结束时,你的智能手机时间应该进行调整。在这种情况下,你需要一个将标准时间和夏令时结合在一起的概念来表示一个时区(例如太平洋时间)。

但是这并不能仅通过一些简单的规则就实现。例如,由于各州在2007年改变了夏令时开始和结束的日期,所以2006年5月31日应该使用PDT(-07:00)作为标准时间,而2007年3月31日应该使用PST(-08:00)作为标准时间。这意味着要想表示特定的时区,你必须了解所有标准时间区或夏令时规则变化的历史数据或变化时间点。

你不能简单地说,“纽约的时区是PST(-08:00)。”你必须更具体地说,“纽约当前使用PST作为标准时间”。然而,出于系统实现的考虑,我们需要更准确的表达方式。忘掉“时区”这个词吧。你需要说,“纽约当前使用PST作为其标准时间”。

那么除了偏移量,我们应该使用什么来指定特定区域的时区呢?答案是该地区的名称。更具体地说,你应该将夏令时或标准时间区的变化被统一应用的区域分组为一个时区,并根据需要进行引用。你可能能够使用像PT(太平洋时间)这样的名称,但是这样的术语只结合了当前标准时间和其夏令时,不一定包含所有历史变化。此外,由于PT目前仅在美国和加拿大使用,因此你需要更加信任的组织制定更加稳定的标准,以便在全球范围内使用软件。

IANA时区数据库

事实上,时区更像是一个数据库,而不是一组规则,因为它们必须包含所有相关的历史变化。有几个标准数据库专门处理时区问题,最常用的是IANA时区数据库。通常称为tz数据库(或tzdata),IANA时区数据库包含了全球各地本地标准时间和夏令时变化的历史数据。该数据库的组织方式是包含所有当前可验证的历史数据,以确保自Unix时间(1970.01/01 00:00:00)以来的时间准确性。虽然它也有1970年以前的数据,但准确性不能保证。

命名约定遵循区域/位置规则。区域通常指大陆或海洋的名称(亚洲、美洲、太平洋),而位置指的是主要城市的名称,例如首尔和纽约,而不是国家的名称(这是因为一个国家的寿命远远比一个城市的寿命短)。例如,韩国的时区是Asia/Seoul,日本的时区是Asia/Tokyo。虽然这两个国家共享相同的UTC+09:00,但是两个国家在时区方面的历史是不同的。这就是为什么这两个国家使用单独的时区进行处理。

IANA时区数据库由众多开发者和历史学家社区管理。新发现的历史事实和政府政策会立即更新到数据库中,使其成为最可靠的信息来源。此外,许多基于UNIX的操作系统,包括Linux和macOS,以及流行的编程语言,包括Java和PHP,都在内部使用此数据库。

注意,Windows不在上述支持列表中。这是因为Windows使用自己的数据库,称为Microsoft时区数据库。然而,这个数据库并没有准确反映历史变化,而且只由微软管理。因此,它比IANA不够准确和可靠。

JavaScript和IANA时区数据库

正如我之前简要提到的,JavaScript的时区功能相当差。由于它默认遵循地区的时区(更具体地说,是在安装操作系统时选择的时区),所以没有办法将其更改为新的时区。此外,它的数据库标准规范甚至不是很清楚,如果你仔细查看ES2015的规范,你会发现这一点。关于本地时区和夏令时可用性,只有几个模糊的声明。例如,夏令时定义如下:ECMAScript 2015 — Daylight Saving Time Adjustment

使用最佳可用的时区信息的实现相关算法来确定本地夏令时调整DaylightSavingTA(t),以毫秒为单位测量。ECMAScript的实现应尽最大努力确定本地夏令时调整。

看起来它只是说,“嘿,伙计们,试一试,尽力让它工作吧。”这在浏览器供应商之间留下了兼容性问题。你可能会认为“这很草率!”,但接下来你会注意到另一行:

注意:建议实现使用IANA时区数据库的时区信息http://www.iana.org/time-zones/。

是的。ECMA规范用这个简单的建议将球扔给了你,JavaScript没有为你准备特定的标准数据库。因此,不同的浏览器使用自己的时区操作进行时区计算,它们通常不兼容。ECMA规范后来在ECMA-402 Intl.DateTimeFormat中添加了使用IANA时区的选项,以进行国际API。然而,这个选项仍然比其他编程语言的选项不可靠得多。# 服务器客户端环境中的时区

我们假设一个简单的场景,需要考虑时区。假设我们要开发一个简单的日历应用程序来处理时间信息。当用户在客户端环境的注册页面上输入日期和时间时,数据被传输到服务器并存储在数据库中。然后客户端从服务器接收已注册的日程数据并在屏幕上显示它。

但这里需要考虑一些问题。如果访问服务器的某些客户端处于不同的时区怎么办?在首尔注册的一个日程,例如 2017 年 3 月 11 日上午 11:30,当在纽约查看该日程时,它应该显示为 2017 年 3 月 10 日晚上 9:30。为了支持来自各个时区的客户端,服务器中存储的日程必须具有不受时区影响的绝对值。每个服务器都有不同的存储绝对值的方式,这超出了本文的范围,因为它完全取决于服务器或数据库环境。但是为了使其工作,从客户端传输到服务器的日期和时间必须是基于相同偏移量(通常是 UTC)的值,或者也包括客户端环境的时区数据。

这种类型的数据通常以基于 UTC 的 Unix 时间或包含偏移信息的 ISO-8601 格式的字符串形式传输。在上面的例子中,如果要将首尔的 2017 年 3 月 11 日上午 11:30 转换为 Unix 时间,则它将是一个整数类型,其值为 1489199400。在 ISO-8601 下,它将是一个字符串类型,其值为 2017–03–11T11:30:00+09:00

如果你在浏览器环境下使用 JavaScript 进行处理,你必须按照上述方式转换输入的值,然后将其转换回适合用户所在时区的时间。这两个任务都必须考虑到。从编程语言的角度来看,前者称为“解析”,后者称为“格式化”。现在让我们来看看 JavaScript 中如何处理这些任务。

即使在使用 Node.js 进行 JavaScript 服务器环境的开发时,你可能也需要根据情况解析从客户端检索到的数据。然而,由于服务器通常将其时区与数据库同步,并且格式化的任务通常留给客户端,因此你需要考虑的因素比浏览器环境中少得多。在本文中,我的解释将基于浏览器环境。

JavaScript 中的 Date 对象

在 JavaScript 中,涉及日期或时间的任务是使用 Date 对象处理的。它是 ECMAScript 中定义的本机对象,如 ArrayFunction 一样。它在本机代码(如 C++)中大多数实现。它的 API 在 MDN 文档 中有很好的描述。它受 Java 的 java.util.Date 类的影响很大。因此,它继承了一些不良特征,例如可变数据的特性和以 0 开始的 month

JavaScript 的 Date 对象在内部使用绝对值(如 Unix 时间)来管理时间数据。但是,构造函数和方法(如 parse() 函数、getHour()setHour() 等)受客户端本地时区的影响(确切地说是运行浏览器的操作系统的时区)。因此,如果你直接使用用户输入数据创建 Date 对象,则数据将直接反映客户端的本地时区。

正如我之前提到的,JavaScript 不提供任何任意更改时区的方法。因此,在此假设可以直接使用浏览器的时区设置。

使用用户输入创建 Date 对象

让我们回到第一个例子。假设用户在遵循首尔时区的设备中输入了 2017 年 3 月 11 日上午 11:30。这些数据存储在 5 个整数中,分别代表年、月、日、小时和分钟。 (由于月份从 0 开始,值必须是 3-1=2)。使用构造函数,你可以轻松地使用数值创建 Date 对象。

const d1 = new Date(2017, 2, 11, 11, 30);
console.log(d1.toString()); // Sat Mar 11 2017 11:30:00 GMT+0900 (KST)

如果查看 d1.toString() 返回的值,你将知道所创建的对象的绝对值是基于偏移量 +09:00(KST)的 2017 年 3 月 11 日上午 11:30。

你也可以将构造函数与字符串数据一起使用。如果将字符串值用于 Date 对象,则它会在内部调用 Date.parse() 并计算出正确的值。此函数支持 RFC2888 规范和 ISO-8601 规范。但是,如 MDN 的 Date.parse() 文档 中所述,此方法的返回值因浏览器而异,字符串类型的格式会影响准确值的预测。因此,建议不要使用此方法。

例如,类似于 2015–10–12 12:00:00 的字符串在 Safari 和 Internet Explorer 上返回 NaN,而在 Chrome 和 Firefox 上返回本地时区。在某些情况下,它返回基于 UTC 标准的值。

使用服务器数据创建 Date 对象

现在假设你要从服务器接收数据。如果数据是数字 Unix 时间值,则可以简单地使用构造函数创建 Date 对象。虽然我之前跳过了解释,但是当 Date 构造函数接收一个值作为唯一参数时,它被视为毫秒的 Unix 时间值。 (注意:JavaScript 在毫秒级别处理 Unix 时间。这意味着第二个值必须乘以 1,000)。如果你看下面的示例,结果值与上一个示例相同。

const d1 = new Date(1489199400000);
console.log(d1.toString()); // Sat Mar 11 2017 11:30:00 GMT+0900 (KST)

那么,如果使用 ISO-8601 等字符串类型而不是 Unix 时间呢?如我在上一段中所解释的,Date.parse() 方法不可靠,最好不要使用。但是,自 ECMAScript 5 或更高版本规定支持 ISO-8601 以来,如果小心使用,你可以在支持 ECMAScript 5 的 Internet Explorer 9.0 或更高版本上使用 ISO-8601 指定的格式的字符串为 Date 构造函数。如果你使用的是旧版本的浏览器,请确保在末尾保留 Z 字母。如果没有它,旧浏览器有时会根据本地时间而不是 UTC 进行解释。以下是在 Internet Explorer 10 上运行它的示例。

const d1 = new Date('2017-03-11T11:30:00+09:00');
console.log(d1.toString()); // Sat Mar 11 2017 11:30:00 GMT+0900 (KST)

根据规范,两种情况的结果值应该相同。但是,如你所见,d1.toString()d2.toString() 的结果值不同。在最新的浏览器上,这两个值将相同。为了防止这种版本问题,如果没有时区数据,请始终在字符串末尾添加 Z。# 创建要传输到服务器的数据

现在可以使用先前创建的 Date 对象,并且你可以自由地根据本地时区添加或减去时间。但在传输回服务器之前,在处理结束时不要忘记将数据转换回先前的格式。

如果是 Unix 时间,可以简单地使用 getTime() 方法执行此操作。(注意使用毫秒。)

const d1 = new Date(2017, 2, 11, 11, 30);
d1.getTime(); // 1489199400000

那么 ISO-8601 格式的字符串呢?正如前面所述,支持 ECMAScript 5 或更高版本的 Internet Explorer 9.0 或更高版本支持 ISO-8601 格式。你可以使用 toISOString()toJSON() 方法创建 ISO-8601 格式的字符串。(toJSON() 可用于与 JSON.stringify() 或其他方法的递归调用。)这两种方法产生的结果相同,除非处理无效数据的情况。

const d1 = new Date(2017, 2, 11, 11, 30);
d1.toISOString(); // "2017-03-11T02:30:00.000Z"
d1.toJSON();      // "2017-03-11T02:30:00.000Z"

const d2 = new Date('Hello');
d2.toISOString(); // Error: Invalid Date
d2.toJSON();      // null

你还可以使用 toGMTString()toUTCString() 方法创建 UTC 字符串。由于它们返回满足 RFC-1123 标准的字符串,因此可以根据需要利用它们。

Date 对象包括 toString()toLocaleString() 及其扩展方法。但是,由于这些方法主要用于根据本地时区返回字符串,并且根据使用的浏览器和操作系统返回不同的值,因此它们并不真正有用。

更改本地时区

现在可以看到 JavaScript 对时区提供了一些支持。如果你想在应用程序中更改本地时区设置,而不遵循操作系统的时区设置,该怎么办?或者,如果你需要在单个应用程序中同时显示多种时区,该怎么办?正如我多次所说,JavaScript 不允许手动更改本地时区。唯一的解决方案是根据已知的时区偏移值添加或删除日期提供的偏移值。但别沮丧,我们来看看是否有任何解决方法。

让我们继续使用之前的示例,假设浏览器的时区设置为首尔。用户根据首尔时间输入 2017 年 3 月 11 日上午 11:30,并希望在纽约的本地时间中查看它。服务器以毫秒为单位传输 Unix 时间数据,并通知纽约的偏移值为 -05:00。然后,如果你只知道本地时区的偏移值,就可以转换数据。

在这种情况下,可以使用 getTimeZoneOffset() 方法。这是 JavaScript 中唯一可用于获取本地时区信息的 API。它返回当前时区的偏移值(以分钟为单位)。

const seoul = new Date(1489199400000);
seoul.getTimeZoneOffset(); // -540

返回值为 -540 表示时区比目标提前 540 分钟。请注意,值前面的减号与首尔的加号(+09:00)相反。我不知道为什么,但是它就是这样显示的。如果我们使用此方法计算纽约的偏移量,我们将得到 60 * 5 = 300。将 840 的差异转换为毫秒并创建一个新的 Date 对象。然后,可以使用该对象的 getXX 方法将值转换为所需的格式。让我们创建一个简单的格式化程序函数来比较结果。

function formatDate(date) {
  return date.getFullYear() + '/' + 
    (date.getMonth() + 1) + '/' + 
    date.getDate() + ' ' + 
    date.getHours() + ':' + 
    date.getMinutes();
}

const seoul = new Date(1489199400000);
const ny = new Date(1489199400000 - (840 * 60 * 1000));

formatDate(seoul);  // 2017/3/11 11:30
formatDate(ny);     // 2017/3/10 21:30

formatDate() 根据首尔和纽约之间的时区差异显示正确的日期和时间。看起来我们找到了一个简单的解决方案。那么,如果我们知道该地区的偏移量,是否可以将其转换为本地时区?不幸的是,答案是“否”。还记得我之前说过的吗?时区数据是一种包含所有偏移更改历史的数据库吗?要获取正确的时区值,必须知道日期的偏移值(而不是当前日期)。

转换本地时区的问题

如果你继续使用上面的示例,很快就会面临一个问题。用户想要在纽约当地时间检查时间,然后将日期从 10 日更改为 15 日。如果使用 Date 对象的 setDate() 方法,可以在保留其他值不变的情况下更改日期。

ny.setDate(15);
formatDate(ny);   // 2017/3/15 21:30

看起来很简单,但是这里有一个隐藏的陷阱。如果你必须将此数据传输回服务器,该怎么办?由于数据已更改,因此无法使用 getTime()getISOString() 等方法。因此,在发送回服务器之前,必须将转换恢复原状。

const time = ny.getTime() + (840 * 60 * 1000);  // 1489631400000

有些人可能会想,既然我必须在返回之前将其转换回来,为什么不在格式化时直接处理它而临时创建一个转换后的 Date 对象呢?但是,这并不是它看起来的那样。如果你从首尔时间更改日期从 11 日到 15 日的 Date 对象,则会添加 4 天(24 * 4 * 60 * 60 * 1000)。但是,在纽约当地时间中,由于日期已从 10 日更改为 15 日,结果添加了 5 天(24 * 5 * 60 * 60 * 1000)。这意味着必须根据本地偏移量计算日期以获得精确的结果。

问题并没有止步于此。还有另一个问题等待着你,即仅通过添加或减去偏移量无法获得所需的值。由于 2017 年 3 月 12 日是纽约当地时间的夏令时起始日期,因此 2017 年 3 月 15 日的偏移量应为 -04:00 而不是 -05:00。因此,在恢复转换时,应添加 780 分钟,比以前少 60 分钟。

const time = ny.getTime() + (780 * 60 * 1000);  // 1489627800000

相反,如果用户的本地时区是纽约,并想要知道首尔的时间,则会不必要地应用夏令时,导致另一个问题。

简而言之,仅凭获得的偏移量无法根据所选时区执行精确操作。如果你回顾一下我们在本文早期讨论的内容,就会很容易知道,如果你知道夏令时规则,则此转换仍存在问题。要获得精确值,你需要包含整个偏移更改历史记录的数据库,例如 IANA 时区数据库。为了解决这个问题,必须存储整个时区数据库,每当从 Date 对象中检索到日期或时间数据时,找到日期和相应的偏移量,然后使用上述过程进行转换。理论上,这是可能的。但在现实中,这需要太多的工作,测试转换后的数据的完整性也会很困难。但是别失望。直到现在,我们讨论了 JavaScript 的一些问题以及如何解决它们。现在我们可以使用一个良好构建的库。

Moment Timezone

Moment 是一个成熟的 JavaScript 库,几乎是处理日期的标准。提供各种日期和格式化 API,最近被许多用户认为是稳定和可靠的。还有一个扩展模块,Moment Timezone,解决了上述所有问题。该扩展模块包含 IANA 时区数据库的数据,以准确计算偏移量,并提供多种可用于更改和格式化时区的 API。

在本文中,我不会详细讨论如何使用库或库的结构。我只会向你展示如何简单地解决我之前讨论的问题。如果有人感兴趣,请参见 Moment Timezone 文档

让我们使用 Moment Timezone 解决图片中显示的问题。

const seoul = moment(1489199400000).tz('Asia/Seoul');
const ny = moment(1489199400000).tz('America/New_York');

seoul.format(); // 2017-03-11T11:30:00+09:00
ny.format();    // 2017-03-10T21:30:00-05:00

seoul.date(15).format();  // 2017-03-15T11:30:00+09:00
ny.date(15).format();     // 2017-03-15T21:30:00-04:00

如果你看到结果,seoul 的偏移量保持不变,而 ny 的偏移量已从 -05:00 更改为 -04:00。如果使用 format() 函数,可以获得一个字符串,其中包含准确应用偏移量的 ISO-8601 格式。相对于我之前解释的内容,你将看到它是多么简单。

结论

到目前为止,我们讨论了 JavaScript 支持的时区 API 及其问题。如果你不需要手动更改本地时区,则即使使用 Internet Explorer 9 或更高版本,也可以使用基本 API 实现所需功能。但是,如果你需要手动更改本地时区,则事情变得非常复杂。在没有夏令时且时区政策很少更改的地区,可以使用 getTimezoneOffset() 转换数据的部分实现。但是,如果你需要完整的时区支持,请勿从头开始实现它。而是使用像 Moment Timezone 这样的库。

我曾经试图自己实现时区,但失败了,这并不令人惊讶。多次失败后,这里的结论是最好“使用库”。当我开始写这篇文章时,我不知道我将写出什么结论,但是现在我有了。作为结论,我想说,盲目使用外部库而不知道它们在 JavaScript 中支持哪些功能以及它们有什么问题,这并不是一个推荐的方法。始终重要的是为自己的情况选择正确的工具。我希望本文能帮助你确定自己的正确决策。

参考文献

译自:https://toastui.medium.com/handling-time-zone-in-javascript-547e67aa842d

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
一个人玩
先找到想要的,然后出发

评论(0)

添加评论