C# times matching - c#

I have written a small function in C# which isn't my main launguage so is coming across a little foreign to me.
public bool CheckForKey(string key)
{
string strKeyTime = Decode(key);
//valid key will be current time +- 5 minutes
string strTheTime = DateTime.Now.ToString("HH:mm:ss tt");
if (strKeyTime == strTheTime)
{
return true;
}
else
{
return false;
}
}
I need to alter this to allow for 5 minutes, so
if (strKeyTime == strTheTime)
needs to be
if (strKeyTime == strTheTime + or - 5 minutes)
my problem is matching the times as they are strings, perhaps convert key(original time) back to a date first and then do it, but I am pretty new to c#

If you convert (or keep) them both to DateTimes you can use TimeSpan:
TimeSpan delta = dateTime1 - dateTime2;
if (Math.Abs(delta.TotalMinutes) <= 5) { ... }
Look into using the DateTime.ParseExact (or any of the Parse... methods) to parse your strKeyTime, and then do something similar to the above.

To convert your sent string to the equivalent DateTime value, use the following code:
var keyDateTime = Convert.ToDateTime(strKeyTime);
var strTheTime = DateTime.Now
from here, you can use this value to compare with your original time value as the following:
if (keyDateTime == strTheTime || (keyDateTime > strTheTime && keyDateTime < strTheTime.AddMinutes(5))
{
return true;
}
the previous block of code will first check if we got an exact match, or the time sent to the method is between the original time and a time shift of additional 5 minutes.
that's it, if this is not what you need, let me know so I may update my answer for you, thanks.
-- if my answer is correct, don't forget to "Mark as answer".

"perhaps convert key(original time) back to a date first and then do it" sounds like a sound solution. I'd do it this way:
Convert both strings to DateTime instances.
Store difference in TimeSpan instance using DateTime.Subtract(DateTime value) ( http://msdn.microsoft.com/en-us/library/8ysw4sby.aspx )
Check if TimeSpanInstance.TotalMinutes is less than or equal to 5.
The first step is something I can't really give you any advice on without information concerning how your string is formatted. However, once this is done, the rest should be easy.

Related

Sorting one array from another's one date

I have Visual Studio 2019. The project is a .Net Windows Form on C# on .Net Framework 4.8.
I have got two arrays.
The first one contains a random number of string values (since they come on a string[]), for example:
AB5XHBC1
NMAK72B8
WB5XHBC1
KCZUH528
NZ9YHF3D
PFKR6WNA
The second one will always have the same length of the first one, but their values are date-strings, and it could be some string.empty or repeated values in some cases:
06/10/2020
08/05/2018
01/12/2020
01/01/2009
01/12/2020
What I need to do is sort the first array based on the second one dates. I tried the Array.Sort method but it does not give me the expected result. I'm not really sure if I have used it wrong.
The "null" values must be the firsts, then the newer date (on the top) to the older date (on the bottom), so the resulting array of this example would have to be sort like this (from 0 to 5 position):
WB5XHBC1
KCZUH528
PFKR6WNA
NMAK72B8
AB5XHBC1
NZ9YHF3D
Thanks in advance.
You could implement a comparer for your dates (which should implement IComparer<string>) and then use Array.Sort(keys, values, comparer) like so:
using System;
using System.Collections.Generic;
namespace Demo
{
static class Program
{
public static void Main()
{
string[] data =
{
"AB5XHBC1",
"NMAK72B8",
"WB5XHBC1",
"KCZUH528",
"NZ9YHF3D",
"PFKR6WNA"
};
string[] dates =
{
"06/10/2020",
"08/05/2018",
"",
"01/12/2020",
"01/01/2009",
"01/12/2020"
};
Array.Sort(dates, data, new CompareDates());
Console.WriteLine(string.Join("\n", data));
}
}
public sealed class CompareDates: IComparer<string>
{
public int Compare(string x, string y)
{
var xd = DateTime.TryParse(x, out DateTime d1) ? d1 : DateTime.MaxValue;
var yd = DateTime.TryParse(y, out DateTime d2) ? d2 : DateTime.MaxValue;
return yd.CompareTo(xd);
}
}
}
However, this gives the output as:
WB5XHBC1
KCZUH528
PFKR6WNA
AB5XHBC1
NMAK72B8
NZ9YHF3D
I believe this is because your expected results have an error. The second-oldest date is "08/05/2018", which corresponds to the string "NMAK72B8". Therefore, according to your specification, "NMAK72B8" should be second from the end - but in your expected results, "AB5XHBC1" is second from the end.
Try it online (.Net Fiddle).
One thing to watch out for is the date parsing. The code above parses the dates in the current locale, which is assumed to be UK (for the dd/mm/yyyy date format). If you want to parse other date formats, you'll have to change the code accordingly.
You can store these in a List of Tuple<string, DateTime>. I've hardcoded the values in the example below - as other commenters have said, you need to properly parse the date strings into proper DateTime objects, etc. I leave that exercise to you.
var list = new List<(string RandomString, DateTime Date)>
{
("AB5XHBC1", DateTime.Parse("06/10/2020")),
("NMAK72B8", DateTime.Parse("08/05/2018")),
("WB5XHBC1", DateTime.MaxValue), // simulating null, see below
("KCZUH528", DateTime.Parse("01/12/2020")),
("NZ9YHF3D", DateTime.Parse("01/01/2009")),
("PFKR6WNA", DateTime.Parse("01/12/2020")),
};
var sorted = list.OrderByDescending(x => x.Date);
For the case of the null dates appearing first, you can check if the particular date string is null. If it is, assign DateTime.MaxValue as a value, otherwise parse it and use the actual value. The logic of this check could resemble the one below:
string.IsNullOrEmpty(whateverStringDate) ? DateTime.MaxValue : DateTime.Parse(whateverStringDate);
This should point you in the right direction, #Matthew Watson's answer would be a much more elegant and complete solution.

Use DateTime.ToFileTime and FromFileTime through file name string

I want to save to a specific space a single file at several states. So i thought about stamping it with the time of creation to tell one from another.
I have created a dummy program that goes through exactly the same procedure my full program does but concentrated.
Here is the code:
DateTime first = DateTime.Now;
long ft = first.ToFileTime();
string time = "" + ft;
long timeLong = Convert.ToInt64(time);
DateTime normalDate = DateTime.FromFileTime(timeLong);
string normalName = ""+ normalDate;
DateTime thisDate = DateTime.Parse(normalName);
long fit = thisDate.ToFileTime();
So it goes through those steps:
Create time and convert to long for file.
Save it as string inside the files name(i pass it like that but in "" is the files name)
Then i retrieve it, i cast it into long, to create a DateTime format readable for the human with FromFileTime.Then to string fro the user to read it in a comboBox.
Then the user selects and it becomes DateTime , to get into long through tge TiFileTime ( at this point i have the problem as it appears to loose everything smaller than seconds)
I want to cast it back into long at the end to be able to run through the files again and find the one that matches with the one that the user choose.
here is some output values:
Edit : As you can see form the results above. I miss something . The initial and the final values are not the same.So i cant find the same file again.
The Parse() method don't have all the information that the DateTime structure holds (you can find its members here).
string normalName = ""+ normalDate;
DateTime thisDate = DateTime.Parse(normalName);
Will not return the exact value (including Ticks) as the original one.
You should do it as follows, using Ticks:
string normalName = "" + normalDate.Ticks;
DateTime thisDate = new DateTime(long.Parse(normalName));
long fit = thisDate.ToFileTime();

How to make DateTime.TryParse() fail if no year is specified?

Consider the following code to parse a date. (Note that I'm in the EN-gb locale):
const DateTimeStyles DATE_TIME_STYLES = DateTimeStyles.NoCurrentDateDefault | DateTimeStyles.AllowWhiteSpaces;
DateTime dt;
// Current culture for this example is "EN-gb".
if (DateTime.TryParse("31/12", CultureInfo.CurrentUICulture, DATE_TIME_STYLES, out dt))
Console.WriteLine("Parsed correctly"); // Do not want!
else
Console.WriteLine("Did not parse correctly.");
I'm deliberately omitting the year. However, TryParse() will parse this without any errors, and will substitute the current year.
I'd like to be able to force the user to enter ALL the components of the date (using their local format), so I'd like the above parsing to fail - or to be able to detect that the user didn't enter a year.
I don't really want to use DateTime.TryParseExact() because then I would have to add code to specify all the different valid formats for all the different supported locales, which is non-trivial and likely error-prone. I suspect this may well be my only sane option, though.
Anyone got any ideas? (Someone here at work has already implemented a "solution" which involves not allowing the current year, which is clearly not a good solution...)
You could query for the culture's patterns, filter out those without a year and then use TryParseExact on the remaining patterns.
var allPatterns = culture.DateTimeFormat.GetAllDateTimePatterns();
var patternsWithYear = allPatterns.Where(s => s.Contains("y")).ToArray();
bool success = TryParseExact(input, patternsWithYear, culture, styles, out dateTime);
Known bug: This doesn't take escaping into account, you'll need to replace the Contains("y") call with proper parsing to fix this.
Alternatively you could go with just LongDatePattern and ShortDatePattern if you're fine with stricter format constraints.
You can use parse exact like this and catch the exception.
CurrentUICulture.DateTimeFormat.ShortDatePattern will give you the cultures short date pattern.
There is also DateTime.TryParseExact
DateTime.ParseExact(value.ToString(), cultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern.ToString, cultureInfo.CurrentUICulture)
The more I think about this the more I think it's a bad solution but given you're getting no other answers I'll post it anyway.
DateTime temp;
DateTime.TryParse(input, CultureInfo.CurrentUICulture, DATE_TIME_STYLES, out temp);
if (temp.Year == DateTime.Now.Year)
{
if (!input.Contains(DateTime.Now.Year))
{
if (temp.Days != int.Parse(DateTime.Now.Year.ToString().SubString(2)))
{
// my god that's gross but it tells you if the day is equal to the last two
// digits of the current year, if that's the case make sure that value occurs
// twice, if it doesn't then we know that no year was specified
}
}
}
Also, as others have suggested in comments now, checking the number of tokens or the strings length could also be useful like;
char[] delims = new char[] { '/', '\', '-', ' '); //are there really any others?
bool yearFound = false;
foreach (char delim in delims)
{
if (input.Split(delim).Count == 3)
{
yearFound = true;
break;
}
}
if (yearFound)
//parse
else
// error
These are just a couple of ideas, neither is truly sound. They're obviously both hacks, only you can know if they'll suffice. At least they beat your co-workers if (dt.Year == 2014) //discard input "solution".

C# 4.0 - 3 value pairs (possibly more). Sort based on values

This is a tough one to phrase as a search query and I'm having no luck. And the more I think about it, it is more a logic question than a syntax one. However I am a newby to C# (8 years php) and I am currently building my third windows forms app so there may be a method built to do just what I want.
What I am doing is reading a date format given by the user as a single string and breaking it into parts to be assigned to an Array, or from what I have seen in my searches for Associative Arrays, maybe a SortedList or Dictionary.
e.g.
SortedList<string, int> resultArray = new SortedList<string, int>();
string dateFormat = "yyyyMMdd" // Just and example
int yearPos = dateFormat.IndexOf("yyyy");
int monthPos = dateFormat.IndexOf("MM");
int dayPos = dateFormat.IndexOf("dd");
resultArray.Add("yearPos", yearPos);
resultArray.Add("monthPos", monthPos);
resultArray.Add("dayPos", dayPos);
// So, resultArray expressed as an array looks like:
// resultArray["yearPos"] = 0
// resultArray["monthPos"] = 4
// resultArray["dayPos"] = 6
// Sort List and reassign keys (or values) based on their position value (which is unique)
// ???????
return resultArray;
Ideally, the finished result that I am after for this collection/array is to have the members ranked by the value of their position in the string. Like this:
// resultArray["yearPos"] = 1
// resultArray["monthPos"] = 2
// resultArray["dayPos"] = 3
The reason I am trying to do this, is because the same date format is used to pull out a real date from a file using Regex.Match. And I want to use these new values to know which group element of the match to use for each portion of the date.
Any help getting my head around this would be greatly appreciated.
I tried this and it works:
DateTime dt;
if (DateTime.TryParseExact("20110223", "yyyyMMdd", null, 0, out dt))
Console.WriteLine(dt);
Just use DateTime.TryParse. You can pass it a formatting string and it will do all the work for you.

How to compare two files based on datetime?

I need to compare two files based on datetime. I need to check whether these two files were created or modified with same datetime. I have used this code to read the datetime of files...
string fileName = txtfile1.Text;
var ftime = File.GetLastWriteTime(fileName).ToString();
string fileName2 = txtfile2.Text;
var ftime2 = File.GetLastWriteTime(fileName2).ToString();
Any suggestions?
Don't call ToString() on the DateTime values returned by GetLastWriteTime(). Do this instead:
DateTime ftime = File.GetLastWriteTime(fileName);
DateTime ftime2 = File.GetLastWriteTime(fileName2);
Then you can just compare ftime and ftime2:
if (ftime == ftime2)
{
// Files were created or modified at the same time
}
Well, how about doing
ftime == ftime2
? No need for the ToString though, better just compare DateTimes as-is.
The precision of the last modification time being stored in a file system varies between different file systems (VFAT, FAT, NTFS). So, its best to use an epsillon environment for this and either let the user choose a sensible value or choose a value based on the involved file systems.
https://superuser.com/questions/937380/get-creation-time-of-file-in-milliseconds
double epsillon = 2.0
DateTime lastUpdateA = File.GetLastWriteTime(filename);
DateTime lastUpdateB = File.GetLastWriteTime(filename2);
if (Math.Abs(Math.Round((lastUpdateA - lastUpdateB).TotalSeconds)) > epsillon)
different = true;
GetLastWriteTime() returns a DateTime object, so you can do this:
if (File.GetLastWriteTime(filename).CompareTo(File.GetLastWriteTime(filename2)) == 0)
to test if they have the same timestamp.
See this for more tips on comparing DateTime objects.
bool isMatched=false;
int ia = string.Compare(ftime.ToString(), ftime2.ToString());
if (string.Compare(ftime.ToString(), ftime.ToString()) == 0)
isMatched = true;
else
isMatched = false;

Categories