diff --git a/Cargo.lock b/Cargo.lock index 152d178b9..a15a00a02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -96,7 +96,7 @@ dependencies = [ "hashbrown 0.16.1", "static_assertions", "windows", - "windows-core 0.62.2", + "windows-core", ] [[package]] @@ -732,19 +732,6 @@ dependencies = [ "libc", ] -[[package]] -name = "chrono" -version = "0.4.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" -dependencies = [ - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-link 0.2.1", -] - [[package]] name = "ciborium" version = "0.2.2" @@ -1323,7 +1310,6 @@ dependencies = [ "accesskit", "accesskit_consumer", "bytemuck", - "chrono", "eframe", "egui", "egui_demo_lib", @@ -1332,6 +1318,7 @@ dependencies = [ "ehttp", "env_logger", "image", + "jiff", "log", "mimalloc", "poll-promise", @@ -1350,13 +1337,13 @@ dependencies = [ name = "egui_demo_lib" version = "0.33.3" dependencies = [ - "chrono", "criterion", "document-features", "egui", "egui_extras", "egui_kittest", "image", + "jiff", "mimalloc", "rand 0.9.2", "serde", @@ -1368,12 +1355,12 @@ name = "egui_extras" version = "0.33.3" dependencies = [ "ahash", - "chrono", "document-features", "egui", "ehttp", "enum-map", "image", + "jiff", "log", "mime_guess2", "profiling", @@ -2151,30 +2138,6 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" -[[package]] -name = "iana-time-zone" -version = "0.1.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core 0.61.2", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - [[package]] name = "icu_collections" version = "2.0.0" @@ -2387,22 +2350,25 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jiff" -version = "0.2.15" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359" dependencies = [ "jiff-static", + "js-sys", "log", "portable-atomic", "portable-atomic-util", - "serde", + "serde_core", + "wasm-bindgen", + "windows-sys 0.61.2", ] [[package]] name = "jiff-static" -version = "0.2.15" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" +checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4" dependencies = [ "proc-macro2", "quote", @@ -5282,7 +5248,7 @@ dependencies = [ "wgpu-naga-bridge", "wgpu-types", "windows", - "windows-core 0.62.2", + "windows-core", ] [[package]] @@ -5347,7 +5313,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" dependencies = [ "windows-collections", - "windows-core 0.62.2", + "windows-core", "windows-future", "windows-numerics", ] @@ -5358,20 +5324,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" dependencies = [ - "windows-core 0.62.2", -] - -[[package]] -name = "windows-core" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link 0.1.3", - "windows-result 0.3.4", - "windows-strings 0.4.2", + "windows-core", ] [[package]] @@ -5383,8 +5336,8 @@ dependencies = [ "windows-implement", "windows-interface", "windows-link 0.2.1", - "windows-result 0.4.1", - "windows-strings 0.5.1", + "windows-result", + "windows-strings", ] [[package]] @@ -5393,7 +5346,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" dependencies = [ - "windows-core 0.62.2", + "windows-core", "windows-link 0.2.1", "windows-threading", ] @@ -5438,19 +5391,10 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" dependencies = [ - "windows-core 0.62.2", + "windows-core", "windows-link 0.2.1", ] -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link 0.1.3", -] - [[package]] name = "windows-result" version = "0.4.1" @@ -5460,15 +5404,6 @@ dependencies = [ "windows-link 0.2.1", ] -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link 0.1.3", -] - [[package]] name = "windows-strings" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index 4c8a52626..6978e4df8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -80,7 +80,6 @@ arboard = { version = "3.6.1", default-features = false } backtrace = "0.3.76" bitflags = "2.9.4" bytemuck = "1.24.0" -chrono = { version = "0.4.42", default-features = false } cint = "0.3.1" color-hex = "0.2.0" criterion = { version = "0.7.0", default-features = false } @@ -96,6 +95,7 @@ glutin = { version = "0.32.3", default-features = false } glutin-winit = { version = "0.5.0", default-features = false } home = "0.5.9" image = { version = "0.25.6", default-features = false } +jiff = { version = "0.2.23", default-features = false } js-sys = "0.3.77" kittest = { version = "0.4.0" } log = { version = "0.4.28", features = ["std"] } diff --git a/crates/egui_demo_app/Cargo.toml b/crates/egui_demo_app/Cargo.toml index b23ea9cbb..49609746f 100644 --- a/crates/egui_demo_app/Cargo.toml +++ b/crates/egui_demo_app/Cargo.toml @@ -42,15 +42,15 @@ wayland = ["eframe/wayland"] x11 = ["eframe/x11"] [dependencies] -chrono = { workspace = true, features = ["js-sys", "wasmbind"] } eframe = { workspace = true, default-features = false, features = ["web_screen_reader"] } egui = { workspace = true, features = ["callstack", "default"] } -egui_demo_lib = { workspace = true, features = ["default", "chrono"] } +egui_demo_lib = { workspace = true, features = ["default", "jiff"] } egui_extras = { workspace = true, features = ["default", "image"] } image = { workspace = true, default-features = false, features = [ # Ensure we can display the test images "png", ] } +jiff = { workspace = true, features = ["std", "tz-system", "js"] } log.workspace = true profiling.workspace = true diff --git a/crates/egui_demo_app/src/lib.rs b/crates/egui_demo_app/src/lib.rs index ea30bda8d..45abccc7f 100644 --- a/crates/egui_demo_app/src/lib.rs +++ b/crates/egui_demo_app/src/lib.rs @@ -9,9 +9,10 @@ pub use wrap_app::{Anchor, WrapApp}; /// Time of day as seconds since midnight. Used for clock in demo app. pub(crate) fn seconds_since_midnight() -> f64 { - use chrono::Timelike as _; - let time = chrono::Local::now().time(); - time.num_seconds_from_midnight() as f64 + 1e-9 * (time.nanosecond() as f64) + jiff::Zoned::now() + .time() + .duration_since(jiff::civil::Time::midnight()) + .as_secs_f64() } /// Trait that wraps different parts of the demo app. diff --git a/crates/egui_demo_lib/Cargo.toml b/crates/egui_demo_lib/Cargo.toml index 4f3b853e0..dc57fb092 100644 --- a/crates/egui_demo_lib/Cargo.toml +++ b/crates/egui_demo_lib/Cargo.toml @@ -26,7 +26,7 @@ rustdoc-args = ["--generate-link-to-definition"] [features] default = [] -chrono = ["egui_extras/datepicker", "dep:chrono"] +jiff = ["egui_extras/datepicker", "dep:jiff"] ## Allow serialization using [`serde`](https://docs.rs/serde). serde = ["egui/serde", "dep:serde", "egui_extras/serde"] @@ -42,7 +42,7 @@ egui_extras = { workspace = true, features = ["image", "svg"] } unicode_names2.workspace = true # this old version has fewer dependencies #! ### Optional dependencies -chrono = { workspace = true, optional = true, features = ["js-sys", "wasmbind"] } +jiff = { workspace = true, optional = true, features = ["std", "js"] } ## Enable this when generating docs. document-features = { workspace = true, optional = true } serde = { workspace = true, optional = true } diff --git a/crates/egui_demo_lib/src/demo/widget_gallery.rs b/crates/egui_demo_lib/src/demo/widget_gallery.rs index 6e23fca92..ec5d5f3eb 100644 --- a/crates/egui_demo_lib/src/demo/widget_gallery.rs +++ b/crates/egui_demo_lib/src/demo/widget_gallery.rs @@ -19,11 +19,11 @@ pub struct WidgetGallery { color: egui::Color32, animate_progress_bar: bool, - #[cfg(feature = "chrono")] + #[cfg(feature = "jiff")] #[cfg_attr(feature = "serde", serde(skip))] - date: Option, + date: Option, - #[cfg(feature = "chrono")] + #[cfg(feature = "jiff")] with_date_button: bool, } @@ -39,19 +39,19 @@ impl Default for WidgetGallery { string: Default::default(), color: egui::Color32::LIGHT_BLUE.linear_multiply(0.5), animate_progress_bar: false, - #[cfg(feature = "chrono")] + #[cfg(feature = "jiff")] date: None, - #[cfg(feature = "chrono")] + #[cfg(feature = "jiff")] with_date_button: true, } } } impl WidgetGallery { - #[allow(clippy::allow_attributes, unused_mut)] // if not chrono + #[allow(clippy::allow_attributes, unused_mut)] // if not jiff #[inline] pub fn with_date_button(mut self, _with_date_button: bool) -> Self { - #[cfg(feature = "chrono")] + #[cfg(feature = "jiff")] { self.with_date_button = _with_date_button; } @@ -140,9 +140,9 @@ impl WidgetGallery { string, color, animate_progress_bar, - #[cfg(feature = "chrono")] + #[cfg(feature = "jiff")] date, - #[cfg(feature = "chrono")] + #[cfg(feature = "jiff")] with_date_button, } = self; @@ -242,9 +242,9 @@ impl WidgetGallery { } ui.end_row(); - #[cfg(feature = "chrono")] + #[cfg(feature = "jiff")] if *with_date_button { - let date = date.get_or_insert_with(|| chrono::offset::Utc::now().date_naive()); + let date = date.get_or_insert_with(|| jiff::Zoned::now().date()); ui.add(doc_link_label_with_crate( "egui_extras", "DatePickerButton", @@ -302,7 +302,7 @@ fn doc_link_label_with_crate<'a>( } } -#[cfg(feature = "chrono")] +#[cfg(feature = "jiff")] #[cfg(test)] mod tests { use super::*; @@ -314,7 +314,7 @@ mod tests { pub fn should_match_screenshot() { let mut demo = WidgetGallery { // If we don't set a fixed date, the snapshot test will fail. - date: Some(chrono::NaiveDate::from_ymd_opt(2024, 1, 1).unwrap()), + date: Some(jiff::civil::date(2024, 1, 1)), ..Default::default() }; diff --git a/crates/egui_extras/Cargo.toml b/crates/egui_extras/Cargo.toml index b124148bc..944576f08 100644 --- a/crates/egui_extras/Cargo.toml +++ b/crates/egui_extras/Cargo.toml @@ -34,7 +34,7 @@ default = ["dep:mime_guess2"] all_loaders = ["file", "http", "image", "svg", "gif", "webp"] ## Enable [`DatePickerButton`] widget. -datepicker = ["chrono"] +datepicker = ["jiff"] ## Add support for loading images from `file://` URIs. file = ["dep:mime_guess2"] @@ -83,7 +83,7 @@ profiling.workspace = true serde = { workspace = true, optional = true } # Date operations needed for datepicker widget -chrono = { workspace = true, optional = true, features = ["clock", "js-sys", "std", "wasmbind"] } +jiff = { workspace = true, optional = true, features = ["std", "tz-system", "js"] } ## Enable this when generating docs. document-features = { workspace = true, optional = true } diff --git a/crates/egui_extras/src/datepicker/button.rs b/crates/egui_extras/src/datepicker/button.rs index d6f69fe77..692dc9d24 100644 --- a/crates/egui_extras/src/datepicker/button.rs +++ b/crates/egui_extras/src/datepicker/button.rs @@ -1,6 +1,6 @@ use super::popup::DatePickerPopup; -use chrono::NaiveDate; use egui::{Area, Button, Frame, InnerResponse, Key, Order, RichText, Ui, Widget}; +use jiff::civil::Date; use std::ops::RangeInclusive; #[derive(Default, Clone)] @@ -11,7 +11,7 @@ pub(crate) struct DatePickerButtonState { /// Shows a date, and will open a date picker popup when clicked. pub struct DatePickerButton<'a> { - selection: &'a mut NaiveDate, + selection: &'a mut Date, id_salt: Option<&'a str>, combo_boxes: bool, arrows: bool, @@ -20,13 +20,13 @@ pub struct DatePickerButton<'a> { show_icon: bool, format: String, highlight_weekends: bool, - start_end_years: Option>, + start_end_years: Option>, reverse_years: bool, - year_scroll_to: Option, + year_scroll_to: Option, } impl<'a> DatePickerButton<'a> { - pub fn new(selection: &'a mut NaiveDate) -> Self { + pub fn new(selection: &'a mut Date) -> Self { Self { selection, id_salt: None, @@ -95,7 +95,7 @@ impl<'a> DatePickerButton<'a> { } /// Change the format shown on the button. (Default: %Y-%m-%d) - /// See [`chrono::format::strftime`] for valid formats. + /// See [`jiff::fmt::strtime`] for valid formats. #[inline] pub fn format(mut self, format: impl Into) -> Self { self.format = format.into(); @@ -115,7 +115,7 @@ impl<'a> DatePickerButton<'a> { /// For example, if you want to provide the range of years from 2000 to 2035, you can use: /// `start_end_years(2000..=2035)`. #[inline] - pub fn start_end_years(mut self, start_end_years: RangeInclusive) -> Self { + pub fn start_end_years(mut self, start_end_years: RangeInclusive) -> Self { self.start_end_years = Some(start_end_years); self } @@ -130,7 +130,7 @@ impl<'a> DatePickerButton<'a> { /// Scroll the year dropdown to this year when the picker first opens. /// Defaults to the currently selected year. #[inline] - pub fn year_scroll_to(mut self, year: i32) -> Self { + pub fn year_scroll_to(mut self, year: i16) -> Self { self.year_scroll_to = Some(year); self } @@ -144,9 +144,9 @@ impl Widget for DatePickerButton<'_> { .unwrap_or_default(); let mut text = if self.show_icon { - RichText::new(format!("{} 📆", self.selection.format(&self.format))) + RichText::new(format!("{} 📆", self.selection.strftime(&self.format))) } else { - RichText::new(format!("{}", self.selection.format(&self.format))) + RichText::new(format!("{}", self.selection.strftime(&self.format))) }; let visuals = ui.visuals().widgets.open; if button_state.picker_visible { diff --git a/crates/egui_extras/src/datepicker/mod.rs b/crates/egui_extras/src/datepicker/mod.rs index 7a114b357..f1f6e58fa 100644 --- a/crates/egui_extras/src/datepicker/mod.rs +++ b/crates/egui_extras/src/datepicker/mod.rs @@ -4,32 +4,32 @@ mod button; mod popup; pub use button::DatePickerButton; -use chrono::{Datelike as _, Duration, NaiveDate, Weekday}; +use jiff::civil::{Date, ISOWeekDate, Weekday}; #[derive(Debug)] struct Week { number: u8, - days: Vec, + days: Vec, } -fn month_data(year: i32, month: u32) -> Vec { - let first = NaiveDate::from_ymd_opt(year, month, 1).expect("Could not create NaiveDate"); +fn month_data(year: i16, month: i8) -> Vec { + let first = Date::new(year, month, 1).expect("Could not create Date"); let mut start = first; - while start.weekday() != Weekday::Mon { - start = start.checked_sub_signed(Duration::days(1)).unwrap(); + while start.weekday() != Weekday::Monday { + start = start.yesterday().unwrap(); } let mut weeks = vec![]; let mut week = vec![]; - while start < first || start.month() == first.month() || start.weekday() != Weekday::Mon { + while start < first || start.month() == first.month() || start.weekday() != Weekday::Monday { week.push(start); - if start.weekday() == Weekday::Sun { + if start.weekday() == Weekday::Sunday { weeks.push(Week { - number: start.iso_week().week() as u8, + number: ISOWeekDate::from(start).week() as u8, days: std::mem::take(&mut week), }); } - start = start.checked_add_signed(Duration::days(1)).unwrap(); + start = start.tomorrow().unwrap(); } weeks diff --git a/crates/egui_extras/src/datepicker/popup.rs b/crates/egui_extras/src/datepicker/popup.rs index 1c24ca81d..5c0726e5a 100644 --- a/crates/egui_extras/src/datepicker/popup.rs +++ b/crates/egui_extras/src/datepicker/popup.rs @@ -1,4 +1,4 @@ -use chrono::{Datelike as _, NaiveDate, Weekday}; +use jiff::civil::{Date, Weekday}; use egui::{Align, Button, Color32, ComboBox, Direction, Id, Layout, RichText, Ui, Vec2}; @@ -9,43 +9,39 @@ use crate::{Column, Size, StripBuilder, TableBuilder}; #[derive(Default, Clone)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] struct DatePickerPopupState { - year: i32, - month: u32, - day: u32, + year: i16, + month: i8, + day: i8, setup: bool, year_scroll_needed: bool, } impl DatePickerPopupState { - fn last_day_of_month(&self) -> u32 { - let date: NaiveDate = - NaiveDate::from_ymd_opt(self.year, self.month, 1).expect("Could not create NaiveDate"); - date.with_day(31) - .map(|_| 31) - .or_else(|| date.with_day(30).map(|_| 30)) - .or_else(|| date.with_day(29).map(|_| 29)) - .unwrap_or(28) + fn last_day_of_month(&self) -> i8 { + Date::new(self.year, self.month, 1) + .expect("Could not create Date") + .days_in_month() } } pub(crate) struct DatePickerPopup<'a> { - pub selection: &'a mut NaiveDate, + pub selection: &'a mut Date, pub button_id: Id, pub combo_boxes: bool, pub arrows: bool, pub calendar: bool, pub calendar_week: bool, pub highlight_weekends: bool, - pub start_end_years: Option>, + pub start_end_years: Option>, pub reverse_years: bool, - pub year_scroll_to: Option, + pub year_scroll_to: Option, } impl DatePickerPopup<'_> { /// Returns `true` if user pressed `Save` button. pub fn draw(&mut self, ui: &mut Ui) -> bool { let id = ui.make_persistent_id("date_picker"); - let today = chrono::offset::Utc::now().date_naive(); + let today = jiff::Zoned::now().date(); let mut popup_state = ui .data_mut(|data| data.get_persisted::(id)) .unwrap_or_default(); @@ -95,7 +91,7 @@ impl DatePickerPopup<'_> { }; let scroll_to_year = self.year_scroll_to.unwrap_or(popup_state.year); - let years: Vec = if self.reverse_years { + let years: Vec = if self.reverse_years { (start_year..=end_year).rev().collect() } else { (start_year..=end_year).collect() @@ -132,7 +128,7 @@ impl DatePickerPopup<'_> { ComboBox::from_id_salt("date_picker_month") .selected_text(month_name(popup_state.month)) .show_ui(ui, |ui| { - for month in 1..=12 { + for month in 1i8..=12 { if ui .selectable_value( &mut popup_state.month, @@ -156,7 +152,7 @@ impl DatePickerPopup<'_> { ComboBox::from_id_salt("date_picker_day") .selected_text(popup_state.day.to_string()) .show_ui(ui, |ui| { - for day in 1..=popup_state.last_day_of_month() { + for day in 1i8..=popup_state.last_day_of_month() { if ui .selectable_value( &mut popup_state.day, @@ -333,9 +329,10 @@ impl DatePickerPopup<'_> { && popup_state.day == day.day() { ui.visuals().selection.bg_fill - } else if (day.weekday() == Weekday::Sat - || day.weekday() == Weekday::Sun) - && self.highlight_weekends + } else if (matches!( + day.weekday(), + Weekday::Saturday | Weekday::Sunday + )) && self.highlight_weekends { if ui.visuals().dark_mode { Color32::DARK_RED @@ -414,12 +411,12 @@ impl DatePickerPopup<'_> { strip.cell(|ui| { ui.with_layout(Layout::top_down_justified(Align::Center), |ui| { if ui.button("Save").clicked() { - *self.selection = NaiveDate::from_ymd_opt( + *self.selection = Date::new( popup_state.year, popup_state.month, popup_state.day, ) - .expect("Could not create NaiveDate"); + .expect("Could not create Date"); saved = true; close = true; } @@ -442,7 +439,7 @@ impl DatePickerPopup<'_> { } } -fn month_name(i: u32) -> &'static str { +fn month_name(i: i8) -> &'static str { match i { 1 => "January", 2 => "February", diff --git a/crates/egui_extras/src/lib.rs b/crates/egui_extras/src/lib.rs index 19e0c95a8..99e6dd5e4 100644 --- a/crates/egui_extras/src/lib.rs +++ b/crates/egui_extras/src/lib.rs @@ -8,7 +8,7 @@ #![expect(clippy::manual_range_contains)] -#[cfg(feature = "chrono")] +#[cfg(feature = "datepicker")] mod datepicker; pub mod syntax_highlighting; @@ -21,7 +21,7 @@ mod sizing; mod strip; mod table; -#[cfg(feature = "chrono")] +#[cfg(feature = "datepicker")] pub use crate::datepicker::DatePickerButton; pub(crate) use crate::layout::StripLayout; diff --git a/examples/hello_android/Cargo.toml b/examples/hello_android/Cargo.toml index 7c8444f99..ae484783c 100644 --- a/examples/hello_android/Cargo.toml +++ b/examples/hello_android/Cargo.toml @@ -22,7 +22,7 @@ eframe = { workspace = true, default-features = false, features = [ "glow", "android-native-activity", ] } -egui_demo_lib = { workspace = true, features = ["chrono"] } +egui_demo_lib = { workspace = true, features = ["jiff"] } # For image support: egui_extras = { workspace = true, features = ["default", "image"] }