Working with environment variables in Rust is easy using the std::env
module.
use std::env; fn main() { let key = "HOME"; let value = env::var(key); if !value.is_ok() { eprintln!("{} not found", key); return; } let value = value.unwrap(); // we know it's there println!("The value of {} is {}", key, value); }
If you create a new project using Cargo, and replace the default source code
in main.rs
with the above, you should be able to run the
program and see something like this:
% cargo run --quiet envvar The value of HOME is /Users/me
Let's define an environment variable that holds a date in standard format, and work with it.
The de facto date and time library in Rust is Chrono. It handles just about anything that you might reasonably want, from storing dates, times or full-blown timestamps, in local time or with a timezone. It also handles formatting and parsing.
Let's make a Rust program that can show the user how old they are in days, and congratulate them if it happens to be their birthday.
Create a new app with cargo new birthday
. Add the Chrono
crate to the Cargo.toml
file:
[dependencies] chrono = "0.4.38"
Here is the full text of main.rs
, with some explanation to follow:
use std::env;
use chrono::{NaiveDate, Local, Datelike};
fn main() {
let key = "BIRTHDATE";
let value = env::var(key);
// If the environment variable was not found,
// we exit early to avoid excessive nesting.
if !value.is_ok() {
return;
}
let value = value.unwrap(); // we know it's there
// Try to parse the BIRTHDATE variable as an ISO 8601 date
// into a NaiveDate. If that succeeds, compare the month and
// day components of the birthdate and the NaiveDate of today.
// If they match, congratulate the user.
match NaiveDate::parse_from_str(&value, "%F") {
Ok(birthdate) => {
let today: NaiveDate = Local::now().date_naive();
if birthdate.month() == today.month() && birthdate.day() == today.day() {
print!("Happy birthday! ");
}
// Compute the difference between the birthdate and today.
// If the result is positive, show the user's age in days
// (if zero, don't bother). If the result is negative,
// be amazed.
let diff = today.signed_duration_since(birthdate);
let day_count = diff.num_days();
if day_count >= 0 {
if day_count != 0 {
print!("You are {} days old.", day_count);
if day_count % 1000 == 0 {
print!(" That's a nice round number!");
}
}
} else {
print!("Looks like you're not born yet!");
}
println!();
},
Err(_) => {
eprintln!("Error in the '{}' environment variable: \
'{}' is not a valid date.", key, value);
}
}
}
If you run the program with Cargo, you will not see any output, because the
BIRTHDATE
environment is not set. So, first set its value to a valid
ISO 8601 date, and then run the program again. You should see something like this:
% BIRTHDATE=1989-11-30 cargo run --quiet You are 12735 days old.
The program was run on 2024-10-12. When you set the BIRTHDATE
environment variable to a date where the month and day match those of today,
you get a congratulation:
% BIRTHDATE=1989-10-12 cargo run --quiet Happy birthday! You are 12784 days old.
There are some checks for corner cases. For example, a bogus BIRTHDATE
environment variable value means that NaiveDate::parse_from_str
fails:
% BIRTHDATE=YYYY-MM-DD cargo run --quiet Error in the 'BIRTHDATE' environment variable: 'YYYY-MM-DD' is not a valid date.
If the value of the BIRTHDATE
environment variable is a valid date
but it has not passed yet, it will be questioned:
% BIRTHDATE=2038-01-19 cargo run --quiet Looks like you're not born yet!
Finally, if it is your birthday but you are a newborn baby, you will be congratulated, but not reminded that you are zero days old:
% BIRTHDATE=2024-10-12 cargo run --quiet Happy birthday!
This logic uses the signed_duration_since
function of NaiveDate
,
which returns a TimeDelta
value that you can convert into days using
its num_days
function. If the user's age in days is an even thousand, it
will be noted.
If you want a constant reminder of the passing of time, and handy reminders to celebrate your thousands of days, then build the app, put it somewhere in your path, and run it in your login shell. Be sure to have a look at the Chrono crate documentation to see what other goodies can be found there.