Repository: datanymizer/datanymizer (language: rust)

Issue:
datetime format issues
```
      birth_month: 
        datetime:
          format: '%m'
```
throws error `Error: Failed transform trailing input`

```
      birth_month: 
        datetime:
          format: %m
```
throws error `Error: unexpected character: '%' at line 68 column 19 in config.yaml`


Discussion / hints:
Hello! I will take a look.

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 312bd38c..048a707e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,7 +10,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ### ⚙️ Changed
 
 ### 🛠 Fixed
-- Fix Postgres COPY syntax when dumping a table with zero defined fields [#147](https://github.com/datanymizer/datanymizer/pull/147)  ([@mbeynon](https://github.com/mbeynon))
+- Fix Postgres COPY syntax when dumping a table with zero defined fields
+  [#147](https://github.com/datanymizer/datanymizer/pull/147) ([@mbeynon](https://github.com/mbeynon))
+- Fix the bug with a datetime format [#150](https://github.com/datanymizer/datanymizer/pull/150)
+  ([@evgeniy-r](https://github.com/evgeniy-r))
 
 ## [v0.5.1] - 2021-12-05
 ### 🚀 Added
diff --git a/datanymizer_engine/src/transformers/datetime.rs b/datanymizer_engine/src/transformers/datetime.rs
index 5e6496e5..83bb845c 100644
--- a/datanymizer_engine/src/transformers/datetime.rs
+++ b/datanymizer_engine/src/transformers/datetime.rs
@@ -11,6 +11,8 @@ pub struct ToValue(String);
 #[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Hash, Clone, Debug)]
 pub struct Format(String);
 
+const BOUNDS_FORMAT: &str = "%Y-%m-%dT%H:%M:%S%.f%:z";
+
 /// Generates random dates.
 ///
 /// # Example:
@@ -35,8 +37,10 @@ pub struct Format(String);
 ///       to: 2010-12-31T00:00:00+00:00
 /// ```
 ///
-/// Also, you can specify datetime format.
-/// Be careful with it...
+/// Also, you can specify datetime format for the output.
+/// For the bounds (from/to) you should use the RFC 3339 format.
+/// The default output format is also RFC 3339 (%Y-%m-%dT%H:%M:%S%.f%:z).
+/// You don't need to change the format when using this transformer with datetime SQL fields.
 ///
 /// ```yaml
 /// #...
@@ -45,7 +49,7 @@ pub struct Format(String);
 ///     datetime:
 ///       from: 1990-01-01T00:00:00+00:00
 ///       to: 2010-12-31T00:00:00+00:00
-///       format: %Y-%m-%dT%H:%M:%S%.f%:z
+///       format: %Y-%m-%d
 /// ```
 #[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Clone, Debug, Default)]
 pub struct RandomDateTimeTransformer {
@@ -71,7 +75,7 @@ impl Default for ToValue {
 
 impl Default for Format {
     fn default() -> Self {
-        Self(String::from("%Y-%m-%dT%H:%M:%S%.f%:z"))
+        Self(String::from(BOUNDS_FORMAT))
     }
 }
 
@@ -82,11 +86,45 @@ impl Transformer for RandomDateTimeTransformer {
         _field_value: &str,
         _ctx: &Option<TransformContext>,
     ) -> TransformResult {
-        let from_dt = DateTime::parse_from_str(&self.from.0, &self.format.0)?.with_timezone(&Utc);
-        let to_dt = DateTime::parse_from_str(&self.to.0, &self.format.0)?.with_timezone(&Utc);
+        let from_dt = DateTime::parse_from_str(&self.from.0, BOUNDS_FORMAT)?.with_timezone(&Utc);
+        let to_dt = DateTime::parse_from_str(&self.to.0, BOUNDS_FORMAT)?.with_timezone(&Utc);
         let between: chrono::DateTime<Utc> = DateTimeBetween(EN, from_dt, to_dt).fake();
         let res: String = between.format(&self.format.0).to_string();
 
         TransformResult::present(res)
     }
 }
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    fn transformed_value(cfg: &str) -> String {
+        let transformer: RandomDateTimeTransformer = serde_yaml::from_str(cfg).unwrap();
+        transformer
+            .transform("datetime", "", &None)
+            .unwrap()
+            .unwrap()
+    }
+
+    #[test]
+    fn default_format() {
+        let cfg = r#"
+                          from: 2010-10-01T00:00:00+00:00
+                          to: 2010-10-31T00:00:00+00:00
+                       "#;
+        let result = transformed_value(cfg);
+        assert!(result.starts_with("2010-10-"));
+    }
+
+    #[test]
+    fn custom_format() {
+        let cfg = r#"
+                          format: "%m"
+                          from: 2000-12-01T00:00:00+00:00
+                          to: 2000-12-31T00:00:00+00:00
+                       "#;
+        let result = transformed_value(cfg);
+        assert_eq!(result, "12");
+    }
+}


Test patch:
diff --git a/datanymizer_dumper/tests/postgres/dumper.rs b/datanymizer_dumper/tests/postgres/dumper.rs
index bf265ad3..c328c0a5 100644
--- a/datanymizer_dumper/tests/postgres/dumper.rs
+++ b/datanymizer_dumper/tests/postgres/dumper.rs
@@ -52,10 +52,11 @@ fn simple_dump() {
 
         let src_first_name: String = src_row.get("first_name");
         let dst_first_name: String = dst_row.get("first_name");
-        assert_ne!(src_first_name, dst_first_name);
-
         let src_last_name: String = src_row.get("last_name");
         let dst_last_name: String = dst_row.get("last_name");
-        assert_ne!(src_last_name, dst_last_name);
+        assert_ne!(
+            format!("{} {}", src_first_name, src_last_name),
+            format!("{} {}", dst_first_name, dst_last_name)
+        );
     }
 }