Related
I want to get the first day and last day of the month where a given date lies in. The date comes from a value in a UI field.
If I'm using a time picker I could say
var maxDay = dtpAttendance.MaxDate.Day;
But I'm trying to get it from a DateTime object. So if I have this...
DateTime dt = DateTime.today;
How to get first day and last day of the month from dt?
DateTime structure stores only one value, not range of values. MinValue and MaxValue are static fields, which hold range of possible values for instances of DateTime structure. These fields are static and do not relate to particular instance of DateTime. They relate to DateTime type itself.
Suggested reading: static (C# Reference)
UPDATE: Getting month range:
DateTime date = ...
var firstDayOfMonth = new DateTime(date.Year, date.Month, 1);
var lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddDays(-1);
UPDATE: From comments (#KarlGjertsen & #SergeyBerezovskiy)
DateTime date = ...
var firstDayOfMonth = new DateTime(date.Year, date.Month, 1);
var lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddSeconds(-1);
//OR
var lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddTicks(-1);
This is more a long comment on #Sergey and #Steffen's answers. Having written similar code myself in the past I decided to check what was most performant while remembering that clarity is important too.
Result
Here is an example test run result for 10 million iterations:
2257 ms for FirstDayOfMonth_AddMethod()
2406 ms for FirstDayOfMonth_NewMethod()
6342 ms for LastDayOfMonth_AddMethod()
4037 ms for LastDayOfMonth_AddMethodWithDaysInMonth()
4160 ms for LastDayOfMonth_NewMethod()
4212 ms for LastDayOfMonth_NewMethodWithReuseOfExtMethod()
2491 ms for LastDayOfMonth_SpecialCase()
Code
I used LINQPad 4 (in C# Program mode) to run the tests with compiler optimization turned on. Here is the tested code factored as Extension methods for clarity and convenience:
public static class DateTimeDayOfMonthExtensions
{
public static DateTime FirstDayOfMonth_AddMethod(this DateTime value)
{
return value.Date.AddDays(1 - value.Day);
}
public static DateTime FirstDayOfMonth_NewMethod(this DateTime value)
{
return new DateTime(value.Year, value.Month, 1);
}
public static DateTime LastDayOfMonth_AddMethod(this DateTime value)
{
return value.FirstDayOfMonth_AddMethod().AddMonths(1).AddDays(-1);
}
public static DateTime LastDayOfMonth_AddMethodWithDaysInMonth(this DateTime value)
{
return value.Date.AddDays(DateTime.DaysInMonth(value.Year, value.Month) - value.Day);
}
public static DateTime LastDayOfMonth_SpecialCase(this DateTime value)
{
return value.AddDays(DateTime.DaysInMonth(value.Year, value.Month) - 1);
}
public static int DaysInMonth(this DateTime value)
{
return DateTime.DaysInMonth(value.Year, value.Month);
}
public static DateTime LastDayOfMonth_NewMethod(this DateTime value)
{
return new DateTime(value.Year, value.Month, DateTime.DaysInMonth(value.Year, value.Month));
}
public static DateTime LastDayOfMonth_NewMethodWithReuseOfExtMethod(this DateTime value)
{
return new DateTime(value.Year, value.Month, value.DaysInMonth());
}
}
void Main()
{
Random rnd = new Random();
DateTime[] sampleData = new DateTime[10000000];
for(int i = 0; i < sampleData.Length; i++) {
sampleData[i] = new DateTime(1970, 1, 1).AddDays(rnd.Next(0, 365 * 50));
}
GC.Collect();
System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].FirstDayOfMonth_AddMethod();
}
string.Format("{0} ms for FirstDayOfMonth_AddMethod()", sw.ElapsedMilliseconds).Dump();
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].FirstDayOfMonth_NewMethod();
}
string.Format("{0} ms for FirstDayOfMonth_NewMethod()", sw.ElapsedMilliseconds).Dump();
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].LastDayOfMonth_AddMethod();
}
string.Format("{0} ms for LastDayOfMonth_AddMethod()", sw.ElapsedMilliseconds).Dump();
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].LastDayOfMonth_AddMethodWithDaysInMonth();
}
string.Format("{0} ms for LastDayOfMonth_AddMethodWithDaysInMonth()", sw.ElapsedMilliseconds).Dump();
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].LastDayOfMonth_NewMethod();
}
string.Format("{0} ms for LastDayOfMonth_NewMethod()", sw.ElapsedMilliseconds).Dump();
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].LastDayOfMonth_NewMethodWithReuseOfExtMethod();
}
string.Format("{0} ms for LastDayOfMonth_NewMethodWithReuseOfExtMethod()", sw.ElapsedMilliseconds).Dump();
for(int i = 0; i < sampleData.Length; i++) {
sampleData[i] = sampleData[i].FirstDayOfMonth_AddMethod();
}
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].LastDayOfMonth_SpecialCase();
}
string.Format("{0} ms for LastDayOfMonth_SpecialCase()", sw.ElapsedMilliseconds).Dump();
}
Analysis
I was surprised by some of these results.
Although there is not much in it the FirstDayOfMonth_AddMethod was slightly faster than FirstDayOfMonth_NewMethod in most runs of the test. However, I think the latter has a slightly clearer intent and so I have a preference for that.
LastDayOfMonth_AddMethod was a clear loser against LastDayOfMonth_AddMethodWithDaysInMonth, LastDayOfMonth_NewMethod and LastDayOfMonth_NewMethodWithReuseOfExtMethod. Between the fastest three there is nothing much in it and so it comes down to your personal preference. I choose the clarity of LastDayOfMonth_NewMethodWithReuseOfExtMethod with its reuse of another useful extension method. IMHO its intent is clearer and I am willing to accept the small performance cost.
LastDayOfMonth_SpecialCase assumes you are providing the first of the month in the special case where you may have already calculated that date and it uses the add method with DateTime.DaysInMonth to get the result. This is faster than the other versions, as you would expect, but unless you are in a desperate need for speed I don't see the point of having this special case in your arsenal.
Conclusion
Here is an extension method class with my choices and in general agreement with #Steffen I believe:
public static class DateTimeDayOfMonthExtensions
{
public static DateTime FirstDayOfMonth(this DateTime value)
{
return new DateTime(value.Year, value.Month, 1);
}
public static int DaysInMonth(this DateTime value)
{
return DateTime.DaysInMonth(value.Year, value.Month);
}
public static DateTime LastDayOfMonth(this DateTime value)
{
return new DateTime(value.Year, value.Month, value.DaysInMonth());
}
}
If you have got this far, thank you for time! Its been fun :¬). Please comment if you have any other suggestions for these algorithms.
Getting month range with .Net API (just another way):
DateTime date = ...
var firstDayOfMonth = new DateTime(date.Year, date.Month, 1);
var lastDayOfMonth = new DateTime(date.Year, date.Month, DateTime.DaysInMonth(date.Year, date.Month));
"Last day of month" is actually "First day of *next* month, minus 1". So here's what I use, no need for "DaysInMonth" method:
public static DateTime FirstDayOfMonth(this DateTime value)
{
return new DateTime(value.Year, value.Month, 1);
}
public static DateTime LastDayOfMonth(this DateTime value)
{
return value.FirstDayOfMonth()
.AddMonths(1)
.AddMinutes(-1);
}
NOTE:
The reason I use AddMinutes(-1), not AddDays(-1) here is because usually you need these date functions for reporting for some date-period, and when you build a report for a period, the "end date" should actually be something like Oct 31 2015 23:59:59 so your report works correctly - including all the data from last day of month.
I.e. you actually get the "last moment of the month" here. Not Last day.
OK, I'm going to shut up now.
DateTime dCalcDate = DateTime.Now;
dtpFromEffDate.Value = new DateTime(dCalcDate.Year, dCalcDate.Month, 1);
dptToEffDate.Value = new DateTime(dCalcDate.Year, dCalcDate.Month, DateTime.DaysInMonth(dCalcDate.Year, dCalcDate.Month));
Here you can add one month for the first day of current month than delete 1 day from that day.
DateTime now = DateTime.Now;
var startDate = new DateTime(now.Year, now.Month, 1);
var endDate = startDate.AddMonths(1).AddDays(-1);
If you only care about the date
var firstDay = new DateTime(date.Year, date.Month, 1, 0, 0, 0, date.Kind);
var lastDay = new DateTime(date.Year, date.Month, 1, 0, 0, 0, date.Kind).AddMonths(1).AddDays(-1);
If you want to preserve time
var firstDay = new DateTime(date.Year, date.Month, 1, date.Hour, date.Minute, date.Second, date.Kind);
var lastDay = new DateTime(date.Year, date.Month, 1, date.Hour, date.Minute, date.Second, date.Kind).AddMonths(1).AddDays(-1);
Try this one:
string strDate = DateTime.Now.ToString("MM/01/yyyy");
The accepted answer here does not take into account the Kind of the DateTime instance. For example if your original DateTime instance was a UTC Kind then by making a new DateTime instance you will be making an Unknown Kind instance which will then be treated as local time based on server settings. Therefore the more proper way to get the first and last date of the month would be this:
var now = DateTime.UtcNow;
var first = now.Date.AddDays(-(now.Date.Day - 1));
var last = first.AddMonths(1).AddTicks(-1);
This way the original Kind of the DateTime instance is preserved.
I used this in my script(works for me) but I needed a full date without the need of trimming it to only the date and no time.
public DateTime GetLastDayOfTheMonth()
{
int daysFromNow = DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month) - (int)DateTime.Now.Day;
return DateTime.Now.AddDays(daysFromNow);
}
For Persian culture
PersianCalendar pc = new PersianCalendar();
var today = pc.GetDayOfMonth(DateTime.Now);
var firstDayOfMonth = pc.GetDayOfMonth(DateTime.Now.AddDays(-(today-1)));
var lastDayOfMonth = pc.GetDayOfMonth(DateTime.Now.AddMonths(1).AddDays(-today));
Console.WriteLine("First day "+ firstDayOfMonth);
Console.WriteLine("Last day " + lastDayOfMonth);
You can do it
DateTime dt = DateTime.Now;
DateTime firstDayOfMonth = new DateTime(dt.Year, date.Month, 1);
DateTime lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddDays(-1);
Give this a try. It basically calculates the number of days that has passed on DateTime.Now, then subtracts one from that and uses the new value to find the first of the current month. From there it uses that DateTime and uses .AddMonths(-1) to get the first of the previous month.
Getting the last day of last month does basically the same thing except it adds one to number of days in the month and subtracts that value from DateTime.Now.AddDays, giving you the last day of the previous month.
int NumberofDays = DateTime.Now.Day;
int FirstDay = NumberofDays - 1;
int LastDay = NumberofDays + 1;
DateTime FirstofThisMonth = DateTime.Now.AddDays(-FirstDay);
DateTime LastDayOfLastMonth = DateTime.Now.AddDays(-LastDay);
DateTime CheckLastMonth = FirstofThisMonth.AddMonths(-1);
You can try this for get current month first day;
DateTime.Now.AddDays(-(DateTime.Now.Day-1))
and assign it a value.
Like this:
dateEndEdit.EditValue = DateTime.Now;
dateStartEdit.EditValue = DateTime.Now.AddDays(-(DateTime.Now.Day-1));
Create an instance of DateTime class
DateTime dateTime = DateTime.Now;
If you want to get the last day of the month you can do this
int lastDayOfMonth = DateTime.DaysInMonth(caducidadPuntos.Year, caducidadPuntos.Month);
If you want to get the first day of the month, you can do this
DateTime firstDayMonth = new DateTime(dateTime.Year, dateTime.Month, 1);
We had the requirement of being able to get the start and end of a given dates month, including times, inclusively. We ended up utilizing the aforementioned solutions, huge thanks to everyone here, and combined it into a util class to be able to get the start and end for a given month and year number combination up to the last millisecond. Including what we moved forward with in the event it helps someone else.
The util:
public class DateUtil
{
public static (DateTime startOfMonth, DateTime endOfMonth) GetStartAndEndOfMonth(int month, int year)
{
DateTime startOfMonth = GetStartOfMonth(month, year);
DateTime endOfMonth = GetEndOfMonth(month, year);
return (startOfMonth, endOfMonth);
}
public static DateTime GetStartOfMonth(int month, int year)
{
return new DateTime(year, month, 1).Date;
}
public static DateTime GetEndOfMonth(int month, int year)
{
return new DateTime(year, month, 1).Date.AddMonths(1).AddMilliseconds(-1);
}
}
Usage:
(DateTime startOfMonth, DateTime endOfMonth) = DateUtil.GetStartAndEndOfMonth(2, 2021); // February, 2021
easy way to do it
Begin = new DateTime(DateTime.Now.Year, DateTime.Now.Month,1).ToShortDateString();
End = new DataFim.Text = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month)).ToShortDateString();
DateTime dCalcDate = DateTime.Now;
var startDate = new DateTime(Convert.ToInt32(Year), Convert.ToInt32(Month), 1);
var endDate = new DateTime(Convert.ToInt32(Year), Convert.ToInt32(Month), DateTime.DaysInMonth((Convert.ToInt32(Year)), Convert.ToInt32(Month)));
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
Hi I have to compare HH:MM(hour and minutes). How can i do so?
var t1 = DateTime.Now.ToString("HH:mm");
var t2 = "20:03";
var res =result(t1, t2);
public int result(string t1, string t2)
{
int i = -1;
int hr1 = Convert.ToInt32(t1.Split(':')[0]);
int hr2 = Convert.ToInt32(t2.Split(':')[0]);
int min1 = Convert.ToInt32(t1.Split(':')[1]);
int min2 = Convert.ToInt32(t2.Split(':')[1]);
if (hr2 >= hr1)
{
if (min2 >= min1)
{
i = 1;
}
}
return i;
}
But it is not correct.. it is not taking care of all conditions.. how to make it perfect. Or is there any built in function that does this with thsi input only(I checked but no answer).
Thanks in advance
If you can assume the two strings are already in the right format, just use:
return t1.CompareTo(t2);
After all, they're lexicographically sorted due to the format used - no need to parse :)
With all the references to TimeSpan... Of course if you were using Noda Time you could use:
private static readonly LocalTimePattern TimePattern =
LocalTimePattern.CreateWithInvariantInfo("HH:mm");
...
public int CompareTimes(string t1, string t2)
{
// These will throw if the values are invalid. Use TryGetValue
// or the Success property to check first...
LocalTime time1 = TimePattern.Parse(t1).Value;
LocalTime time2 = TimePattern.Parse(t2).Value;
return time1.CompareTo(time2);
}
(You can use TimeSpan if you want, of course... but LocalTime represents the actual type of data you've got: a time of day, rather than an amount of time passing ;)
Use a TimeSpan:
TimeSpan s1 = TimeSpan.Parse(t1);
TimeSpan s2 = TimeSpan.Parse(t2);
return s1.CompareTo(s2);
If you're not sure the inputs are in the correct format, you can use TryParse instead.
If these represent clock times (i.e. hour is always less than 24), then DateTime.ParseExact is what you want.
Otherwise, TimeSpan.ParseExact
If you can guarantee that the provided time is always HH:mm you can use TimeSpan.ParseExact.
You can parse the time direct from the string. Beware the culture!
var time1 = DateTime.ParseExact("12:56", "hh:mm", CultureInfo.CurrentCulture);
var time2 = DateTime.ParseExact("11:21", "hh:mm", CultureInfo.CurrentCulture);
The other solutions are more elegant and simple and deal with culture issues and should be used in professional level code.
But to fix your code, you only need to compare the minute values if and only if the hour values are equal.
var t1 = DateTime.Now.ToString("HH:mm");
var t2 = "20:03";
var res =result(t1, t2);
public int result(string t1, string t2)
{
int i = -1;
int hr1 = Convert.ToInt32(t1.Split(':')[0]);
int hr2 = Convert.ToInt32(t2.Split(':')[0]);
int min1 = Convert.ToInt32(t1.Split(':')[1]);
int min2 = Convert.ToInt32(t2.Split(':')[1]);
if (hr2 > hr1)
i = 1;
else if (hr2 = hr1 && min2 >= min1)
i = 1;
return i;
}
This works
public int CompareTime(string t1, string t2)
{
int i = -1;
int hr1 = Convert.ToInt32(t1.Split(':')[0]);
int hr2 = Convert.ToInt32(t2.Split(':')[0]);
int min1 = Convert.ToInt32(t1.Split(':')[1]);
int min2 = Convert.ToInt32(t2.Split(':')[1]);
if (hr2 == hr1)
{
if (min2 >= min1)
{
i = 1;
}
}
if (hr2 > hr1)
{
i = 1;
}
return i;
}
I am comparing the LastWriteTime of two files, however it is always failing because the file I downloaded off the net always has milliseconds set at 0, and my original file has an actual value. Is there a simple way to ignore the milliseconds when comparing?
Here's my function:
//compare file's dates
public bool CompareByModifiedDate(string strOrigFile, string strDownloadedFile)
{
DateTime dtOrig = File.GetLastWriteTime(strOrigFile);
DateTime dtNew = File.GetLastWriteTime(strDownloadedFile);
if (dtOrig == dtNew)
return true;
else
return false;
}
I recommend you use an extension method:
public static DateTime TrimMilliseconds(this DateTime dt)
{
return new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, 0, dt.Kind);
}
then its just:
if (dtOrig.TrimMilliseconds() == dtNew.TrimMilliseconds())
Care should be taken, if dt has non-zero microseconds (fractions of millis). Setting only milliseconds to zero is not enough.
To set millis and below to zero (and get a succesfull comparison), the code would be:
dt = dt.AddTicks(-dt.Ticks % TimeSpan.TicksPerSecond); // TimeSpan.TicksPerSecond=10000000
Create a new DateTime value with the milliseconds component set to 0:
dt = dt.AddMilliseconds(-dt.Millisecond);
TimeSpan difference = dtNew - dtOrig;
if (difference >= TimeSpan.FromSeconds(1))
{
...
}
You can subtract them, to get a TimeSpan.
Then use TimeSpan.totalSeconds()
This is overkill for a single Truncate, but if you have several and of various types you could do this using the generalized Extension Method below:
DateTime dtSecs = DateTime.Now.TruncateTo(Extensions.DateTruncate.Second);
DateTime dtHrs = DateTime.Now.TruncateTo(Extensions.DateTruncate.Hour);
More general Use Extension method:
public static DateTime TruncateTo(this DateTime dt, DateTruncate TruncateTo)
{
if (TruncateTo == DateTruncate.Year)
return new DateTime(dt.Year, 0, 0);
else if (TruncateTo == DateTruncate.Month)
return new DateTime(dt.Year, dt.Month, 0);
else if (TruncateTo == DateTruncate.Day)
return new DateTime(dt.Year, dt.Month, dt.Day);
else if (TruncateTo == DateTruncate.Hour)
return new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, 0, 0);
else if (TruncateTo == DateTruncate.Minute)
return new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, 0);
else
return new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second);
}
public enum DateTruncate
{
Year,
Month,
Day,
Hour,
Minute,
Second
}
Here is the simplest way of doing this. You can control precision as you want.
bool AreEqual(DateTime a, DateTime b, TimeSpan precision)
{
return Math.Abs((a - b).TotalMilliseconds) < precision.TotalMilliseconds;
}
and usage is pretty self-explanatory
var _ = AreEqual(a, b, precision: TimeSpan.FromSeconds(1));
One way would be to create new dates, inputting the year, month, day, hour, minute, second into the constructor. Alternatively, you could simply compare each value separately.
Ether set the milliseconds in your other datetime to zero, or subtract one date from the other and just check the TotalMinutes property of the resulting time span.
instead of trimming unrelevant DateTime parts via creating new DateTimes, compare only relevant parts:
public static class Extensions
{
public static bool CompareWith(this DateTime dt1, DateTime dt2)
{
return
dt1.Second == dt2.Second && // 1 of 60 match chance
dt1.Minute == dt2.Minute && // 1 of 60 chance
dt1.Day == dt2.Day && // 1 of 28-31 chance
dt1.Hour == dt2.Hour && // 1 of 24 chance
dt1.Month == dt2.Month && // 1 of 12 chance
dt1.Year == dt2.Year; // depends on dataset
}
}
I took answer by Dean Chalk as base for performance comparison, and results are:
CompareWith is a bit faster than TrimMilliseconds in case of equal dates
CompareWith is a faster than dates are not equal
my perf test (run in Console project)
static void Main(string[] args)
{
var dtOrig = new DateTime(2018, 03, 1, 10, 10, 10);
var dtNew = dtOrig.AddMilliseconds(100);
//// perf run for not-equal dates comparison
//dtNew = dtNew.AddDays(1);
//dtNew = dtNew.AddMinutes(1);
int N = 1000000;
bool isEqual = false;
var sw = Stopwatch.StartNew();
for (int i = 0; i < N; i++)
{
// TrimMilliseconds comes from
// https://stackoverflow.com/a/7029046/1506454
// answer by Dean Chalk
isEqual = dtOrig.TrimMilliseconds() == dtNew.TrimMilliseconds();
}
var ms = sw.ElapsedMilliseconds;
Console.WriteLine("DateTime trim: " + ms + " ms");
sw = Stopwatch.StartNew();
for (int i = 0; i < N; i++)
{
isEqual = dtOrig.CompareWith(dtNew);
}
ms = sw.ElapsedMilliseconds;
Console.WriteLine("DateTime partial compare: " + ms + " ms");
Console.ReadKey();
}
You could create an extension method that would set the milliseconds to zero for a DateTime object
public static DateTime ZeroMilliseconds(this DateTime value) {
return new DateTime(value.Year, value.Month, value.Day,
value.Hours, value.Minutes, value.Seconds);
}
Then in your function
if (dtOrig.ZeroMilliseconds() == dtNew.ZeroMilliseconds())
return true;
else
return false;
Simply you can use datetime format with the format you want, and convert it again to datetime as below,
//compare file's dates
String format1 = #"yyyy-MM-dd HH:mm:ss"; // you also can avoid seconds if you want
public bool CompareByModifiedDate(string strOrigFile, string strDownloadedFile)
{
//.here we will use the format
DateTime dtOrig = Convert.ToDateTime(File.GetLastWriteTime(strOrigFile).ToString(format1));
DateTime dtNew = Convert.ToDateTime(File.GetLastWriteTime(strDownloadedFile).ToString(format1));
if (dtOrig == dtNew)
return true;
else
return false;
}
cast sortable strings and compare. simple and run well.
return string.Compare(dtOrig.ToString("s"), dtNew.ToString("s"),
StringComparison.Ordinal) == 0;
The most straightforward way to truncate time is to format it and parse on the units that you want:
var myDate = DateTime.Parse(DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss"));
DOK's method re-written
public bool CompareByModifiedDate(string strOrigFile, string strDownloadedFile)
{
DateTime dtOrig = DateTime.Parse(File.GetLastWriteTime(strOrigFile).ToString("MM/dd/yyyy hh:mm:ss"));
DateTime dtNew = DateTime.Parse(File.GetLastWriteTime(strDownloadedFile).ToString("MM/dd/yyyy hh:mm:ss"));
if (dtOrig == dtNew)
return true;
else
return false;
}
Don't know why almost all programmers needs extra lines to return a bool value from a function with a bool expression.
instead
if (dtOrig.ZeroMilliseconds() == dtNew.ZeroMilliseconds())
return true;
else
return false;
you can always just use
return dtOrig.ZeroMilliseconds() == dtNew.ZeroMilliseconds()
if the expression is true it returns true else false.
I am making a function to check time fall between a time range in 24hr format, However there is some thing wrong with my code , can any one point out how to fix ?
My code:
bool isDoTime(int starthour, int startminute, int endhour, int endminute)
{
TimeSpan start = new TimeSpan(starthour, startminute, 0);
TimeSpan end = new TimeSpan(endhour, endminute, 0);
TimeSpan add24h = new TimeSpan(24, 0, 0);
TimeSpan now = DateTime.Now.TimeOfDay;
if (starthour > endhour || (endhour == starthour && endminute <= startminute))
{
end += add24h;
}
if ((now > start) && (now < end))
{
return true;
}
return false;
}
Problem: i want to return true when current time between 20:30 - 3:30 , however when i run my code as below. the condition is return true only from 8:30 to 00:00 , not true from 00:00 - 3:30
if (isDoTime(20,30,3,30) //return true from 20:30 - 3:30
{
//dosomething
}
Split up in one check if it spans across midninght, and one for same day.
TimeSpan start = new TimeSpan(starthour, startminute, 0);
TimeSpan end = new TimeSpan(endhour, endminute, 0);
TimeSpan now = DateTime.Now.TimeOfDay;
//The readable version:
if(start>end){
//Must check if after start (before midnight) or before end (after midnight)
if((now > start) || (now < end)){
return true;
{
}
else
{
//Simple check - span is within same day
if ((now > start) && (now < end))
{
return true;
}
}
return false;
The short/cryptic version:
return start > end ? (now > start) || (now < end) : (now > start) && (now < end);
You want to use DateTime structures rather than integers. You can also generalise it to arbitary DateTimes. If secondTime is less than firstTime, it adds 1 day to secondTime.
public bool IsBetween(this DateTime thisTime, DateTime firstTime, DateTime secondTime) {
if (secondTime < firstTime)
secondTime = secondTime.AddDays(1);
return firstTime < thisTime && thisTime < secondTime);
}
// to use...
bool isDoTime = DateTime.Now.IsBetween(firstTime, secondTime);
I think you'd be better off using DateTime however, you will still need to check that if the start time is greater than the end time and add 24 hours in that case.
Your method would start:
bool isDoTime(int starthour, int startminute, int endhour, int endminute)
{
DateTime start = new DateTime(0, 0, 0, starthour, startminute, 0);
DateTime end = new DateTime(0, 0, 0, endhour, endminute, 0);
if (start > end)
{
end.AddDays(1);
}
DateTime now = DateTime.Now;
return start < now && now < end;
}
Though you might want <= tests depending on your logic
(Unless it's your logic of where you're adding 24 hours of course - does that code execute?)
It will be much easier to make to use DateTime's as parameters here, and avoid the whole problem of manually checking:
bool isDoTime(DateTime starttime, DateTime endtime)
{
if (DateTime.Now > starttime && DateTime.Now < endtime)
{
return true;
}
return false;
}
[TestFixture]
public class Class1
{
private DateTime _now;
[SetUp]
public void SetUp()
{
_now = DateTime.MinValue.AddDays(1).AddHours(2); //02.01.0001 02:00:00
}
[Test]
public void TestCase()
{
Assert.IsTrue(IsDoTime(20, 30, 3, 30));
}
bool IsDoTime(int starthour, int startminute, int endhour, int endminute)
{
var start1 = DateTime.MinValue.AddHours(starthour).AddMinutes(startminute); //01.01.0001 20:30:00
var end1 = endhour < starthour
? DateTime.MinValue.AddDays(1).AddHours(endhour).AddMinutes(endminute) //02.01.0001 03:30:00
: DateTime.MinValue.AddHours(endhour).AddMinutes(endminute);
return ((_now > start1) && (_now < end1));
}
}