Decrement date month transition - c#

I have a function to decrement a date by one day each time is called.
private IEnumerable<DateTime> EachDay(DateTime from, DateTime thru)
{
for (var day = thru.Date; day.Date >= from.Date; day = day.Subtract(TimeSpan.FromDays(1)))//day.AddDays(-1))
{
yield return day;
}
}
Seems to work fine until i arrive to the previous month. If someone have a solution ?

I would be using something like this
private IEnumerable<DateTime> EachDay(DateTime from, DateTime thru)
{
var days=(thru.Date - from.Date).Days;
if (days <= 0) yield return DateTime.MinValue;
else for (var day = days; day >= 0; day-=1)
yield return from.Date.AddDays(day);
}
test
var thru =new DateTime(day: 01,month:12, year:2021);
var from= thru.AddDays(-10);
EachDay(from,thru).Dump();
result
2021-12-01
2021-11-30
2021-11-29
2021-11-28
2021-11-27
2021-11-26
2021-11-25
2021-11-24
2021-11-23
2021-11-22
2021-11-21

My other answer notwithstanding, you said in a comment on Serge's answer:
when i give 01/12/2021 the response is 01/00/2021
I just wanted to point out that you may get this if you have a date of midnight on 01/12/2021 and you accidentally use a date format of dd/mm/yyyy when printing it out
mm is minutes, not months. MM is months.. If you're stringing your date using mm the 00 you're seeing is the minute from 00:00:00 time, not the month
All in your entire code might be fine (it seems fine to me) and you're being misled by a typo in a ToString

Finally got it. I store the value in a database and a piece of code induce an implicit conversion from native date format to french date format.
I force to use the native date format into all code and all is now fine.
Thanks for your response

To some extent you're reinventing a wheel here. You can use Enumerable.Range to do your dates:
var f = // the date from eg DateTime.Now;
var t = // the date to eg DateTime.Now.AddDays(-45);
//this line of code generates the dates
var d = Enumerable.Range(0, 1 + (int)((f-t).TotalDays)).Select(x => f.AddDays(-x));
The dates in d have no problem crossing a month boundary

Related

If condition not working as expected c#

This is now bugging me , i have tried to fix it for the past hour but still no luck!
I hope some one could spot what i'm doing wrong . here is my code:
var maxDays = 30;
DateTime today = DateTime.Now; //todays date
DateTime lastAction = '2017-03-07 12:47:58.967';
double totalDays = (lastAction - today).TotalDays;
var days = Math.Round(totalDays);
if(days > maxDays)
{
//never hits this even though days is greater than max days ..i'm so confused
}
what am i doing wrong?
Duplicate problem as here:
C# Number of days between two dates problem
Timespan.TotalDays can be negative. So in your case it is almost guaranteed that lastAction - today will be a negative number, and so will always be less than 30.
If you only care about the absolute value of days, use Math.Abs otherwise re-arrange so that you are subtracting lastAction from today (today - lastAction).
Note that due to rounding, your condition will still not be triggered if there is less than 1 day difference.
Is it possible you are subtracting a larger value (today) from a small value (lastaction) which should result in a negative number making days negative?
That and you do need to do an explicit parse on the string to make it a date:
DateTime lastAction = DateTime.Parse("2017-03-07 12:47:58
.967");
Couple of things.
First you cant convert a string to DateTime like that. You should do something like this instead. DateTime lastAction = DateTime.Parse("2017-03-07 12:47:58.967");
Second, Just as #MikeS said, you are subtracting the lastAction from Today, which is resulting in a negative number (in this case its like -173). You should flip that statement. double totalDays = ( today - lastAction).TotalDays;
Your whole section should look something like this.
var maxDays = 30;
DateTime today = DateTime.Now; //todays date
DateTime lastAction = DateTime.Parse("2017-03-07 12:47:58.967");
double totalDays = ( today - lastAction).TotalDays;
var days = Math.Round(totalDays);
if (days > maxDays)
{
// now this is hit
}
Thanks for the help. I did something stupid .. I had
double totalDays = (lastAction - today).TotalDays; // returns -176
changed my code to:
double totalDays = (today - lastAction).TotalDays; //returns 176
Your first problem:
You didn't parse the string to DateTime.
DateTime lastAction = Convert.ToDateTime("2017-03-07 12:47:58.967");
Your second problem:
You were receiving a negative value, and checking if it's bigger.
var days = (Math.Round(totalDays)) * (-1);
Like this, it should work.

Calculate the annual use of a service starting from the date of signing

I need to calculate the annual use of a service starting from the date of signing. Something like:
select Count(*) from TABLENAME where Date >= MYDATE
MYDATE need to be calculate from a subscription date and I need to get the last year date from subscription referring to the current date
Some examples:
subscription date: 2007-06-29
if current date is : 2015-04-29 then date is: 2014-06-29
if current date is : 2015-06-29 then date is: 2015-06-29
if current date is : 2015-06-29 then date is: 2015-06-29
I'm using c# to calculate the date but it crashes in leapyear:
var date = new DateTime(DateTime.Now.Year, subscriptionDate.Month, subscriptionDate.Day);
if (DateTime.Now.Date < date)
{
date = date.AddYears(-1);
}
I was wondering if there were a clever/better way to do it in c# or mysql also handling leapyear
---UPDATE----
Running example with suggested solutions
Well, I'd do it in Noda Time, myself:
LocalDate subscriptionDate = ...;
LocalDate today = ...; // Need to take time zone into account
int years = Period.Between(subscriptionDate, today);
return subscription.PlusYears(years);
With .NET that would be slightly harder, but I'd still go for the approach of adding years (and letting it do the truncation for Feb 29th):
// Only call this *once* - otherwise you could get inconsistent results
DateTime today = DateTime.Today;
int years = today.Year - subscriptionDate.Year;
DateTime candidate = subscriptionDate.AddYears(years);
// We might have overshot, in which case lower the number of years.
return candidate <= today ? candidate : subscriptionDate.AddYears(years - 1);
Thanks to Yuri Dorokhov answer and Jon Skeet suggestion
I found a solution that works well and handle leap year:
int year = DateTime.Now.DayOfYear >= subscriptionDate.DayOfYear ?
DateTime.Now.Year : DateTime.Now.Year - 1;
var date = new DateTime(year, 1, 1).AddDays(subscriptionDate.DayOfYear - 1);
--------UPDATE------
I leave here this answer as reference but it does not handle well leap year so don't use it
Use mysql DATE_SUB function
DATE_SUB(Date, INTERVAL 1 YEAR)

how to get no of days and nights between two dates using c#

i am doing a project on cab services.in this rate is different for day and night.
in the form only journey start date and end date is selected.based on this i have to calculate the no of days and nights.
here i am confused how to calculate the no of days and night.
thanks in advance.
private List<DateTime> GetDateRange(DateTime StartingDate, DateTime EndingDate)
{
if (StartingDate > EndingDate)
{
return null;
}
List<DateTime> rv = new List<DateTime>();
DateTime tmpDate = StartingDate;
do
{
rv.Add(tmpDate);
tmpDate = tmpDate.AddDays(1);
} while (tmpDate <= EndingDate);
return rv;
}
To view this code in action, copy and paste the following code into SnippetCompiler:
DateTime StartingDate = DateTime.Parse("02/25/2007");
DateTime EndingDate = DateTime.Parse("03/06/2007");
foreach (DateTime date in GetDateRange(StartingDate,EndingDate))
{
WL(date.ToShortDateString());
}
Sample output :
2/25/2007
2/26/2007
2/27/2007
2/28/2007
3/1/2007
3/2/2007
3/3/2007
3/4/2007
3/5/2007
3/6/2007
Use the Subtract method to get the difference, which is a TimeSpan value. Example:
TimeSpan diff = SecondDate.Subtract(FirstDate);
You can get the length of the time span for example in hours:
double hours = diff.TotalHours;
I'm not sure which time unit "days and nights" could be interpreted as, though. Perhaps days?
double days = diff.TotalDays;
DateTime dt1,dt2;
//...
TimeSpan period = dt1 - dt2;
int days = period.Days;
It sounds like a very long Cab journey that takes days and nights!
I think you need to define what a day and a night is more clearly in order to get your perfect answer. You also need to think about what impact Daylight Saving Time has on your calculations.
If say:
a day was the period from 6am to 6pm
the night was the rest - from 6pm to 6am
and you wanted to really count hours rather than days
In this case then a calculation would require you to:
iterate a currentDateTime from the startDateTime to the endDateTime
choose the increment in the currentDateTime so that it jumps to the next time barrier (6am, 6pm or the endDateTime)
within each loop, then add to your cumulative calculation of numDayHours or numNightHours so far.
Note that:
you could make this calculation quicker by counting whole days along the way
you need to be very careful about the time zone you are calculating in (I just hope that your taxi doesn't cross time zone boundaries!)
you need to be very careful about local time changes - especially "daylight savings time" type changes - the duration from 6pm to 6am is not always 12 hours!
Some pseudo code:
var numDayHours = 0.0;
var numNightHours = 0.0;
var current = startDateTime;
while (current < endDateTime)
{
next_hop = calculate_next_hop (current, endDateTime);
// select next date time
switch (next_hop.hop_type)
{
case HopType.night_time_hop:
numNightHours += next_hop.num_hours;
break;
case HopType.day_time_hop:
numDayHours += next_hop.num_hours;
break;
}
current = next_hop.EndDateTime;
}
// and here is the result
double numDays = numDayHours / 12.0;
double numHours = numNightHours / 12.0;

DateTime of next 3am occurrence

I'm sure this is very easy, but I've got a sudden mental block.
I'm trying to get a DateTime object for the next occurence of 3am. For example, if DateTime.Now is 16/july/2009 : 12:04pm - the next occurance of 3am would be 17/july/2009 : 03:00
However, if DateTime.Now was 17/july/2009 : 01:00 then the next occurence would still be 17/july/2009 : 03:00 (not the day after).
Does that make sense?
One option:
DateTime now = DateTime.Now;
DateTime today3am = now.Date.AddHours(3);
DateTime next3am = now <= today3am ? today3am : today3am.AddDays(1);
Another:
DateTime now = DateTime.Now;
DateTime today = now.Date;
DateTime next3am = today.AddHours(3).AddDays(now.Hour >= 3 ? 1 : 0)
Lots of ways of skinning that particular cat :)
This is all in local time of course, which means you don't need to worry about time zones. Life becomes trickier if you want to get time zones involved...
Note that it's a good idea to take DateTime.Now once to avoid problems if the date rolls over while you're calculating...
DateTime now = DateTime.Now;
DateTime threeAM = now.Date.AddHours(3);
if (threeAM < now)
threeAM = threeAM.AddDays(1);
//just add 24 - 3 = 21 hours and get Today (start of day) and Add 3 hour
DateTime now = DateTime.Now.AddHours(21).Today.AddHours(3);
An alternative (using a function):
DateTime NextAt(TimeSpan time)
{
DateTime now = DateTime.Now;
DateTime result = now.Date + time;
return (now <= result) ? result : result.AddDays(1);
}
call it like:
DateTime next3am = NextAt(new TimeSpan(3,0,0));
You can do it without an if statement (or conditional operator):
// get the current time
DateTime now = DateTime.Now;
// get a 3:00 AM point in time in the future
DateTime next = now.Date.AddHours(24 + 3);
// subtract the number of whole extra days
next = next.AddDays((now - next).Days);
I always explain that you should get the point in time (DateTime.Now) only once in a calculation like this, as it's a changing value, so do I have to repeat it? Well, I just did. ;)
I think this One:
DateTime.Now.Date.AddHours(3).AddMinutes(0).AddSeconds(0).AddDays(1);

How do you do end-of-week rounding on a date field in C# (without using LINQ)?

I have a weird date rounding problem that hopefully someone can solve. My client uses a work week that runs from Monday through Sunday. Sunday's date is considered the end of the week, and is used to identify all records entered in a particular week (so anything entered last week would have a WEEKDATE value of '10/26/2008', which is Sunday's date).
One little twist is that users enter records for the previous week up until 11 AM on the Monday of the current week.
So I need a function that starts with DateTime.Now and returns the week-ending date (no time part) according to the rules above. Thanks for your help. I have a solution that works, but I'm too embarassed to post it.
Oh, and I can't use LINQ.
public DateTime WeekNum(DateTime now)
{
DateTime NewNow = now.AddHours(-11).AddDays(6);
return (NewNow.AddDays(- (int) NewNow.DayOfWeek).Date);
}
public void Code(params string[] args)
{
Console.WriteLine(WeekNum(DateTime.Now));
Console.WriteLine(WeekNum(new DateTime(2008,10,27, 10, 00, 00)));
Console.WriteLine(WeekNum(new DateTime(2008,10,27, 12, 00, 00)));
Console.WriteLine(WeekNum(new DateTime(2008,10,28)));
Console.WriteLine(WeekNum(new DateTime(2008,10,25)));
}
You may hard-code DateTime.Now instead of passing a DateTime object. It just made testing easier this way.
This passes for me as well:
[Test]
public void Test()
{
DateTime sunday = DateTime.Parse("10/26/2008");
DateTime nextSunday = DateTime.Parse("11/2/2008");
Assert.AreEqual(sunday, GetSunday(DateTime.Parse("10/21/2008")));
Assert.AreEqual(sunday, GetSunday(DateTime.Parse("10/22/2008")));
Assert.AreEqual(sunday, GetSunday(DateTime.Parse("10/23/2008")));
Assert.AreEqual(sunday, GetSunday(DateTime.Parse("10/24/2008")));
Assert.AreEqual(sunday, GetSunday(DateTime.Parse("10/25/2008")));
Assert.AreEqual(sunday, GetSunday(DateTime.Parse("10/26/2008")));
Assert.AreEqual(sunday, GetSunday(DateTime.Parse("10/27/2008 10:59 AM")));
Assert.AreEqual(nextSunday, GetSunday(DateTime.Parse("10/27/2008 11:00 AM")));
}
private DateTime GetSunday(DateTime date)
{
if (date.DayOfWeek == DayOfWeek.Monday && date.Hour < 11)
return date.Date.AddDays(-1);
while (date.DayOfWeek != DayOfWeek.Sunday)
date = date.AddDays(1);
return date.Date;
}
DateTime GetMidnightFollowingSunday()
{
DateTime now = DateTime.Now;
return now.AddDays(7 - (int)now.DayOfWeek).Date;
}
If you need to start the new week after 11AM on Monday morning just subtract 11 hours from now but then it probably makes sense to name the method something else.
DateTime GetRecordDate()
{
DateTime nowMinusOffset = DateTime.Now.AddHours(-11);
return nowMinusOffset.AddDays(7-(int)nowMinusOffset.DayOfWeek).Date;
}
I've used these extensions with great success:
http://www.codeplex.com/DateTimeExtensions

Categories

Resources