This question already has answers here:
Maximum integer value find in list<int>
(7 answers)
Closed 4 years ago.
I am using WebClient to retrieve a set of data. After receiving the data, I need to loop trough it. I need to know the what was the maximum value of date within the data, so new data can be retrieved from following date.
Simplified, my code looks like:
class MyClass
{
public DateTime LoopDate()
{
DateTime[] TripDates = { DateTime.Parse("2019-01-01"), DateTime.Parse("2019-01-02"), DateTime.Parse("2019-01-03") };
DateTime maxdate;
foreach (var date in TripDates)
{
maxdate = date;
Console.WriteLine(date);
}
return maxdate; //needs to return the maximum DateTime value from the loop
}
}
class Program
{
static void Main(string[] args)
{
var MyClass = new MyClass();
var Nextdate = MyClass.LoopDate();
Console.ReadKey();
}
}
public DateTime LoopDate()
{
DateTime[] TripDates = { DateTime.Parse("2019-01-01"), DateTime.Parse("2019-01-02"), DateTime.Parse("2019-01-03") };
DateTime maxdate = TripDates.Max();
return maxdate; //needs to return the maximum DateTime value from the loop
}
The below line will work for you
DateTime maxdate = TripDates.Max();
Related
Been stuck on this task for a while now any help would be greatly appreciated.
So I have user input of Patient ID, Staff ID, visitType and DateTime from the Presentation Layer which I want to add to a list through the Business Layer.
The dateTime is inputted as a string and I can store It as a string fine but what I am trying to do is convert it into DateTime and then be able to store it in a list. this is where I encounter errors.
here is my code in presentation layer(MainWindow.cs), where I am pulling the information to be stored;
private void BtnAddVisit_Click(object sender, RoutedEventArgs e)
{
txtOutput.Text = "";
try
{
if (healthSystem.addVisit(new int[2] { 1, 3 }, 1, visitTypes.assessment, "01/01/2020 09:00")) //Should be OK
txtOutput.Text += "Visit 1 added.\n";
}
catch (Exception ex)
{
txtOutput.Text += ex.Message;
}
txtOutput.Text += healthSystem.getVisitList();
}
and here is my code in the business layer(HealthFacade);
public Boolean addVisit(int[] staff, int patient, int type, string dateTime)
{
//if the number of objects in the visit list is equal to 6, clear the list to avoid repeated output in textbox
if (visit.Count == 6)
{
visit.Clear();
}
//converting from string to dateTime
for (int i = 0; i < visit.Count; i++)
{
//the original task was to store 6 instances so thats why is says < 7
if (visit.Count < 7)
{
DateTime oDate = Convert.ToDateTime(dateTime);
}
}
//adding all the visits, regardless of if the data is valid or not
Visit v = new Visit();
v.Staff = staff;
v.Patient = patient;
v.Type = type;
v.DateTime = oDate;
//adds instance of visit to the visit list
visit.Add(v);
return true;
My understanding would be that I would then write v.DateTime = oDate; but it tells me 'oDate' does not exist in the current context.
the code for my Visit class is here;
using System;
using System.Collections.Generic;
using System.Text;
namespace BusinessLayer
{
class Visit
{
int[] staff;
int patient, type;
string dateTime;
public Visit()
{
}
// Constructor for Staff, using example from week 5 practical
public Visit(int [] aStaff, int aPatient, int aType, string aDateTime)
{
staff = aStaff;
patient = aPatient;
type = aType;
dateTime = aDateTime;
}
public int[] Staff
{
set { staff = value; }
get { return staff; }
}
public int Patient
{
set { patient = value; }
get { return patient; }
}
public int Type
{
set { type = value; }
get { return type; }
}
public string DateTime
{
set { dateTime = value; }
get { return dateTime; }
}
}
}
The reason I am trying to do this is so that I can set up a doctors appointments system and make sure that no 2 appointments are at the same time and therefore clash.
Thanks in advance for any help you can give!
The problem here is that the variable oDate only exists in the scope where you declared it.
In your case it's only usable inside your if statement.
Your function should look like this for you to access the variable when needed:
public Boolean addVisit(int[] staff, int patient, int type, string dateTime)
{
//if the number of objects in the visit list is equal to 6, clear the list to avoid repeated output in textbox
if (visit.Count == 6)
{
visit.Clear();
}
DateTime oDate = Convert.ToDateTime(dateTime);;
//converting from string to dateTime
for (int i = 0; i < visit.Count; i++)
{
//the original task was to store 6 instances so thats why is says < 7
if (visit.Count < 7)
{
//DateTime oDate = Convert.ToDateTime(dateTime);
// Because you definded oDate inside your if clause it is only accessible inside the clause
}
}
//adding all the visits, regardless of if the data is valid or not
Visit v = new Visit();
v.Staff = staff;
v.Patient = patient;
v.Type = type;
v.DateTime = oDate;
//adds instance of visit to the visit list
visit.Add(v);
return true;
Convert.ToDateTime may not work with different local settings. Because a DateTime is not allways dd/MM/yyyy HH:mm.
You can try like this if you are sure that your datetime string is allways formatted like this "01/01/2020 09:00".
var dateTime = "01/01/2020 09:00";//Assume your date is that.
DateTime dtInvariant = DateTime.ParseExact(dateTime, "dd/MM/yyyy HH:mm", CultureInfo.InvariantCulture);
//If you want to work with strings,
var datePart = dateTime.Split(' ')[0];
var timePart = dateTime.Split(' ')[1];
var day = int.Parse(datePart.Split('/')[0]);
var month = int.Parse(datePart.Split('/')[1]);
var year = int.Parse(datePart.Split('/')[2]);
var hour = int.Parse(timePart.Split(':')[0]);
var minute = int.Parse(timePart.Split(':')[1]);
var myDate = new DateTime(year, month, day, hour,minute, 0);
I am currently want to get the date range (between time range) from the list of dates.
For example:
The time now is
2017-04-08 18:00
And I got these from and to dates:
public static string[] fromDates = new string[] { "2017-04-07 07:00", "2017-04-07 10:00", "2017-04-07 12:00", "2017-04-07 14:00", "2017-04-07 16:00" };
public static string[] toDates = new string[] { "2017-04-07 08:00", "2017-04-07 11:00", "2017-04-07 13:00", "2017-04-07 15:00", "2017-04-07 17:00" };
I am using this code:
public static bool IsInRange(this DateTime dateToCheck, string[] startDates, string[] endDates, out string StartDate, out string EndDate)
{
DateTime startDate = new DateTime();
DateTime endDate = new DateTime();
bool isWithinRange = false;
for (int i = 0; i < startDates.Length; i++)
{
startDate = Convert.ToDateTime(startDates[i]);
isWithinRange = dateToCheck >= startDate;
if (isWithinRange)
break;
}
for (int y = 0; y < endDates.Length; y++)
{
endDate = Convert.ToDateTime(endDates[y]);
isWithinRange = dateToCheck < endDate;
if (isWithinRange)
break;
}
StartDate = startDate;
EndDate = endDate;
return isWithinRange;
}
And I call it like this:
var isBetween = Convert.ToDateTime("2017-04-08 18:00").IsInRange(fromDates, toDates, out StartDate, out EndDate)
But I couldn't make it working, the StartDate in IsInRange method is always return true and it will return the first index from fromDates variable, which is wrong.
How can I make it like the time between?
I know I can do it like this:
var isBetween = dateToCheck >= startDate && dateToCheck < endDate
But it is only one date need to check, what about if it is like my situation?
Your answer much appreciated.
Thanks
I would start by converting everything into a more useful object model:
Get rid of all the strings (i.e. convert from strings to something more useful early on)
Instead of having two collections, create a new type indicating "a date/time range". You're being somewhat foiled by relating the wrong items together: the start values aren't related to each other, they're related to their corresponding end dates.
You could do this within the method if you really need to, but it would be better to move to a richer object model for as much of your code as you can. For example, suppose you have:
public sealed class DateTimeRange
{
public DateTime Start { get; }
public DateTime End { get; }
public DateTimeRange(DateTime start, DateTime end)
{
// TODO: Validate that start <= end
Start = start;
End = end;
}
public bool Contains(DateTime value) => Start <= value && value < End;
}
Then your method can look like this:
public DateTimeRange FindRange(IEnumerable<DateTimeRange> ranges, DateTime value) =>
ranges.FirstOrDefault(range => range.Contains(value));
That will return null if no ranges contain the value, or the first one that does contain a value otherwise.
(As an aside, I'd do all of this in Noda Time instead as a better date/time API, but I'm biased.)
If you want to stay with yoir design, then you should simply do everything inside one loop, instead of doing it twice, as you want always to match first element with first element, second with second etc.
public static bool IsInRange(this DateTime dateToCheck, string[] startDates, string[] endDates, out DateTime StartDate, out DateTime EndDate)
{
if (startDates.Length != endDates.Length)
{
throw new ArgumentException("The arrays must have the same length");
}
StartDate = new DateTime();
EndDate = new DateTime();
for (int i = 0; i < startDates.Length; i++)
{
StartDate = Convert.ToDateTime(startDates[i]);
EndDate = Convert.ToDateTime(endDates[i]);
if (dateToCheck >= StartDate && dateToCheck <= EndDate)
{
return true;
}
}
return false;
}
But as already stated in other answer - you should redesign your code, because it's not very maintenable and easy to understand
I have a textbox in my WPF application in which i'm getting time in 24 hour format. What I want is, if my textbox's time is less than current time then IF condition should be true but its not working...
e.g:
txtdeparturetime.Text = 00:10
time == 00:31// time==>(object) here current time
if(txtdeparturetime.Text < time) // than this should work
Below is my code.
DateTime time = new DateTime();
DateTime deptime = DateTime.Parse(txtdeparturetime.Text);//converting textbox value into date object
if ((TimeSpan.Compare(deptime.TimeOfDay, time.TimeOfDay)) == -1)
{
//some code here
}
You have some mistakes in your code...
private void button1_Click(object sender, EventArgs e)
{
DateTime t1 = DateTime.Now;
DateTime t2 = Convert.ToDateTime(textBox1.Text);
int i = DateTime.Compare(t1, t2);
if (i < 1)
{
}
}
Now, The variable i will be less than Zero if t1 is less than t2.
If t1 is equals t2 the result is Zero.
Finally, if t1 is bigger than t2 the result will be bigger than Zero.
You want to compare to DateTime.Now instead of new DateTime() and can use a simple < comparison operator.
DateTime now = DateTime.Now;
DateTime deptime = DateTime.Parse(txtdeparturetime.Text);
if (deptime.TimeOfDay < now.TimeOfDay)
{
//some code here
}
here is a working example with text set by a constant instead of a text field.
public static void test1()
{
DateTime now = DateTime.Now;
string timetext = "2017-02-04 12:16PM";
DateTime deptime = DateTime.Parse(timetext);
Console.WriteLine("text time="+timetext);
if (deptime.TimeOfDay < now.TimeOfDay)
{
Console.WriteLine("time is less than now");
}
Console.WriteLine("End");
Console.ReadLine();
}
I'm the head in the refacto of my code because it's a mess.
But since I'm on it from yesterday, my head look like a stone -_-"
#region DateTime foreach Currencies
static DateTime eurusd = DateTime.Now.AddHours(-1);
static DateTime eurgbp = DateTime.Now.AddHours(-1);
static DateTime eurjpy = DateTime.Now.AddHours(-1);
static DateTime usdjpy = DateTime.Now.AddHours(-1);
static DateTime gbpjpy = DateTime.Now.AddHours(-1);
static DateTime gbpusd = DateTime.Now.AddHours(-1);
static DateTime eurusdm1 = DateTime.Now.AddHours(-1);
static DateTime eurgbpm1 = DateTime.Now.AddHours(-1);
static DateTime eurjpym1 = DateTime.Now.AddHours(-1);
static DateTime usdjpym1 = DateTime.Now.AddHours(-1);
static DateTime gbpjpym1 = DateTime.Now.AddHours(-1);
static DateTime gbpusdm1 = DateTime.Now.AddHours(-1);
static DateTime eurusdh1 = DateTime.Now.AddHours(-1);
static DateTime eurgbph1 = DateTime.Now.AddHours(-1);
static DateTime eurjpyh1 = DateTime.Now.AddHours(-1);
static DateTime usdjpyh1 = DateTime.Now.AddHours(-1);
static DateTime gbpjpyh1 = DateTime.Now.AddHours(-1);
static DateTime gbpusdh1 = DateTime.Now.AddHours(-1);
static DateTime eurusdd1 = DateTime.Now.AddHours(-1);
static DateTime eurgbpd1 = DateTime.Now.AddHours(-1);
static DateTime eurjpyd1 = DateTime.Now.AddHours(-1);
static DateTime usdjpyd1 = DateTime.Now.AddHours(-1);
static DateTime gbpjpyd1 = DateTime.Now.AddHours(-1);
static DateTime gbpusdd1 = DateTime.Now.AddHours(-1);
#endregion
There are 24 different DateTime.
switch (data.Instrument)
{
case "EUR/USD":
if (CanUpdate(ref eurusd, "s5"))
{ InsertData("eurusd", data); }
if (CanUpdate(ref eurusdm1, "m1"))
{ InsertData("eurusdm1", data);}
if (CanUpdate(ref eurusdh1, "h1"))
{ InsertData("eurusdh1", data);}
if (CanUpdate(ref eurusdd1, "d1"))
{ InsertData("eurusdd1", data);}
}
A switch case with 6 Case (like the one above)
(InsertData just put some object in a collection. "x" => collection name, data => the object)
private bool CanUpdate(ref DateTime date, string timer)
{
TimeSpan result = DateTime.Now - date;
if (timer == "s5")
{
int difSeconds = result.Seconds;
if (difSeconds >= 5)
{
date = DateTime.Now;
return true;
}
}
if (timer == "m1")
{
int difMinutes = result.Minutes;
if (difMinutes >= 1)
{
date = DateTime.Now;
return true;
}
}
if (timer == "h1")
{
int difHour = result.Hours;
if (difHour >= 1)
{
date = DateTime.Now;
return true;
}
}
if (timer == "d1")
{
int difDays = result.Days;
if (difDays >= 1)
{
date = DateTime.Now;
return true;
}
}
return false;
}
My "CanUpdate" Method. Check the time between the last update and if the "if condition" are true it update the "date variable" and return true, else it return false.
As you can guess, this switchcase have more or less 70 lines. One change need to be repercuted on the whole switchcase. Ugly right ?
I would like to get rid of this switchcase and make it more maintainable.
I've think about put all of the data in different list.
So it will look like:
List<String> collectionName;
List<DateTime> dateTime;
List<String> timeFrame;
and do a foreach on the DateTime collection then do 2 nested for.
Somthing like:
foreach (DateTime dt in dateTime)
{
for(i=0; i <= collectionName.Lenght; i++)
{
for(j=0; j <= timeFrame.Lenght; j++)
{
CanUpdate(ref dt, timeFrame[j])
InsertData(collectionName[i].ToString(), data)
}
}
}
Am I in the right direction and do you even understand what I would like. Because if your head are in the same state as mine after reading this. Sorry :O
Preamble
I would (and, in fact, I did) use Dictionary to solve this problem.
I'm not a big fan of Tuple. So, for real application I would create some struct/class instead.
For the answer I assume that it's required to work with strings of formats "EUR/USD" and "eurusdm1" (see method GetInsertDataArgument()).
Of course, I haven't tested the code :) But I think it's more than enough to get the idea.
I've decided to make all the members static because you had your datetimes static in the original code. You can easily change this.
Code
class MyClass
{
private static readonly Dictionary<Tuple<string, string>, DateTime> lastUpdateDateTimes = new Dictionary<Tuple<string, string>, DateTime>();
private static readonly Dictionary<string, TimeSpan> timeIntervals = new Dictionary<string, TimeSpan>();
static MyClass()
{
timeIntervals.Add("s5", TimeSpan.FromSeconds(5));
timeIntervals.Add("m1", TimeSpan.FromMinutes(1));
timeIntervals.Add("h1", TimeSpan.FromHours(1));
timeIntervals.Add("d1", TimeSpan.FromDays(1));
}
private static string GetInsertDataArgument(string instrument, string timeIntervalName)
{
string result = instrument.Replace("/", "").ToLower();
if (timeIntervalName != "s5")
result = result + timeIntervalName;
return result;
}
private static void Update(string instrument)
{
DateTime now = DateTime.Now;
foreach (var timeInterval in timeIntervals)
{
var dateTimeKey = new Tuple<string, string>(instrument, timeInterval.Key);
if (now - lastUpdateDateTimes[dateTimeKey] < timeInterval.Value)
continue;
lastUpdateDateTimes[dateTimeKey] = now;
InsertData(GetInsertDataArgument(instrument, timeInterval.Key), data);
}
}
}
What's going on
There are 2 dictionaries:
lastUpdateDateTimes stores datetimes for each currency pair and time interval. First member of tuple stores currency pair (in "EUR/USD" format), second member stores time interval name (in "s5" format).
timeIntervals holds your time intervals. It is filled in static constructor of class.
Update method is the replacement for your switch statement and CanUpdate method.
Thanks you. Your idea are really good.
exactly what I needed especially the:
Dictionnary<Tuple<string,string>,DateTime>
I was wondering how to make all those data relational.
I just needed to delete the
if (timeIntervalName != "s5")
because
"result = result + timeIntervalName;"
should be trigger every time GetArgumentName are called.
Neded to make a
TimeSpan timeElapsed = now - lastUpdateDateTimes[dateTimeKey];
Because it didn't work in the condition even between (). Don't know why, it should.(?)
And I also needed to populate my lastUpdateDateTimes Dictionnary. (ofc)
So, thank you again. Work like a charm.
I have the following datetimes:
Start = 15/12/2012 13:00:00
End = 16/02/2013 14:00:00
How can I split that in 3 parts for each month?
- 15-12-2012 13:00:00 -> 01-01-2013 00:00:00
- 01-01-2013 00:00:00 -> 01-02-2013 00:00:00
- 01-02-2013 00:00:00 -> 16-02-2013 14:00:00
The total timespan must remain the same.
Can this easily be done with LINQ?
sure, try this (with little helper class included)
Process:
var Start = DateTime.Parse("15 Dec 2012 13:00:00");
var End = DateTime.Parse("16 Feb 2013 14:00:00");
var runningDate = Start;
while (runningDate < End)
{
var nextMonthSeed = runningDate.AddMonths(1);
var to = DateHelper.Min(new DateTime(nextMonthSeed.Year, nextMonthSeed.Month, 1), End);
Console.WriteLine("{0} -> {1}", runningDate.ToString("dd-MM-yyyy HH:mm:ss"), to.ToString("dd-MM-yyyy HH:mm:ss"));
runningDate = to;
}
Helper class:
public static class DateHelper
{
public static DateTime Min(DateTime date1, DateTime date2)
{
return (date1 < date2 ? date1 : date2);
}
}
You could try something like these extension methods:
public static class SomeExtensions {
public static IEnumerable<Tuple<DateTime, DateTime>> GetIntervals(
this DateTime from,
DateTime to) {
var currentFrom = from;
var currentTo = from.AdvanceToStartOfNextMonth();
while (currentTo < to) {
yield return Tuple.Create(currentFrom, currentTo);
currentFrom = currentTo;
currentTo = currentFrom.AdvanceToStartOfNextMonth();
}
yield return Tuple.Create(currentFrom, to);
}
public static DateTime AdvanceToStartOfNextMonth(this DateTime #this) {
var newMonth = #this.Month + 1;
var newYear = #this.Year;
if (newMonth == 13) {
newMonth = 1;
newYear++;
}
return new DateTime(newYear, newMonth, 1);
}
}
and then use them like so:
public class Etc {
public static void Foo() {
DateTime start = ...
DateTime stop = ....
Tuple<DateTime, DateTime>[] intervals = start.GetIntervals(stop).ToArray();
// or simply
foreach (var interval in start.GetIntervals(stop))
Console.WriteLine(interval);
}
}
EDIT
And here's a little test I just tried out (and it looks alright, I think):
class Program {
static void Main(string[] args) {
DateTime start = DateTime.Now.Subtract(TimeSpan.FromDays(170));
DateTime stop = DateTime.Now;
foreach (var interval in start.GetIntervals(stop))
Console.WriteLine(interval);
Console.ReadKey(intercept: true);
}
}
and that produced these results (in a console app):
END OF EDIT