From e5b29648c075940cc1667cb0563e657803a5f943 Mon Sep 17 00:00:00 2001 From: Jannik Beyerstedt Date: Sun, 25 Nov 2018 14:21:21 +0100 Subject: [PATCH] [CODE] parsing CSV, no speakers yet --- main.go | 177 +++++++++++++++++++++++++++++++++++++++------------ schedule.csv | 17 ++++- 2 files changed, 152 insertions(+), 42 deletions(-) diff --git a/main.go b/main.go index aa0d0a9..8fc6053 100644 --- a/main.go +++ b/main.go @@ -7,10 +7,22 @@ import ( "fmt" "log" "os" + "strconv" "text/template" "time" ) +var timeCSVFormat = "2.1.06 15:04" // input format +var timeXMLDateFormat = "2006-01-02" // frab xml format for dates +var timeXMLTimeFormat = "15:04" // frab xml format for times + +const csvColTitle = 0 +const csvColRoom = 1 +const csvColStart = 2 +const csvColEnd = 3 +const csvColSpeaker = 4 +const csvColLang = 5 + type frabSchedule struct { Conf conference Days []day @@ -55,6 +67,14 @@ type person struct { Name string } +func fmtDuration(d time.Duration) string { + d = d.Round(time.Minute) + h := d / time.Hour + d -= h * time.Hour + m := d / time.Minute + return fmt.Sprintf("%02d:%02d", h, m) +} + func main() { fmt.Println("Conference Schedule: CSV to Frab (Infobeamer) Converter") @@ -67,7 +87,9 @@ func main() { log.Fatal("Error opening CSV file:\n", err) } - records, err := csv.NewReader(csvFile).ReadAll() + csvReader := csv.NewReader(csvFile) + csvReader.Comma = ';' // MS excel default export format + records, err := csvReader.ReadAll() if err != nil { log.Fatal("Error reading CSV file:\n", err) } @@ -75,51 +97,114 @@ func main() { // omit title row csvRecords := records[1:] - fmt.Println(csvRecords) // TODO + // fmt.Println(csvRecords) // TODO /* * Data Conversion */ - timeDateFormat := "2006-01-02" - // timeTimeFormat := "15:04" + roomsList := make(map[time.Time]map[string]int) // map of day's start time to map of room names + var conferenceStart time.Time + var conferenceEnd time.Time + loc, _ := time.LoadLocation("Europe/Berlin") + + for idx, row := range csvRecords { + // parse event times + eventStart, err := time.ParseInLocation(timeCSVFormat, row[csvColStart], loc) + if err != nil { + log.Fatal("Error parsing start date in CSV file, line ", idx+1, ":\n", err) + } + eventEnd, err := time.ParseInLocation(timeCSVFormat, row[csvColEnd], loc) + if err != nil { + log.Fatal("Error parsing end date in CSV file, line ", idx+1, ":\n", err) + } + + // create unique list of the rooms for each day + dayStart := eventStart.Truncate(24 * time.Hour) + if roomsList[dayStart] == nil { + roomsList[dayStart] = make(map[string]int) + } + roomsList[dayStart][row[csvColRoom]] = 1 + + // get conference start and end date + if idx == 0 { + conferenceStart = eventStart + conferenceEnd = eventEnd + } + if eventStart.Before(conferenceStart) { + conferenceStart = eventStart + } + if eventEnd.After(conferenceEnd) { + conferenceEnd = eventEnd + } + } + + conferenceStart = conferenceStart.Truncate(24 * time.Hour) + conferenceEnd = conferenceEnd.Truncate(24 * time.Hour).Add(24 * time.Hour) + + // convert csv entries into event and sort in days + events := make(map[int][]event) // map of day index to day's events + eventID := 100 + confDays := make(map[int]day) // map of day index to day structure + + for idx, row := range csvRecords { + // TODO: add speakers + + eventStart, err := time.ParseInLocation(timeCSVFormat, row[csvColStart], loc) + if err != nil { + log.Fatal("Error parsing start date in CSV file, line ", idx+1, ":\n", err) + } + eventEnd, err := time.ParseInLocation(timeCSVFormat, row[csvColEnd], loc) + if err != nil { + log.Fatal("Error parsing end date in CSV file, line ", idx+1, ":\n", err) + } + + dayIdx := int(eventStart.Sub(conferenceStart).Hours()/24) + 1 + eventGUID := strconv.Itoa(dayIdx) + "-" + strconv.Itoa(eventID) + eventDateStr := eventStart.Format(time.RFC3339) + eventStartStr := eventStart.Format(timeXMLTimeFormat) + eventDurationStr := fmtDuration(eventEnd.Sub(eventStart)) + + events[dayIdx] = append(events[dayIdx], event{eventID, eventGUID, row[csvColRoom], row[csvColTitle], eventDateStr, eventStartStr, eventDurationStr, row[csvColLang], nil}) + + // create days + if _, ok := confDays[dayIdx]; !ok { + dayDateStr := eventStart.Format(timeXMLDateFormat) + dayStart := eventStart.Truncate(24 * time.Hour) + dayEnd := dayStart.Add(24 * time.Hour) + dayStartStr := dayStart.Format(time.RFC3339) + dayEndStr := dayEnd.Format(time.RFC3339) + + var dayRooms []room + for roomName := range roomsList[dayStart] { + dayRooms = append(dayRooms, room{roomName, nil}) + } + + confDays[dayIdx] = day{dayIdx, dayDateStr, dayStartStr, dayEndStr, dayRooms} + } + + eventID++ + } + + // sort events to rooms and day structures + for dayIdx, eventDay := range events { + for _, event := range eventDay { + for roomIdx, roomName := range confDays[dayIdx].Rooms { + if roomName.Name == event.Room { + confDays[dayIdx].Rooms[roomIdx].Events = append(confDays[dayIdx].Rooms[roomIdx].Events, event) + } + } + } + } // new conference - cmdTitle := "Test Conference" // TODO: get from command line - cmdStart := "2018-11-18" // TODO: get from command line - cmdEnd := "2018-11-19" // TODO: get from command line + confDurationDays := int(conferenceEnd.Sub(conferenceStart).Hours() / 24) + conf := conference{"Wälderhaus Veranstaltung", conferenceStart.Format(time.RFC3339), conferenceEnd.Format(time.RFC3339), confDurationDays} - cmdStartTime, _ := time.Parse(timeDateFormat, cmdStart) - cmdEndTime, _ := time.Parse(timeDateFormat, cmdEnd) + var days []day + for _, d := range confDays { + days = append(days, d) + } - confDurationDays := int(cmdEndTime.Sub(cmdStartTime).Hours()/24) + 1 - conf := conference{cmdTitle, cmdStart, cmdEnd, confDurationDays} - - // gather all rooms and persons - // TODO - - // TODO: make room and day structs - - // sort by room and day into structure - // TODO - // valid rooms: Heuckenlock, Heuckenlock {Ebbe, Flut}, Holzhafen, Raackmoor, Wohldorfer Wald - - // assign the conference and days to the schedule - speaker1 := person{1, "Frau Testperson"} - - day1Room1Event1 := event{123, "1-123", "Heuckenlock", "Opening Keynote", "2018-11-18T21:00:00+01:00", "21:00", "01:00", "", []person{speaker1}} - day1Room1Event2 := event{124, "1-124", "Heuckenlock", "Quartalszahlen", "2018-11-18T22:00:00+01:00", "22:00", "00:30", "de", []person{speaker1}} - day1Room1Events := []event{day1Room1Event1, day1Room1Event2} - day1Room1 := room{"Heuckenlock", day1Room1Events} - - day1Room2Event1 := event{223, "", "Holzhafen", "Room 2 Talk 1", "2018-11-18T21:00:00+01:00", "21:00", "01:00", "", []person{speaker1}} - day1Room2Event2 := event{224, "", "Holzhafen", "Room 2 Title 2", "2018-11-18T22:00:00+01:00", "22:00", "00:30", "", []person{speaker1}} - day1Room2Events := []event{day1Room2Event1, day1Room2Event2} - day1Room2 := room{"Holzhafen", day1Room2Events} - - day1Rooms := []room{day1Room1, day1Room2} - day1 := day{1, "2018-11-18", "2018-11-18T00:00:00+01:00", "2018-11-19T00:00:00+01:00", day1Rooms} - - days := []day{day1} sched := frabSchedule{conf, days} /* @@ -145,7 +230,21 @@ func main() { /* * Print Summary */ - // TODO + fmt.Println("- Conference Start:", conferenceStart) + fmt.Println("- Conference End :", conferenceEnd) + fmt.Println("- Days :", confDurationDays) + fmt.Println("- Events :", eventID-100) + + // fmt.Println("Dump days:") + // for _, day := range days { + // fmt.Println("Day", day.Index) + // for _, room := range day.Rooms { + // fmt.Println(" Room", room.Name) + // for _, event := range room.Events { + // fmt.Println(" Event", event) + // } + // } + // } fmt.Println("done") } diff --git a/schedule.csv b/schedule.csv index de1fea9..538d82f 100644 --- a/schedule.csv +++ b/schedule.csv @@ -1,3 +1,14 @@ -Titel, Raum, Von, Bis, Speaker, Sprache (DE/EN) -Very good talk, Holzhafen, 19.11.2018 12:00, 19.11.2018 13:00:00, frab-user, de -Keynote, Heuckenlock Ebbe, 19.11.2018 12:00, 19.11.2018 13:00:00, frab-user, de +Titel des Programmpunktes;Raum;Von (TT.MM.JJ HH:MM);Bis (TT.MM.JJ HH:MM);Vortragende;Sprache (DE/EN) +Begrüßung;Holzhafen;25.11.18 12:00;25.11.18 13:00;Ada Lovelace;EN +Vortrag 1;Raackmoor;25.11.18 12:00;25.11.18 13:00;Marie Curie; +Noch ein Vortrag;Wohldorfer Wald;25.11.18 12:00;25.11.18 13:00;Donna Strickland; +Workshop;Heuckenlock;25.11.18 12:00;25.11.18 13:00;Edith Clarke; +Testvortrag Ebbe;Heuckenlock Ebbe;25.11.18 12:00;25.11.18 13:00;Bjarne Stroustrup; +Testvortrag Flut;Heuckenlock Flut;25.11.18 12:00;25.11.18 13:00;Chris Lattner; +Test 1;Holzhafen;25.11.18 13:00;25.11.18 13:30;; +Test 2;Raackmoor;25.11.18 13:00;25.11.18 13:30;; +Test 3;Wohldorfer Wald;25.11.18 13:00;25.11.18 13:30;; +Test 4;Heuckenlock;25.11.18 13:00;25.11.18 13:30;; +Test 5;Heuckenlock Ebbe;25.11.18 13:00;25.11.18 13:30;; +Test 6;Heuckenlock Flut;25.11.18 13:00;25.11.18 13:30;; +Test 7;Heuckenlock Flut;24.11.18 13:00;24.11.18 13:30;; \ No newline at end of file