0

A Person has a first_name and a last_name. How do I add a time of export to a CSV when writing an instance of Person to a CSV?

#[macro_use]
extern crate serde_derive;
extern crate csv;
extern crate serde;

use std::time::{SystemTime, UNIX_EPOCH};

#[derive(Debug, Serialize, Deserialize)]
struct Person {
    first_name: String,
    last_name: String,
}

fn current_ms() -> u64 {
    let since_the_epoch = &SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
    let ms = since_the_epoch.as_secs() * 1000 + since_the_epoch.subsec_nanos() as u64 / 1_000_000;
    ms
}

fn main() {
    let person = Person {
        first_name: "Craig".to_string(),
        last_name: "David".to_string(),
    };
    let file_path = std::path::Path::new("test.csv");
    let mut wtr = csv::Writer::from_path(file_path).unwrap();
    wtr.serialize(&person).unwrap();
    println!("{}", current_ms());
}

The above code results in:

>>> cat test.csv
first_name,last_name
Craig,David

My objective is to generate a file which is in the format:

>>> cat test.csv
time,first_name,last_name
1527661792118,Craig,David

Serde attributes do not have an option to add an additional field. In the above example the Person struct does not contain a time value. The time value is only required when the data is written to a CSV.

Greg
  • 8,175
  • 16
  • 72
  • 125
  • I believe your question is answered by the answers of [How to transform fields during serialization using Serde?](https://stackoverflow.com/q/39383809/155423). If you disagree, please [edit] your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster May 30 '18 at 10:06
  • @Shepmaster I've updated the post to explain why serde attributes do not appear to be a solution. – Greg May 30 '18 at 10:17
  • Did you read **both** parts of the answer? I know it's a very long answer, but read the part with "to create a separate struct". – Shepmaster May 30 '18 at 10:37
  • I've reorganized that answer to make it clear that there are two solutions presented. – Shepmaster May 30 '18 at 10:55
  • @Shepmaster Thanks! It took a while for me to understand how your solution worked however I got it in the end :) – Greg May 30 '18 at 11:14

1 Answers1

4

If you don't want to add a timestamp column to Person, you can create a separate struct for that and then join them together in a tuple:

#[derive(Debug, Deserialize, Serialize)]
struct Timestamp {
    time: u64,
}

impl Timestamp {
    fn now() -> Timestamp {
        Timestamp { time: current_ms() }
    }
}

fn main() {
    let person = Person {
        first_name: "Craig".to_string(),
        last_name: "David".to_string(),
    };
    let person_and_time = (Timestamp::now(), person);
    let file_path = std::path::Path::new("test.csv");
    let mut wtr = csv::Writer::from_path(file_path).unwrap();
    wtr.serialize(&person_and_time).unwrap();
}
Peter Hall
  • 53,120
  • 14
  • 139
  • 204