{"id":21395,"date":"2024-06-26T01:50:15","date_gmt":"2024-06-26T05:50:15","guid":{"rendered":"https:\/\/qxf2.com\/blog\/?p=21395"},"modified":"2024-06-26T01:50:15","modified_gmt":"2024-06-26T05:50:15","slug":"introduction-to-chrono-crate-in-rust","status":"publish","type":"post","link":"https:\/\/qxf2.com\/blog\/introduction-to-chrono-crate-in-rust\/","title":{"rendered":"Introduction to Chrono Crate in Rust"},"content":{"rendered":"<p><a href=\"https:\/\/qxf2.com\/?utm_source=chrono_rust&amp;utm_medium=click&amp;utm_campaign=From%20blog\">Qxf2<\/a> is writing about commonly used Rust libraries. This series of posts is aimed at testers (like us) who want to start using Rust as part of their daily work. In this post, we will show you how to use <a href=\"https:\/\/crates.io\/crates\/chrono\">Chrono<\/a>. Chrono aims to provide all functionality needed to do correct operations on dates and times.<\/p>\n<h4>Getting Started<\/h4>\n<p>Setting up with a Rust project:<br \/>\nFirst, open a terminal and navigate to folder to make your new project. Then, run this command to start a new project with Cargo.<\/p>\n<pre lang=\"rust\"> \r\ncargo new chrono_crate\r\n<\/pre>\n<p>Here &#8216;chrono_crate&#8217; is the project name where you can use any name to call your project.<\/p>\n<p>Install Chrono:<br \/>\nTo get &#8216;chrono&#8217; crate, change the directory to chrono_crate by using &#8216;cd chrono_crate&#8217; and run following command:<\/p>\n<pre lang=\"rust\"> \r\ncargo add chrono\r\n<\/pre>\n<p>or as an alternate, add these lines to your project&#8217;s Cargo.toml file:<\/p>\n<pre lang=\"rust\"> \r\nchrono = \"0.4.34\"\r\n<\/pre>\n<h3>Chrono Modules<\/h3>\n<p>We will cover some of the most commonly used modules from the Chrono crate. In our limited experience, these were the modules that were useful to us when working with date and time objects. <\/p>\n<h4>Chrono:Format<\/h4>\n<p>The \u2018format\u2019 module in the Chrono crate gives functionality which is related to parsing and formatting DateTime strings. It includes types and functions for parsing DateTime strings from various formats and formatting DateTime values into strings according to specific formats.<\/p>\n<pre lang=\"rust\"> \r\n\/\/ This program demonstrates parsing a DateTtime string and formatting it using Chrono crate.\r\n\/\/ It has two functions:\r\n\/\/ - `new_datetime`: Parses a date and time string with a given format and returns a `DateTime<Local>` object.\r\n\/\/ - `format_with_items`: Formats a `DateTime<Local>` object using provided format items and returns a string.\r\n\r\nuse chrono::format::{ParseError, StrftimeItems};\r\nuse chrono::{DateTime, Local};\r\n\r\nfn new_datetime(datetime_str: &str, format_str: &str) -> Result<DateTime<Local>, ParseError> {\r\n    DateTime::parse_from_str(datetime_str, format_str)\r\n        .map(|datetime| datetime.with_timezone(&Local))\r\n}\r\n\r\nfn format_with_items(datetime: DateTime<Local>, items: StrftimeItems) -> String {\r\n    datetime.format_with_items(items).to_string()\r\n}\r\n\r\nfn main() {\r\n    \/\/ Custom date and time format\r\n    let custom_format = \"%Y-%m-%d %H:%M:%S %:z\";\r\n\r\n    \/\/ Date time string in custom format with timezone\r\n    let date_time_string = \"2024-01-01 02:30:00 +05:30\";\r\n\r\n    match new_datetime(date_time_string, custom_format) {\r\n        Ok(parsed_datetime) => {\r\n            \/\/ Formatting the parsed DateTime object into a different format using StrftimeItems submodule\r\n            let new_format_items = StrftimeItems::new(\"%A, %d %B %Y %H:%M:%S\");\r\n            let formatted_datetime = format_with_items(parsed_datetime, new_format_items);\r\n\r\n            println!(\"Parsed and formatted date and time: {}\", formatted_datetime);\r\n        }\r\n        Err(err) => {\r\n            eprintln!(\"Error parsing date and time: {}\", err);\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>Here in the example script, I am parsing a date and time string using a custom format and then formatting it again using a different custom format using the \u2018format\u2019 module in the \u2018Chrono\u2019 crate.<\/p>\n<p>For that, I have defined two functions i.e \u2018new_datetime\u2019 and &#8216;format_with_items&#8217;. The new_datetime function is a constructor, where it parses a DateTime string using the given format string and provides a Result. This Result can either contain the parsed DateTime<Local> object or a ParseError. The format_with_items function formats the DateTime using StrftimeItems and returns the formatted string.<\/p>\n<p>In the \u2018Main\u2019 function define a custom date and time format and a datetime string with a timezone offset. It then tries to parse the DateTime string using the custom format. If successful, it defines a new format for the datetime and formats it. Otherwise, it prints an error message.<\/p>\n<h4>Chrono:Offset<\/h4>\n<p>The offset module within Chrono gives functionality for working with time offsets, such as time zone offsets or offsets from UTC (Coordinated Universal Time). This module allows developers to perform operations like converting between different time zones or calculating time differences accounting for offsets.<\/p>\n<pre lang=\"rust\"> \r\n\/\/ Timezome converstion script!\r\n\/\/ It defines two time zones, `Local` and `New York`, calculates and prints the time difference between them.\r\n\/\/ It also creates a vector of events in UTC time zone And converts a vector of events from UTC to both local and New York time zones.\r\n\r\nuse chrono::offset::FixedOffset;\r\nuse chrono::prelude::{Utc, Local, TimeZone};\r\nuse chrono::Duration;\r\n\r\nfn main() {\r\n    \/\/ Define two time zones: Local and New York\r\n    let local_timezone = Local;\r\n    let ny_timezone = match FixedOffset::west_opt(5 * 3600) {\r\n        Some(offset) => offset,\r\n        None => {\r\n            eprintln!(\"Failed to create New York time zone with west offset\");\r\n            match FixedOffset::east_opt(0) {\r\n                Some(offset) => offset,\r\n                None => {\r\n                    eprintln!(\"Failed to create New York time zone with east offset\");\r\n                    let default_offset = match FixedOffset::east_opt(0) {\r\n                        Some(offset) => offset,\r\n                        None => {\r\n                            eprintln!(\"Failed to create New York time zone with default east offset\");\r\n                            panic!(\"Failed to create New York time zone with any offset\");\r\n                        }\r\n                    };\r\n                    default_offset\r\n                }\r\n            }\r\n        }\r\n    };\r\n\r\n    \/\/ Calculate and print the time difference between Local and New York\r\n    let now_utc = Utc::now();\r\n    let now_local = local_timezone.from_utc_datetime(&now_utc.naive_utc());\r\n    let now_ny = ny_timezone.from_utc_datetime(&now_utc.naive_utc());\r\n    let time_difference = now_local.signed_duration_since(now_ny);\r\n    println!(\"Time difference between Local and New York: {}\", time_difference);\r\n\r\n    \/\/ Create a vector of events in UTC\r\n    let events_utc = vec![\r\n        Utc::now() + Duration::hours(1),\r\n        Utc::now() + Duration::hours(5),\r\n        Utc::now() + Duration::hours(10),\r\n    ];\r\n\r\n    \/\/ Convert and print events in Local time zone\r\n    let events_local: Vec<_> = events_utc\r\n        .iter()\r\n        .map(|&dt| local_timezone.from_utc_datetime(&dt.naive_utc()))\r\n        .collect();\r\n\r\n    println!(\"Events in Local time zone: {:?}\", events_local);\r\n\r\n    \/\/ Convert and print events in New York time zone\r\n    let events_ny: Vec<_> = events_utc\r\n        .iter()\r\n        .map(|&dt| ny_timezone.from_utc_datetime(&dt.naive_utc()))\r\n        .collect();\r\n\r\n    println!(\"Events in New York time zone: {:?}\", events_ny);\r\n}\r\n\r\n<\/pre>\n<p>In the above example, &#8216;chrono::prelude::{Utc, Local, TimeZone}&#8217; and &#8216;chrono::offset::FixedOffset&#8217; import the modules and traits necessary for handling dates, times, and time zones.<\/p>\n<p>The &#8216;prelude&#8217; module imports traits and types for date and time manipulation, while &#8216;offset::FixedOffset&#8217; imports types and traits related to time zones and offsets. <\/p>\n<p>Within the main function, methods for converting time zones and calculating time differences are defined. The function creates instances of time zones, specifically for Local and New York, using a &#8216;FixedOffset&#8217;. It calculates and prints the time difference between the given time zones and converts a set of events from UTC to both Local and New York time zones, prints the results.<\/p>\n<h4>Chrono:Prelude<\/h4>\n<p>The prelude module serves as a collection of commonly used types, traits, and functions. By importing \u2018chrono::prelude\u2019, developers can easily access components like DateTime, NaiveDateTime, Utc, and local time without repetitive imports. This module simplifies code readability and promotes efficiency by providing a convenient starting point for working with DateTime operations.<\/p>\n<pre lang=\"rust\"> \r\n\/\/ This script demonstrate working with events and date\/time calculations using the 'prelude' module.\r\n\r\n\/\/ It provides methods to create a new event, calculate the number of days until the event occurs, and format the event timestamp.\r\n\/\/ The main function creates an event, prints its details, calculates the days until the event\r\n\/\/ occurs from the current date, and formats the event timestamp.\r\n\r\nuse chrono::prelude::{Local, TimeZone, DateTime};\r\n\r\nstruct Event {\r\n    name: String,\r\n    timestamp: DateTime<Local>,\r\n}\r\n\r\nimpl Event {\r\n    fn new(name: &str, timestamp: DateTime<Local>) -> Self {\r\n        Event {\r\n            name: name.to_string(),\r\n            timestamp,\r\n        }\r\n    }\r\n\r\n    fn days_until(&self, other: DateTime<Local>) -> i64 {\r\n        let duration = other.signed_duration_since(self.timestamp);\r\n        duration.num_days()\r\n    }\r\n}\r\n\r\nfn main() {\r\n    \/\/ Create an event\r\n    let event_name = \"Meeting\";\r\n    let event_timestamp = Local.ymd(2024, 2, 15).and_hms(14, 30, 0); \r\n    let event = Event::new(event_name, event_timestamp);\r\n\r\n    \/\/ Print event details\r\n    println!(\"Event: {} at {}\", event.name, event.timestamp);\r\n\r\n    \/\/ Calculate days until the event\r\n    let today = Local::now(); \r\n    let days_until_event = event.days_until(today); \r\n    println!(\"Days until {}: {}\", event.name, days_until_event);\r\n\r\n    \/\/ Format the event timestamp\r\n    let formatted_timestamp = event.timestamp.format(\"%Y-%m-%d %H:%M:%S\");\r\n    println!(\"Formatted timestamp: {}\", formatted_timestamp);\r\n}\r\n<\/pre>\n<p>In the above example, importing the &#8216;prelude&#8217; module to use its date and time functionalities. The &#8220;Event&#8217; struct has and event&#8217;s name and timestamp. The timestamp is a type &#8216;DateTime<Local>&#8216;, which is a datetime type representing the local time zone.<\/p>\n<p>Inside the &#8216;impl&#8217; block, two methods like &#8216;new &#8216; and &#8216;days_until&#8217; are implemented for the &#8216;Event &#8216; struct, this will allow for the creating of new instances and calculating the time difference betweent events.<\/p>\n<p>In the &#8216;main&#8217; function it creates an instance of &#8216;Event&#8217; struct using the &#8216;Local::with_ymd_and_hms&#8217; method provided by &#8216;prelude&#8217; module to specify the date and time of the event and it prints the detauls of event including the name and date and timestamp.<br \/>\nAfter that it calculates the number of days until the event occurs  by using &#8216;Local::now&#8217; method to get the current local time.<br \/>\nThe &#8216;event.timestamp.format&#8217; is used to format the event&#8217;s timestamp provided bt &#8216;DateTime<Local>&#8216;.<\/p>\n<h4>Chrono Serde:<\/h4>\n<p>Serialization and deserialization are important while working with data. In Rust, the serde does that by providing a powerful framework for handling these tasks. When it is combined with the chrono crate, which is a date and time librsry in Rust, we can efficiently serialize and deserialize timestamps into a human-readable format.<\/p>\n<p>Below is an example where we have used ts_seconds which serialize and deserialize to\/from timestamps in seconds.<\/p>\n<pre lang=\"rust\"> \r\n\/\/In this script, Serde module is used form the chrono crate. \r\n\/\/Serializing and Deserializing Timestamp in seconds\r\n\r\nuse serde::{Serialize, Deserialize};\r\nuse chrono::{DateTime, Utc};\r\n\r\n#[derive(Debug, Serialize, Deserialize)]\r\npub struct SecStruct {\r\n    #[serde(with = \"chrono::serde::ts_seconds\")]\r\n    pub timestamp: DateTime<Utc>,\r\n    pub message: String,\r\n}\r\n\r\nimpl SecStruct {\r\n    pub fn new(message: &str) -> Self {\r\n        SecStruct {\r\n            timestamp: Utc::now(),\r\n            message: message.to_string(),\r\n        }\r\n    }\r\n\r\n    pub fn to_json(&self) -> Result<String, serde_json::Error> {\r\n        serde_json::to_string(self)\r\n    }\r\n\r\n    pub fn from_json(json: &str) -> Result<Self, serde_json::Error> {\r\n        serde_json::from_str(json)\r\n    }\r\n}\r\n\r\nfn main() {\r\n    \/\/ Create a new instance of SecStruct\r\n    let sec_struct = SecStruct::new(\"Hello!\");\r\n\r\n    \/\/ Convert the struct to JSON\r\n    let json_result = sec_struct.to_json();\r\n    match json_result {\r\n        Ok(json) => {\r\n            println!(\"JSON representation: {}\", json);\r\n\r\n            \/\/ Parse the JSON back into a SecStruct\r\n            let parsed_result = SecStruct::from_json(&json);\r\n            match parsed_result {\r\n                Ok(parsed_struct) => {\r\n                    println!(\"Parsed struct: {:?}\", parsed_struct);\r\n                }\r\n                Err(err) => {\r\n                    eprintln!(\"Error parsing JSON: {}\", err);\r\n                }\r\n            }\r\n        }\r\n        Err(err) => {\r\n            eprintln!(\"Error converting struct to JSON: {}\", err);\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>In this code, we define a SecStruct struct with two fields: timestamp and message.<\/p>\n<p>The timestamp field is annotated with #[serde(with = &#8220;chrono::serde::ts_seconds&#8221;)], indicating that the ts_seconds module from the chrono crate should be used during serialization and deserialization.<\/p>\n<p>The SecStruct struct also includes methods for creating a new instance, converting the struct to JSON (to_json), and parsing JSON back into a struct (from_json).<\/p>\n<p>In The main function, we create an instance of SecStruct, convert the struct to JSON, and then parsing the JSON back into a SecStruct.<\/p>\n<p>This code illustrates how to use the serde crate with the chrono crate&#8217;s ts_seconds module for efficient serialization and deserialization of Rust structs containing timestamp fields.<\/p>\n<h4>Chrono:Naive<\/h4>\n<p>The naive module in the chrono crate provides functionality for working with date and time without considering time zones or daylight saving time adjustments.<\/p>\n<p>Below is an example of using naive from chrono crate and how it is being implemented using methods<\/p>\n<pre lang=\"rust\"> \r\n\/\/ In this script the naive module is used to work with date and time\r\n\/\/ without considering timezone and daylight saving adjustments.\r\nuse chrono::naive::NaiveDate;\r\nuse chrono::Local;\r\n\r\n\/\/Define a struct\r\nstruct EventDate {\r\n    event_name: String,\r\n    event_date: NaiveDate,\r\n}\r\n\r\n\/\/Implement two methods for EventDate\r\nimpl EventDate {\r\n\r\n    pub fn new(event_name: &str, year: i32, month: u32, day: u32) -> Result<Self, &#038;'static str> {\r\n\r\n        let event_date = NaiveDate::from_ymd_opt(year, month, day);\r\n\r\n        match event_date {\r\n            Some(date) => Ok(Self {\r\n                event_name: String::from(event_name),\r\n                event_date: date,\r\n            }),\r\n            None => Err(\"Invalid date provided\"),\r\n        }\r\n    }\r\n\r\n    \/\/Check if the event is today\r\n    fn is_today(&self) -> bool {\r\n        let today = Local::now().date_naive();\r\n        self.event_date == today\r\n    }\r\n}\r\n\r\nfn main() {\r\n\r\n    match EventDate::new(\"Rust Demo Meeting\", 2023, 10, 27) {\r\n        Ok(event) => {\r\n\r\n            println!(\"Event: {}\", event.event_name);\r\n            println!(\"Event Date: {}\", event.event_date);\r\n\r\n            if event.is_today() {\r\n                println!(\"This event is scheduled for today!\");\r\n            } else {\r\n                println!(\"This event is not scheduled for today.\");\r\n            }\r\n        }\r\n        Err(err) => {\r\n            eprintln!(\"Error: {}\", err);\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>The code snippets used in this blog is available <a href=\"https:\/\/github.com\/ajitava-git\/rmotw-chrono\/tree\/main\/src\/bin\" rel=\"noopener\" target=\"_blank\">here.<\/a> <\/p>\n<h4>Hire technical testers from Qxf2<\/h4>\n<p>Testers from Qxf2 continually learn and evolve. We have excellent testing fundamentals and constantly update our technical toolbelt. Engineering teams love working with us because we understand the problems they face and are in a position to compliment their technical abilities. If you are having a hard time hiring technical testers, <a href=\"https:\/\/qxf2.com\/contact?utm_source=Clap_in_Rust&amp;utm_medium=click&amp;utm_campaign=From%20blog\">get in touch with Qxf2<\/a>.<\/p>\n<hr \/>\n","protected":false},"excerpt":{"rendered":"<p>Qxf2 is writing about commonly used Rust libraries. This series of posts is aimed at testers (like us) who want to start using Rust as part of their daily work. In this post, we will show you how to use Chrono. Chrono aims to provide all functionality needed to do correct operations on dates and times. Getting Started Setting up [&hellip;]<\/p>\n","protected":false},"author":38,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[412,306],"tags":[],"class_list":["post-21395","post","type-post","status-publish","format-standard","hentry","category-chrono","category-rust"],"_links":{"self":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/21395","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/users\/38"}],"replies":[{"embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/comments?post=21395"}],"version-history":[{"count":33,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/21395\/revisions"}],"predecessor-version":[{"id":22287,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/21395\/revisions\/22287"}],"wp:attachment":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/media?parent=21395"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/categories?post=21395"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/tags?post=21395"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}