build_time/lib.rs
1/*!
2# build-time
3
4Simple proc-macros to generate build timestamp string literals.
5
6Based on Jasen Borisov's [build_timestamp](https://crates.io/crates/build_timestamp) crate.
7
8Two function like procedures are provided: `build_time_utc` and `build_time_local`.
9
10They take an optional [`strftime`](https://docs.rs/chrono/0.4/chrono/format/strftime/index.html)
11date and time format string as input, and return a string literal.
12If the input is empty, they will return a string literal in
13[RFC 3339 date and time format](https://en.wikipedia.org/wiki/ISO_8601#RFCs),
14e.g., `"2021-05-29T06:55:50.418437046+00:00"`.
15
16Requires Rust 1.45+ because these macros are used in expression positions.
17
18## Usage
19
20```rust
21use build_time::{build_time_utc, build_time_local};
22
23// Returns the UTC build timestamp in RFC3339 date and time format.
24let utc_build_time = build_time_utc!();
25
26// Returns the local build timestamp in the specified format.
27let local_build_time = build_time_local!("%Y-%m-%dT%H:%M:%S%.f%:z");
28```
29*/
30
31use chrono::{DateTime, Local, Utc};
32use once_cell::sync::Lazy;
33use proc_macro::TokenStream;
34use proc_macro2::Span;
35use quote::quote;
36use syn::{parse_macro_input, LitStr};
37
38static BUILD_TIME: Lazy<DateTime<Utc>> = Lazy::new(Utc::now);
39
40/// Build time in UTC.
41///
42/// It takes an optional [`strftime`](https://docs.rs/chrono/0.4/chrono/format/strftime/index.html)
43/// date and time format string as input, and returns a string literal.
44/// If the input is empty, it will return a string literal in
45/// [RFC 3339 date and time format](https://en.wikipedia.org/wiki/ISO_8601#RFCs),
46/// e.g., `"2021-05-29T06:55:50.418437046+00:00"`.
47///
48/// # Example
49///
50/// ```rust
51/// use build_time::build_time_utc;
52///
53/// // Returns the UTC build timestamp in RFC3339 date and time format.
54/// let build_time_rfc3339 = build_time_utc!();
55///
56/// // Returns the UTC build timestamp in the specified format.
57/// let build_time_formatted = build_time_utc!("%Y-%m-%dT%H:%M:%S%.f%:z");
58/// ```
59#[proc_macro]
60pub fn build_time_utc(input: TokenStream) -> TokenStream {
61 let time_str = if input.is_empty() {
62 BUILD_TIME.to_rfc3339()
63 } else {
64 let format = parse_macro_input!(input as LitStr);
65 BUILD_TIME.format(&format.value()).to_string()
66 };
67
68 let lit = LitStr::new(&time_str, Span::call_site());
69
70 quote!(#lit).into()
71}
72
73/// Build time in the local timescale.
74///
75/// It takes an optional [`strftime`](https://docs.rs/chrono/0.4/chrono/format/strftime/index.html)
76/// date and time format string as input, and returns a string literal.
77/// If the input is empty, it will return a string literal in
78/// [RFC 3339 date and time format](https://en.wikipedia.org/wiki/ISO_8601#RFCs),
79/// e.g., `"2021-05-29T06:55:50.418437046+00:00"`.
80///
81/// # Example
82///
83/// ```rust
84/// use build_time::build_time_local;
85///
86/// // Returns the local build timestamp in RFC3339 date and time format.
87/// let build_time_rfc3339 = build_time_local!();
88///
89/// // Returns the local build timestamp in the specified format.
90/// let build_time_formatted = build_time_local!("%Y-%m-%dT%H:%M:%S%.f%:z");
91/// ```
92#[proc_macro]
93pub fn build_time_local(input: TokenStream) -> TokenStream {
94 let local_time = BUILD_TIME.with_timezone(&Local);
95 let time_str = if input.is_empty() {
96 local_time.to_rfc3339()
97 } else {
98 let format = parse_macro_input!(input as LitStr);
99 local_time.format(&format.value()).to_string()
100 };
101
102 let lit = LitStr::new(&time_str, Span::call_site());
103
104 quote!(#lit).into()
105}