linux: Implement local time zone support (#14610)

I decided to remove the GPUI APIs since `chrono` already provides this
functionality, and is already been used for this purpose in other parts
of the code (e.g.
[here](80402a6840/crates/zed/src/main.rs (L756))
or
[here](80402a6840/crates/ui/src/utils/format_distance.rs (L258)))

These usages end up calling the `time_format` crate, which takes in a
`UtcOffset`. It's probably cleaner to rewrite the crate to take in
`chrono` types, but that would require rewriting most of the code there.

Release Notes:

- linux: Use local time zone in chat and Git blame
This commit is contained in:
apricotbucket28 2024-07-18 08:42:18 -03:00 committed by GitHub
parent 22a2cc6950
commit 013c9f0420
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 26 additions and 72 deletions

2
Cargo.lock generated
View File

@ -2564,6 +2564,7 @@ dependencies = [
"anyhow",
"call",
"channel",
"chrono",
"client",
"collections",
"db",
@ -3593,6 +3594,7 @@ dependencies = [
"aho-corasick",
"anyhow",
"assets",
"chrono",
"client",
"clock",
"collections",

View File

@ -457,7 +457,6 @@ features = [
"Win32_System_SystemInformation",
"Win32_System_SystemServices",
"Win32_System_Threading",
"Win32_System_Time",
"Win32_System_WinRT",
"Win32_UI_Controls",
"Win32_UI_HiDpi",

View File

@ -32,6 +32,7 @@ test-support = [
anyhow.workspace = true
call.workspace = true
channel.workspace = true
chrono.workspace = true
client.workspace = true
collections.workspace = true
db.workspace = true

View File

@ -111,6 +111,7 @@ impl ChatPanel {
this.is_scrolled_to_bottom = !event.is_scrolled;
}));
let local_offset = chrono::Local::now().offset().local_minus_utc();
let mut this = Self {
fs,
client,
@ -120,7 +121,7 @@ impl ChatPanel {
active_chat: Default::default(),
pending_serialization: Task::ready(None),
message_editor: input_editor,
local_timezone: cx.local_timezone(),
local_timezone: UtcOffset::from_whole_seconds(local_offset).unwrap(),
subscriptions: Vec::new(),
is_scrolled_to_bottom: true,
active: false,

View File

@ -127,11 +127,12 @@ impl NotificationPanel {
},
));
let local_offset = chrono::Local::now().offset().local_minus_utc();
let mut this = Self {
fs,
client,
user_store,
local_timezone: cx.local_timezone(),
local_timezone: UtcOffset::from_whole_seconds(local_offset).unwrap(),
channel_store: ChannelStore::global(cx),
notification_store: NotificationStore::global(cx),
notification_list,

View File

@ -31,6 +31,7 @@ test-support = [
aho-corasick = "1.1"
anyhow.workspace = true
assets.workspace = true
chrono.workspace = true
client.workspace = true
clock.workspace = true
collections.workspace = true

View File

@ -8,6 +8,7 @@ use gpui::{
use settings::Settings;
use std::hash::Hash;
use theme::{ActiveTheme, ThemeSettings};
use time::UtcOffset;
use ui::{
div, h_flex, tooltip_container, v_flex, Avatar, Button, ButtonStyle, Clickable as _, Color,
FluentBuilder, Icon, IconName, IconPosition, InteractiveElement as _, IntoElement,
@ -129,7 +130,7 @@ impl Render for BlameEntryTooltip {
let author_email = self.blame_entry.author_mail.clone();
let short_commit_id = self.blame_entry.sha.display_short();
let absolute_timestamp = blame_entry_absolute_timestamp(&self.blame_entry, cx);
let absolute_timestamp = blame_entry_absolute_timestamp(&self.blame_entry);
let message = self
.details
@ -247,30 +248,25 @@ impl Render for BlameEntryTooltip {
}
}
fn blame_entry_timestamp(
blame_entry: &BlameEntry,
format: time_format::TimestampFormat,
cx: &WindowContext,
) -> String {
fn blame_entry_timestamp(blame_entry: &BlameEntry, format: time_format::TimestampFormat) -> String {
match blame_entry.author_offset_date_time() {
Ok(timestamp) => time_format::format_localized_timestamp(
timestamp,
time::OffsetDateTime::now_utc(),
cx.local_timezone(),
format,
),
Ok(timestamp) => {
let local = chrono::Local::now().offset().local_minus_utc();
time_format::format_localized_timestamp(
timestamp,
time::OffsetDateTime::now_utc(),
UtcOffset::from_whole_seconds(local).unwrap(),
format,
)
}
Err(_) => "Error parsing date".to_string(),
}
}
pub fn blame_entry_relative_timestamp(blame_entry: &BlameEntry, cx: &WindowContext) -> String {
blame_entry_timestamp(blame_entry, time_format::TimestampFormat::Relative, cx)
pub fn blame_entry_relative_timestamp(blame_entry: &BlameEntry) -> String {
blame_entry_timestamp(blame_entry, time_format::TimestampFormat::Relative)
}
fn blame_entry_absolute_timestamp(blame_entry: &BlameEntry, cx: &WindowContext) -> String {
blame_entry_timestamp(
blame_entry,
time_format::TimestampFormat::MediumAbsolute,
cx,
)
fn blame_entry_absolute_timestamp(blame_entry: &BlameEntry) -> String {
blame_entry_timestamp(blame_entry, time_format::TimestampFormat::MediumAbsolute)
}

View File

@ -3923,7 +3923,7 @@ fn render_inline_blame_entry(
workspace: Option<WeakView<Workspace>>,
cx: &mut WindowContext<'_>,
) -> AnyElement {
let relative_timestamp = blame_entry_relative_timestamp(&blame_entry, cx);
let relative_timestamp = blame_entry_relative_timestamp(&blame_entry);
let author = blame_entry.author.as_deref().unwrap_or_default();
let text = format!("{}, {}", author, relative_timestamp);
@ -3969,7 +3969,7 @@ fn render_blame_entry(
};
last_used_color.replace((sha_color, blame_entry.sha));
let relative_timestamp = blame_entry_relative_timestamp(&blame_entry, cx);
let relative_timestamp = blame_entry_relative_timestamp(&blame_entry);
let short_commit_id = blame_entry.sha.display_short();

View File

@ -14,7 +14,6 @@ use derive_more::{Deref, DerefMut};
use futures::{channel::oneshot, future::LocalBoxFuture, Future};
use slotmap::SlotMap;
use smol::future::FutureExt;
use time::UtcOffset;
pub use async_context::*;
use collections::{FxHashMap, FxHashSet, VecDeque};
@ -647,11 +646,6 @@ impl AppContext {
self.platform.restart(binary_path)
}
/// Returns the local timezone at the platform level.
pub fn local_timezone(&self) -> UtcOffset {
self.platform.local_timezone()
}
/// Updates the http client assigned to GPUI
pub fn update_http_client(&mut self, new_client: Arc<dyn HttpClient>) {
self.http_client = new_client;

View File

@ -60,7 +60,6 @@ pub(crate) use mac::*;
pub use semantic_version::SemanticVersion;
#[cfg(any(test, feature = "test-support"))]
pub(crate) use test::*;
use time::UtcOffset;
#[cfg(target_os = "windows")]
pub(crate) use windows::*;
@ -159,7 +158,6 @@ pub(crate) trait Platform: 'static {
""
}
fn app_path(&self) -> Result<PathBuf>;
fn local_timezone(&self) -> UtcOffset;
fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf>;
fn set_cursor_style(&self, style: CursorStyle);

View File

@ -30,7 +30,6 @@ use filedescriptor::FileDescriptor;
use flume::{Receiver, Sender};
use futures::channel::oneshot;
use parking_lot::Mutex;
use time::UtcOffset;
use util::ResultExt;
use wayland_client::Connection;
use wayland_protocols::wp::cursor_shape::v1::client::wp_cursor_shape_device_v1::Shape;
@ -397,10 +396,6 @@ impl<P: LinuxClient + 'static> Platform for P {
fn set_dock_menu(&self, menu: Vec<MenuItem>, keymap: &Keymap) {}
fn local_timezone(&self) -> UtcOffset {
UtcOffset::UTC
}
fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
Err(anyhow::Error::msg(
"Platform<LinuxPlatform>::path_for_auxiliary_executable is not implemented yet",

View File

@ -49,7 +49,6 @@ use std::{
slice, str,
sync::Arc,
};
use time::UtcOffset;
use super::renderer;
@ -760,14 +759,6 @@ impl Platform for MacPlatform {
}
}
fn local_timezone(&self) -> UtcOffset {
unsafe {
let local_timezone: id = msg_send![class!(NSTimeZone), localTimeZone];
let seconds_from_gmt: NSInteger = msg_send![local_timezone, secondsFromGMT];
UtcOffset::from_whole_seconds(seconds_from_gmt.try_into().unwrap()).unwrap()
}
}
fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
unsafe {
let bundle: id = NSBundle::mainBundle();

View File

@ -257,10 +257,6 @@ impl Platform for TestPlatform {
unimplemented!()
}
fn local_timezone(&self) -> time::UtcOffset {
time::UtcOffset::UTC
}
fn path_for_auxiliary_executable(&self, _name: &str) -> Result<std::path::PathBuf> {
unimplemented!()
}

View File

@ -16,7 +16,6 @@ use futures::channel::oneshot::{self, Receiver};
use itertools::Itertools;
use parking_lot::RwLock;
use smallvec::SmallVec;
use time::UtcOffset;
use windows::{
core::*,
Win32::{
@ -35,7 +34,6 @@ use windows::{
Ole::*,
SystemInformation::*,
Threading::*,
Time::*,
},
UI::{Input::KeyboardAndMouse::*, Shell::*, WindowsAndMessaging::*},
},
@ -482,25 +480,6 @@ impl Platform for WindowsPlatform {
Ok(std::env::current_exe()?)
}
fn local_timezone(&self) -> UtcOffset {
let mut info = unsafe { std::mem::zeroed() };
let ret = unsafe { GetTimeZoneInformation(&mut info) };
if ret == TIME_ZONE_ID_INVALID {
log::error!(
"Unable to get local timezone: {}",
std::io::Error::last_os_error()
);
return UtcOffset::UTC;
}
// Windows treat offset as:
// UTC = localtime + offset
// so we add a minus here
let hours = -info.Bias / 60;
let minutes = -info.Bias % 60;
UtcOffset::from_hms(hours as _, minutes as _, 0).unwrap()
}
// todo(windows)
fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
Err(anyhow!("not yet implemented"))