1 00:00:06,570 --> 00:00:09,540 - Applications often need to create objects from Strings, 2 00:00:09,540 --> 00:00:11,280 and for example, in our application, 3 00:00:11,280 --> 00:00:14,700 we have a String representing year, month, day, 4 00:00:14,700 --> 00:00:17,430 and we need to convert it into a date object, NaiveDate. 5 00:00:17,430 --> 00:00:20,850 So in util.rs, gonna see these functions 6 00:00:20,850 --> 00:00:23,520 to achieve that effect and prompt_for_date 7 00:00:23,520 --> 00:00:24,930 and date_from_str. 8 00:00:24,930 --> 00:00:26,190 Okay, I've written these functions 9 00:00:26,190 --> 00:00:28,983 to help me with date String conversions. 10 00:00:30,030 --> 00:00:33,210 Okay then, so in util.rs, so first of all, 11 00:00:33,210 --> 00:00:34,680 let's give you a quick reminder, 12 00:00:34,680 --> 00:00:38,100 prompt_for_string, and the purpose of the function, 13 00:00:38,100 --> 00:00:38,970 you call the function. 14 00:00:38,970 --> 00:00:41,910 You pass in a message, a prompt message 15 00:00:41,910 --> 00:00:43,590 to tell the user what you want, 16 00:00:43,590 --> 00:00:45,393 and it should return a String. 17 00:00:46,290 --> 00:00:49,500 So it displays the message that we passed in 18 00:00:49,500 --> 00:00:52,020 asking the user to enter something. 19 00:00:52,020 --> 00:00:55,290 I create an empty String object here, 20 00:00:55,290 --> 00:01:00,187 and then in the std::io module, there's a std::in function. 21 00:01:00,187 --> 00:01:03,780 Basically it represents the standard input device. 22 00:01:03,780 --> 00:01:06,810 It's like cin in C++. 23 00:01:07,650 --> 00:01:09,960 It's like Console in C#. 24 00:01:09,960 --> 00:01:13,193 Anyway, from the input device, I read a line, okay? 25 00:01:14,640 --> 00:01:16,653 And I store it in the String. 26 00:01:17,640 --> 00:01:22,640 So it's a bit like scanf in C, if you remember that. 27 00:01:22,950 --> 00:01:26,550 It returns a result, so I unwrap the result, okay? 28 00:01:26,550 --> 00:01:30,210 And I return the String that's been entered. 29 00:01:30,210 --> 00:01:32,550 The String here, which is empty initially, 30 00:01:32,550 --> 00:01:35,430 will be populated by the read_line function, 31 00:01:35,430 --> 00:01:38,220 and then I return that String back to the user. 32 00:01:38,220 --> 00:01:39,540 So that was easy enough. 33 00:01:39,540 --> 00:01:41,940 I've got a similar kinda thing, prompt_for_date. 34 00:01:43,680 --> 00:01:45,600 It takes a message asking the user, you know, 35 00:01:45,600 --> 00:01:50,100 please enter a date, and it's meant to return a NaiveDate. 36 00:01:50,100 --> 00:01:55,100 So it calls the prompt_for_string method 37 00:01:55,710 --> 00:01:59,220 that we just looked at to display the message, 38 00:01:59,220 --> 00:02:00,820 and that gives me back a String. 39 00:02:02,266 --> 00:02:04,200 Okay, so that's a bit of reuse going on there. 40 00:02:04,200 --> 00:02:07,020 I've reused my prompt_for_string function already, 41 00:02:07,020 --> 00:02:09,780 gives me back a String that the user has entered. 42 00:02:09,780 --> 00:02:11,430 I get rid of any white space 43 00:02:11,430 --> 00:02:14,190 in case the user had spaces at the beginning and end, 44 00:02:14,190 --> 00:02:19,190 and then I pass that function into date_from_str down here. 45 00:02:19,200 --> 00:02:21,810 Okay, so it turns out that this date_from_str 46 00:02:21,810 --> 00:02:25,620 is a generally useful function that I might use elsewhere 47 00:02:25,620 --> 00:02:28,200 where you've got a String or a String slice, 48 00:02:28,200 --> 00:02:32,130 and it parses it to give you back a date object, NaiveDate. 49 00:02:32,130 --> 00:02:35,370 So this is the interesting function really, I guess. 50 00:02:35,370 --> 00:02:39,720 Here's a String. Parse that String into NaiveDate. 51 00:02:39,720 --> 00:02:42,333 So it turns out it's just a simple wrapper. 52 00:02:43,260 --> 00:02:47,700 The NaiveDate structure has a parse_from_str 53 00:02:47,700 --> 00:02:50,433 associated function or static function. 54 00:02:51,420 --> 00:02:56,340 You give it a String that contains a stringified date, 55 00:02:56,340 --> 00:02:58,740 and then you tell it the format to expect. 56 00:02:58,740 --> 00:03:01,530 So obviously you can have a look at the documentation 57 00:03:01,530 --> 00:03:03,780 in the NaiveDate structure to see 58 00:03:03,780 --> 00:03:05,470 what the different options are here. 59 00:03:05,470 --> 00:03:07,990 %Y, four-digit year. 60 00:03:07,990 --> 00:03:11,220 %m, month. %d, day. 61 00:03:11,220 --> 00:03:14,130 So it needs to know the format of the incoming String 62 00:03:14,130 --> 00:03:17,910 to see where's the year part, where's the month part, 63 00:03:17,910 --> 00:03:20,970 where's the date part in the incoming String, 64 00:03:20,970 --> 00:03:22,590 and again, I unwrap that result 65 00:03:22,590 --> 00:03:25,320 and I return it back to the code. 66 00:03:25,320 --> 00:03:28,950 All right, so you could argue that this function here, 67 00:03:28,950 --> 00:03:32,133 I could've just called that function directly up here, 68 00:03:34,391 --> 00:03:35,943 and I could've done that, 69 00:03:37,050 --> 00:03:39,600 but sometimes it's nice to just wrap up 70 00:03:39,600 --> 00:03:43,950 some low-level API behind your own function 71 00:03:43,950 --> 00:03:47,400 because that function could in the future evolve 72 00:03:47,400 --> 00:03:50,250 to do something a little bit more complete. 73 00:03:50,250 --> 00:03:53,220 Okay, so I was quite happy with those functions. 74 00:03:53,220 --> 00:03:56,040 So the next thing we're going to look at is how to actually, 75 00:03:56,040 --> 00:03:58,770 in the context of my application scenario, 76 00:03:58,770 --> 00:04:00,570 which is all about visits to Europe 77 00:04:00,570 --> 00:04:04,200 in a 180-day period in Schengen, 78 00:04:04,200 --> 00:04:07,140 how do I actually implement that logic, 79 00:04:07,140 --> 00:04:11,160 the actual scenario, in my application? 80 00:04:11,160 --> 00:04:13,050 And it turns out I had to do quite a lot 81 00:04:13,050 --> 00:04:15,210 of date manipulation. 82 00:04:15,210 --> 00:04:16,800 So we're gonna look at that now, 83 00:04:16,800 --> 00:04:20,040 and this will be the end of our discussions. 84 00:04:20,040 --> 00:04:22,380 This is the only bit that we haven't yet seen. 85 00:04:22,380 --> 00:04:26,400 In menu.rs, we're going to see the options 86 00:04:26,400 --> 00:04:28,470 for basically displaying the dates 87 00:04:28,470 --> 00:04:30,030 within a certain period of interest, 88 00:04:30,030 --> 00:04:31,800 which is the whole point of the demo. 89 00:04:31,800 --> 00:04:33,360 So there's a couple of functions we're gonna look at. 90 00:04:33,360 --> 00:04:36,970 Get_days_prior_to is a function I've written 91 00:04:36,970 --> 00:04:39,450 and display_days_within_period_of_interest. 92 00:04:39,450 --> 00:04:40,980 I'm trying to go for the world record 93 00:04:40,980 --> 00:04:42,843 for the longest function name ever. 94 00:04:43,710 --> 00:04:45,570 So let's have a look at those then. 95 00:04:45,570 --> 00:04:50,570 So in menu.rs, just a quick reminder 96 00:04:50,670 --> 00:04:53,580 just to kind of set the scene, 97 00:04:53,580 --> 00:04:56,670 the menu function, or do_menu, 98 00:04:56,670 --> 00:04:59,643 it displays a list of options to the user, 99 00:05:00,660 --> 00:05:05,010 and we've covered all of these apart from option 2. 100 00:05:05,010 --> 00:05:07,740 How do I calculate the number of days 101 00:05:07,740 --> 00:05:11,463 when I've been away from a specified date? 102 00:05:12,840 --> 00:05:16,590 Right, so if the user chooses option 2, 103 00:05:16,590 --> 00:05:19,957 it calls the display_days_within_period_of_interest, 104 00:05:19,957 --> 00:05:22,650 and it gives you all the visits, it takes in all the visits, 105 00:05:22,650 --> 00:05:25,800 and it calculates how many days you've been away. 106 00:05:25,800 --> 00:05:27,506 So let's have a look at this function now, 107 00:05:27,506 --> 00:05:30,756 display_days_within_period_of_interest. 108 00:05:34,770 --> 00:05:35,943 So here we are. 109 00:05:37,800 --> 00:05:40,980 I'm gonna go through this function in a couple of steps. 110 00:05:40,980 --> 00:05:44,373 I'm just gonna give us a little bit more space as well. 111 00:05:46,110 --> 00:05:48,210 I'm gonna run the application actually before I do this 112 00:05:48,210 --> 00:05:51,360 just to remind you of what that option does. 113 00:05:51,360 --> 00:05:52,810 Let's open up a new terminal. 114 00:05:54,240 --> 00:05:56,970 I run the application, cargo run. 115 00:05:56,970 --> 00:05:58,500 Remember, when the application starts, 116 00:05:58,500 --> 00:06:01,893 it immediately loads in the data from data.txt, 117 00:06:02,730 --> 00:06:04,530 and it builds the collection of visits. 118 00:06:04,530 --> 00:06:06,900 So it's already done all that, 119 00:06:06,900 --> 00:06:08,400 and then it displays the menu, 120 00:06:08,400 --> 00:06:10,500 and its option 2 is what we're interested in, 121 00:06:10,500 --> 00:06:13,530 calculate visit days within period of interest. 122 00:06:13,530 --> 00:06:16,710 So I'll choose option 2, okay? 123 00:06:16,710 --> 00:06:20,040 And you see the first thing it does, I'm in here now. 124 00:06:20,040 --> 00:06:24,390 What reference date do you want to use? Year, month, day. 125 00:06:24,390 --> 00:06:27,570 All right, so I'll enter, let's say, 126 00:06:27,570 --> 00:06:31,290 2023-12-31, 127 00:06:31,290 --> 00:06:34,470 New Year's Eve 2023. 128 00:06:34,470 --> 00:06:38,830 When I press Enter, this is the function 129 00:06:40,230 --> 00:06:44,820 which is currently going to be processing. 130 00:06:44,820 --> 00:06:47,370 So I pass that message into the function. 131 00:06:47,370 --> 00:06:49,530 This function is currently running, 132 00:06:49,530 --> 00:06:52,500 and it's waiting for me to press Enter down here. 133 00:06:52,500 --> 00:06:55,740 When I press Enter, it'll do the work we just looked at, 134 00:06:55,740 --> 00:06:57,420 and it'll give me back a date, 135 00:06:57,420 --> 00:06:59,160 and that date object will represent 136 00:06:59,160 --> 00:07:01,710 the 31st of December, 2023. 137 00:07:01,710 --> 00:07:02,880 So I press Enter. 138 00:07:02,880 --> 00:07:04,380 What it's then gonna do, obviously, 139 00:07:04,380 --> 00:07:06,033 is to display all the results. 140 00:07:07,530 --> 00:07:09,180 So I wanna remind you a couple of things. 141 00:07:09,180 --> 00:07:12,990 First of all, it displays two batches of results, right? 142 00:07:12,990 --> 00:07:15,033 Go back up to the top of the output. 143 00:07:18,630 --> 00:07:20,820 So there are lots of visits here. 144 00:07:20,820 --> 00:07:24,963 The first set of results is chronological. 145 00:07:26,220 --> 00:07:28,950 Okay, so from the date that I specified, 146 00:07:28,950 --> 00:07:33,840 the 31st of December, 2023, it displays the number of days. 147 00:07:33,840 --> 00:07:36,240 It takes the 31st of December, 148 00:07:36,240 --> 00:07:38,770 and it displays the number of days I've been away 149 00:07:40,281 --> 00:07:43,163 for 180 days prior to that date, okay? 150 00:07:44,610 --> 00:07:49,610 So each of these things being displayed here is a Record. 151 00:07:49,710 --> 00:07:52,350 Remember the Record structure? 152 00:07:52,350 --> 00:07:54,263 Let me give you a quick reminder of that. 153 00:07:58,080 --> 00:08:02,730 The Record structure, it says how many days were you away, 154 00:08:02,730 --> 00:08:07,230 and what's the date 155 00:08:07,230 --> 00:08:08,520 that we're talking about, okay? 156 00:08:08,520 --> 00:08:11,880 So if it says if the date 157 00:08:11,880 --> 00:08:15,360 was the 31st of December, 158 00:08:15,360 --> 00:08:18,210 it'll tell me how many days were you away 159 00:08:18,210 --> 00:08:20,700 180 days prior to that, okay? 160 00:08:20,700 --> 00:08:25,200 So from this date here, the 31st of December, 161 00:08:25,200 --> 00:08:28,080 I was away 67 days 162 00:08:28,080 --> 00:08:31,203 in the 180-day period prior to that, 163 00:08:32,190 --> 00:08:36,090 but it doesn't just display the number of days I was away 164 00:08:36,090 --> 00:08:37,710 on the 31st of December. 165 00:08:37,710 --> 00:08:41,880 It also displays the number of days on the 30th of December 166 00:08:41,880 --> 00:08:43,770 and the 29th of December. 167 00:08:43,770 --> 00:08:45,300 The whole point of the application 168 00:08:45,300 --> 00:08:47,520 was not to just give me a single snapshot in time 169 00:08:47,520 --> 00:08:51,030 but to show me a historical record of all dates, 170 00:08:51,030 --> 00:08:53,820 so not only for the date that I've entered 171 00:08:53,820 --> 00:08:57,480 but all other dates, and it basically does all dates. 172 00:08:57,480 --> 00:09:00,540 It'll say, if I scroll down here, for example, 173 00:09:00,540 --> 00:09:04,080 let's just pick a random date, the 5th of November. 174 00:09:04,080 --> 00:09:06,990 That's Bonfire Night, Guy Fawkes Night in the UK. 175 00:09:06,990 --> 00:09:11,293 It says, "In your current calendar on the 11th, 176 00:09:11,293 --> 00:09:14,730 on the 5th of November, you will have been away, 177 00:09:14,730 --> 00:09:17,640 in the 180 days before the 5th of November, 178 00:09:17,640 --> 00:09:20,700 you will have been away for 88 days," all right? 179 00:09:20,700 --> 00:09:24,363 So that's what's going on in my application. 180 00:09:25,410 --> 00:09:27,780 It's gonna build collection of Records. 181 00:09:27,780 --> 00:09:30,000 Each one of these is a Record with a date 182 00:09:30,000 --> 00:09:32,290 and the number of days I've been away 183 00:09:33,330 --> 00:09:35,943 in the 180-day period before that. 184 00:09:37,410 --> 00:09:42,270 So it takes, this date here is the date that I entered, 185 00:09:42,270 --> 00:09:47,270 the 31st of December, 2023, and it basically, 186 00:09:47,370 --> 00:09:52,370 it'll iterate over all dates from now, from that date, 187 00:09:52,380 --> 00:09:57,380 up to and including the current date going backwards, okay? 188 00:09:57,960 --> 00:09:59,010 Each time around the loop, 189 00:09:59,010 --> 00:10:02,220 it'll subtract one day from the date. 190 00:10:02,220 --> 00:10:03,330 First time around the loop, 191 00:10:03,330 --> 00:10:06,873 the date is the 31st of December. 192 00:10:08,790 --> 00:10:11,610 31st of December. That's the current date. 193 00:10:11,610 --> 00:10:14,670 Is the date greater than or equal to the current date? 194 00:10:14,670 --> 00:10:18,720 I mean today. Today here is the, check phone. 195 00:10:18,720 --> 00:10:21,213 It's the 26th of May I'm here. 196 00:10:22,050 --> 00:10:23,760 So it's a bit tricky, 197 00:10:23,760 --> 00:10:27,030 but there's an API to get the current date. 198 00:10:27,030 --> 00:10:28,320 It's the 26th of May. 199 00:10:28,320 --> 00:10:31,350 So this loop is gonna go from the 31st of December 200 00:10:31,350 --> 00:10:35,130 all the way down to the 26th of May, 201 00:10:35,130 --> 00:10:37,290 decrementing as we go. 202 00:10:37,290 --> 00:10:38,643 So if I scroll down here, 203 00:10:39,570 --> 00:10:41,470 it's gonna have to scroll quite a lot. 204 00:10:42,630 --> 00:10:43,860 How far is it gonna go? 205 00:10:43,860 --> 00:10:46,620 There we go, down to today, the 26th of May, 206 00:10:46,620 --> 00:10:48,600 as my phone just told me. 207 00:10:48,600 --> 00:10:52,170 Each time round, and I'll show you how it does this, 208 00:10:52,170 --> 00:10:55,350 it'll say if we're talking about a particular date, 209 00:10:55,350 --> 00:10:57,630 so let's again pick a date at random, 210 00:10:57,630 --> 00:10:59,460 the, oh, I'll tell you what we'll do. 211 00:10:59,460 --> 00:11:02,310 We'll choose the 11th of August. 212 00:11:02,310 --> 00:11:06,240 That was our wedding date back in 1990, the 11th of August. 213 00:11:06,240 --> 00:11:07,620 So let's say that's the date. 214 00:11:07,620 --> 00:11:09,180 It's gonna iterate through all the dates, 215 00:11:09,180 --> 00:11:11,700 but let's say that's the current date it's looking at. 216 00:11:11,700 --> 00:11:14,940 All right, so it'll say prior to that date, 217 00:11:14,940 --> 00:11:17,850 look at all the visits that you'd been away altogether 218 00:11:17,850 --> 00:11:21,930 and tell me in the 180 days prior to that date, 219 00:11:21,930 --> 00:11:26,430 okay, so 180 days prior 220 00:11:26,430 --> 00:11:30,423 to the 11th of August, I was away 74 days. 221 00:11:34,080 --> 00:11:36,960 So it'll tell me how many days I was away, 74 days, 222 00:11:36,960 --> 00:11:38,700 and then it creates a new Record. 223 00:11:38,700 --> 00:11:41,130 It'll create a Record with the date, 224 00:11:41,130 --> 00:11:44,137 like the 11th of August, and it'll say, 225 00:11:44,137 --> 00:11:46,977 "On that date, you were away 74 days." 226 00:11:47,940 --> 00:11:52,290 Okay, so I add that to my vector of all Records, 227 00:11:52,290 --> 00:11:54,780 and then I decrement my date counter 228 00:11:54,780 --> 00:11:56,550 to go back to the previous day. 229 00:11:56,550 --> 00:12:00,870 Okay, so the previous day was the 10th of August, 230 00:12:00,870 --> 00:12:04,290 and it'll say, "Okay then, for the 10th of August, 231 00:12:04,290 --> 00:12:05,760 with all the visits that you had, 232 00:12:05,760 --> 00:12:07,450 how many days were you away 233 00:12:08,545 --> 00:12:11,340 in the 180-day period before then?" 234 00:12:11,340 --> 00:12:15,847 So 180 days before the 10th of August, it'll tell me, 235 00:12:15,847 --> 00:12:18,150 "Oh, it was 74 days away there." 236 00:12:18,150 --> 00:12:22,353 That days, I push it into a new Record again. 237 00:12:23,580 --> 00:12:26,190 Obviously I need to explain how this function works. 238 00:12:26,190 --> 00:12:28,503 I'll get on to that in a moment. 239 00:12:29,820 --> 00:12:31,260 By the time it gets to here, 240 00:12:31,260 --> 00:12:34,710 it has gathered a collection of all the Record objects, 241 00:12:34,710 --> 00:12:37,440 and I then display them in chronological order. 242 00:12:37,440 --> 00:12:40,680 Well, actually, it's reverse chronological order. 243 00:12:40,680 --> 00:12:43,740 For each Record, I iterate over my Records, 244 00:12:43,740 --> 00:12:45,780 and for each Record I display it. 245 00:12:45,780 --> 00:12:46,613 Remember, 246 00:12:48,390 --> 00:12:51,240 my Record type implements the Display trait, 247 00:12:51,240 --> 00:12:54,360 so it can output via the format function. 248 00:12:54,360 --> 00:12:59,360 It can output a Record object as the number of days 249 00:12:59,460 --> 00:13:01,440 and the date that we're talking about, 250 00:13:01,440 --> 00:13:04,410 the number of days and the date that we're talking about. 251 00:13:04,410 --> 00:13:07,350 So that's coming together quite nicely now. 252 00:13:07,350 --> 00:13:09,450 So it displays all the information 253 00:13:09,450 --> 00:13:11,100 in reverse chronological order. 254 00:13:11,100 --> 00:13:12,180 So that was useful for me. 255 00:13:12,180 --> 00:13:14,850 So I can see where the hotspots are. 256 00:13:14,850 --> 00:13:18,393 It looks quite busy around July. 257 00:13:20,310 --> 00:13:22,980 Right, so if I go back, it'll keep on looping 258 00:13:22,980 --> 00:13:26,670 till the bottom of the current date basically, 259 00:13:26,670 --> 00:13:30,900 but then it also displays the same information 260 00:13:30,900 --> 00:13:32,940 in reverse number of days. 261 00:13:32,940 --> 00:13:35,310 Ultimately, I want to be able to see 262 00:13:35,310 --> 00:13:39,240 what's the top number of days I've been away in that period, 263 00:13:39,240 --> 00:13:42,090 so I sort my records. 264 00:13:42,090 --> 00:13:46,447 When you sort the records, it has to compare records to say, 265 00:13:46,447 --> 00:13:49,080 "Is your number of days greater than or less than?" 266 00:13:49,080 --> 00:13:52,770 So sorting, in order to sort a structure type 267 00:13:52,770 --> 00:13:54,510 or a vector of structures, 268 00:13:54,510 --> 00:13:58,110 you have to implement comparability, and I did. 269 00:13:58,110 --> 00:14:03,060 So my Record type implemented the order trait 270 00:14:03,060 --> 00:14:05,757 and the partial order trait, okay? 271 00:14:05,757 --> 00:14:07,680 And that gives me sortability. 272 00:14:07,680 --> 00:14:10,950 It can then compare based on days. 273 00:14:10,950 --> 00:14:13,200 It compares one record against another, 274 00:14:13,200 --> 00:14:17,010 and it's the days that will influence the ordering. 275 00:14:17,010 --> 00:14:19,530 So then, having sorted the records, 276 00:14:19,530 --> 00:14:23,583 these records, this vector is now in time order. 277 00:14:26,059 --> 00:14:28,380 So not in time order, in the number of days order. 278 00:14:28,380 --> 00:14:32,040 So I can then display the records in the number of days, 279 00:14:32,040 --> 00:14:34,290 okay, so the highest number of days appearing 280 00:14:34,290 --> 00:14:35,190 at the top of the list. 281 00:14:35,190 --> 00:14:36,960 It says, "Watch out. 282 00:14:36,960 --> 00:14:41,520 On the 4th of November, in the 180 days prior to that, 283 00:14:41,520 --> 00:14:43,530 you'll have been away 89 days." 284 00:14:43,530 --> 00:14:47,793 That's very close to the 90-day margin for the Brexit rule. 285 00:14:48,960 --> 00:14:51,410 I still can't believe Brexit, to be quite honest.