i3status_rs/blocks/time.rs
1//! The current time.
2//!
3//! # Configuration
4//!
5//! Key | Values | Default
6//! -----------|--------|--------
7//! `format` | Format string. See [chrono docs](https://docs.rs/chrono/0.3.0/chrono/format/strftime/index.html#specifiers) for all options. | `" $icon $timestamp.datetime() "`
8//! `interval` | Update interval in seconds | `10`
9//! `timezone` | A timezone specifier (e.g. "Europe/Lisbon") | Local timezone
10//!
11//! Placeholder | Value | Type | Unit
12//! --------------|---------------------------------------------|----------|-----
13//! `icon` | A static icon | Icon | -
14//! `timestamp` | The current time | Datetime | -
15//!
16//! Action | Default button
17//! ----------------|---------------
18//! `next_timezone` | Left
19//! `prev_timezone` | Right
20//!
21//! # Example
22//!
23//! ```toml
24//! [[block]]
25//! block = "time"
26//! interval = 60
27//! [block.format]
28//! full = " $icon $timestamp.datetime(f:'%a %Y-%m-%d %R %Z', l:fr_BE) "
29//! short = " $icon $timestamp.datetime(f:%R) "
30//! ```
31//!
32//! # Non Gregorian calendars
33//!
34//! You can use calendars other than the Gregorian calendar by adding the calendar specifier in the locale string. When using
35//! this feature you can't use chrono style format string, and you should use one of the options provided by
36//! the `icu4x` crate: `short`, `medium`, `long`, `full`.
37//! If you set `precision` to `hours`/`hour`/`h`, `minutes`/`minute`/`m`, or `seconds`/`second`/`s` then then the datetime will be formatted accordingly, otherwise only the date will be displayed.
38//!
39//! ** Only available using feature `icu_calendar`. **
40//!
41//! ## Example
42//!
43//! ```toml
44//! [[block]]
45//! block = "time"
46//! interval = 60
47//! format = "$timestamp.datetime(locale:'fa_IR-u-ca-persian', f:'full', precision: minutes)"
48//! ```
49//!
50//! # Icons Used
51//! - `time`
52
53use chrono::{Timelike as _, Utc};
54use chrono_tz::Tz;
55
56use super::prelude::*;
57
58#[derive(Deserialize, Debug, SmartDefault)]
59#[serde(deny_unknown_fields, default)]
60pub struct Config {
61 pub format: FormatConfig,
62 #[default(10.into())]
63 pub interval: Seconds,
64 pub timezone: Option<Timezone>,
65}
66
67#[derive(Deserialize, Debug, Clone)]
68#[serde(untagged)]
69pub enum Timezone {
70 Timezone(Tz),
71 Timezones(Vec<Tz>),
72}
73
74pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {
75 let mut actions = api.get_actions()?;
76 api.set_default_actions(&[
77 (MouseButton::Left, None, "next_timezone"),
78 (MouseButton::Right, None, "prev_timezone"),
79 ])?;
80
81 let format = config
82 .format
83 .with_default(" $icon $timestamp.datetime() ")?;
84
85 let timezones = match config.timezone.clone() {
86 Some(tzs) => match tzs {
87 Timezone::Timezone(tz) => vec![tz],
88 Timezone::Timezones(tzs) => tzs,
89 },
90 None => Vec::new(),
91 };
92
93 let prev_step_length = timezones.len().saturating_sub(2);
94
95 let mut timezone_iter = timezones.iter().cycle();
96
97 let mut timezone = timezone_iter.next();
98
99 let interval_seconds = config.interval.seconds().max(1);
100
101 let mut timer = tokio::time::interval_at(
102 tokio::time::Instant::now() + Duration::from_secs(interval_seconds),
103 Duration::from_secs(interval_seconds),
104 );
105 timer.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
106
107 loop {
108 let mut widget = Widget::new().with_format(format.clone());
109 let now = Utc::now();
110
111 widget.set_values(map! {
112 "icon" => Value::icon("time"),
113 "timestamp" => Value::datetime(now, timezone.copied())
114 });
115
116 api.set_widget(widget)?;
117
118 let phase = now.second() as u64 % interval_seconds;
119 if phase != 0 {
120 timer.reset_after(Duration::from_secs(interval_seconds - phase));
121 }
122
123 tokio::select! {
124 _ = timer.tick() => (),
125 _ = api.wait_for_update_request() => (),
126 Some(action) = actions.recv() => match action.as_ref() {
127 "next_timezone" => {
128 timezone = timezone_iter.next();
129 },
130 "prev_timezone" => {
131 timezone = timezone_iter.nth(prev_step_length);
132 },
133 _ => (),
134 }
135 }
136 }
137}