如何将 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())
<script src="https://momentjs.com/downloads/moment.js"></script>
【讨论】:
这个答案可以解决这个问题。您应该致力于从源头上修复它 @Phil 是的,它起作用了,我根据 vue 实现了这个。import moment from "moment";
convertFromNow(date)
return moment.utc(date).fromNow();
`,`【参考方案2】:
我对您的问题的理解是您需要获取用户的时区(通过他们的浏览器)。我将使用 moment 的 cdn 来演示这一点。
您需要同时拥有moment.js
和moment-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 日期时间字符串转换为用户的当前时区?的主要内容,如果未能解决你的问题,请参考以下文章