如何将 UTC 日期时间字符串转换为用户的当前时区?

Posted

技术标签:

【中文标题】如何将 UTC 日期时间字符串转换为用户的当前时区?【英文标题】:How to convert a UTC datetime string into users' current timezone? 【发布时间】:2019-09-07 06:53:38 【问题描述】:

我使用 laravel 5.7 作为 api 和 vue 作为前端。在 api 响应中,我将用户最后一次看到的时间戳记为 last_seen: "2019-04-17 05:20:37",默认情况下为 UTC 格式。

Laravel API 代码:

$user_details = array(
            'user_id' => $userId,
            'name' => $userDetails->name,
            'email' => $userDetails->email,
            'phone' => $userDetails->contact,
            'account_creation_date' => $userDetails->created_at->toDateTimeString(),
            'last_seen' => $lastSeen != null ? $lastSeen->toDateTimeString() : $userDetails->last_login->toDateTimeString(),
            'language' => 'English',
            'country' => $country->name
        );

$user_profile['user_details'] = $user_details;
return response()->api(true, 'Success', $user_profile);

这是我得到的 api 响应:

在前端,即在 vue 中,我使用 Dayjs Package 显示用户的最后一次显示为 [Day|Hours|Minutes] ago,但问题是 目标用户刚刚登录,但我知道它正在显示6 Hours ago

由于我在 Asia/Kolkata 时区,因此代码也需要 5.5/6 小时。

我也尝试使用moment.js,但我得到undefined function moment.tz.guess() 错误

这是我迄今为止尝试过的:

我将日期时间字符串传递给我的 vuejs 函数:

import dayjs from "dayjs";

convertFromNow(date) 
 return dayjs(date).fromNow();
,

然后调用这个方法打印为1 minute ago

<div class="side-box mt-4">
                  <h2 class="side-head">
                    <i class="fa fa-clock-o" />
                     convertFromNow(userInfo.user_details.last_seen) 
                    <h6 class="text-gray">
                      Last seen
                    </h6>
                  </h2>
                </div>

我需要的预期结果是,无论 UTC 时间是多少,我都应该根据我的时区获得用户的最后一次访问。

【问题讨论】:

使用moment.js有什么问题?这是一个很棒的图书馆。 @iwaduarte 使用moment.js 没有问题,但我在猜测用户的时区时出错。 另请参阅此链接以了解您的代码发生了什么。 github.com/moment/moment-timezone/issues/523 。您能否也编辑您的问题以包含您在 moment.js 中使用的代码? 为什么您的 API 返回的日期/时间字符串没有时区信息?恕我直言,日期的最佳传输格式是 ISO 8601,即2019-04-17T05:20:37Z。这使它明确并且JS可以正确解析它。在我的浏览器中,解析您的 "2019-04-17 05:20:37" 字符串会将其视为当地时间(这似乎是您的问题) 您可以使用toLocaleString()获取用户当前时间 【参考方案1】:

你也尝试使用moment.js,你需要告诉moment时间是UTC

console.log(moment.utc("2019-04-17 05:20:37").fromNow())
&lt;script src="https://momentjs.com/downloads/moment.js"&gt;&lt;/script&gt;

【讨论】:

这个答案可以解决这个问题。您应该致力于从源头上修复它 @Phil 是的,它起作用了,我根据 vue 实现了这个。 import moment from "moment";convertFromNow(date) return moment.utc(date).fromNow();`,`【参考方案2】:

我对您的问题的理解是您需要获取用户的时区(通过他们的浏览器)。我将使用 moment 的 cdn 来演示这一点。

您需要同时拥有moment.jsmoment-timezone-with-data.js

<script type="text/javascript" src="https://cdn.jsdelivr.net/momentjs/latest/moment.min.js"></script>

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.23/moment-timezone-with-data.js"></script>

然后使用这个函数:你的代码中的moment.tz.guess(); 应该给你用户的时区。

之后,您可以将获得的时区传递给您的 API,以检索该时区的正确时间。

另外,如果您使用的是 Carbon,您(可能)需要使用 setTimezone()

Carbon::parse($time)->setTimezone($tz);

其他人见:https://momentjs.com/timezone/docs/#/using-timezones/guessing-user-timezone/

【讨论】:

【参考方案3】:

这是我在 Vanilla JavaScript 中的解决方案(不依赖于外部库,例如 moment.js 或 days.js)。

诀窍是将“UTC”附加到日期字符串,然后再将其转换为 JavaScript Date 对象。

const dateString = '2019-04-17 05:20:37';
const localDate = new Date(`$dateString UTC`);
console.log(localDate)

如果您在本地浏览器 (Chrome) 控制台上运行上述代码,它应该会根据您(或您的用户)本地时区打印时间。

【讨论】:

“如果您在本地浏览器 (Chrome) 控制台上运行上述代码,它应该会根据您(或您的用户)本地时区打印时间。” - Firefox 将打印null 谢谢@wentjun,您的解决方案帮助了我:) 但让我也可以在其他浏览器中进行测试。 @Andreas 你能告诉我你的 Firefox 版本吗?我相信这只适用于“旧”的 Firefox 浏览器 @DineshSuthar 我必须添加一个免责声明,该方法可能不适用于旧版 IE 浏览器。【参考方案4】:

您的日期/时间字符串 "2019-04-17 05:20:37" 可能表示 UTC 时间,但 JavaScript 会将其解析为本地时间,这意味着时间将始终 错了。

非常简单的答案是使用明确的格式,例如 ISO 8601 / Atom,例如

"2019-04-17T05:20:37+00:00"

Carbon 提供了一种简单的方法,您可以将其替换为 toDateTimeString()

$user_details = [
    // snip
    'account_creation_date' => $userDetails->created_at->toAtomString(),
    'last_seen' => $lastSeen != null ? $lastSeen->toAtomString() : $userDetails->last_login->toAtomString(),
    // snip
];

见https://carbon.nesbot.com/docs/#api-commonformats

【讨论】:

感谢@Phil 指出这一改进。其实我不知道Carbon的这个toAtomString()方法。

以上是关于如何将 UTC 日期时间字符串转换为用户的当前时区?的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript:将 UTC 日期时间转换为传递时区的日期时间

如何将 UTC 格式的字符串转换为特定时区的日历?

将 UTC DateTime 转换为另一个时区

将输入字符串日期时间从不同时区转换为UTC

将 UTC 日期时间字符串转换为本地日期时间

Spring MVC - 将用户时区的日期转换为 UTC