Partly negative period between 2 dates with NodaTime - c#

I use NodaTime library to get period between two days, but sometimes I get partly negative period between two dates:
var start = DateTime.Now;
var end = start.AddDays(7).AddMinutes(-1);
//6 days, 24 hours and -1 minutes
var period = Period.Between(LocalDateTime.FromDateTime(start), LocalDateTime.FromDateTime(end));
How can I prevent such behavior?
At this moment I already have found one solution:
//6 days, 23 hours and 59 minutes, but no weeks, months, years
var duration = period.ToDuration();
But duration object is not contrain weeks, months, years and so on.

TL;DR: Update to Noda Time 2.0.2.
This was a bug in 2.0.0 and 2.0.1 of Noda Time. Brief testing suggests it wasn't an issue in earlier versions.
The problem was due to an optimization when trying to obtain the time parts of a period between two LocalDateTime values. Consider finding the difference between these values using all units:
start: 2017-05-22T12:00:00
end: 2017-05-25T11:30:00
We'd start by finding the days portion: 2 days (not 3, because that would overshoot). That would leave us finding the time units between:
updated-start: 2017-05-24T12:00:00
end: 2017-05-25T11:30:00
When trying to find the number of hours, it would first find the number of days between the two dates, then multiply by 24, and then the number of hours between the results - so we'd end up with 24 hours, which then overshot by 30 minutes.
The fix for this was basically an overhaul of Period - see PR 825 and PR 826. PR 825 was then cherry-picked into the 2.0.x branch, and 2.0.2 was released on May 22nd 2017.

With the help of Jon Skeet, this bug will be fixed in 2.0.2 version of NodaTime.

Related

Entity Framework migration timestamp

Very basic question.
When MSFT creates a migration ID, it prefixes the name of the migration with a timestamp.
For Example.
201802132140243_initial.
Can someone explain how to read that?
year = 2018
month = 02
day = 13
and then?
2140243?
I'm pretty sure that it is the time of day in hhmmss format, maybe to the tenth of a second. If it doesn't fit with the time when you created the migration, maybe it is in UTC time and you live in a different hour band than UTC (not sure about this because I live close to UTC time, so I have never paid attention to see if there is a big difference). So summing up, it should mean 21 hours, 40 minutes, 24.3 seconds

How to get the remaining time from 24 hours in C#

This is currentTime(EST) "2015-09-20 04:25:49.090". I need the below calculation.
Remaining time of "2015-09-20 04:25:49.090" this day (Ex : remaining time of this day is : 19 hours 35 minutes)
againg i have subtract from 24 hours - remainingTime (With minutes)
Could you please suggest me the solution for this?
Regards,
Arun
Sure - you do exactly as you've described, using TimeSpan. You can get the time of day from a DateTime using the TimeOfDay property, and then just subtract that from 24 hours:
// You could use TimeSpan.FromDays(1) as well
var remaining = TimeSpan.FromHours(24) - dateTime.TimeOfDay;
Now, one thing to be wary of is that this doesn't necessarily give you the amount of time left in the day - because "local" days can be different lengths depending on time zone changes (e.g. for daylight saving time). If you need to take that into account (e.g. that on November 1st at 00:30 in New York, there's 24 1/2 hours left in the day...). That's a more complicated question - especially if you also need to take account of time zones where the day doesn't always start at 00:00.
As for the second part of getting "24 hours - remaining time" - that's just "the time of day", as you've got 24 hours - (24 hours - x) which is just x.

Display items that are no more than 6 months old

What is the correct method to display items that are no more than 6 months (180 days) old? I'm using the following code, but it seems to be showing items that don't fit the criterion accurately.
DateTime.Now.Subtract(Convert.ToDateTime(e.DateCreated)).Days <= 180
Where could I have gone wrong?
Edit
Thanks everyone for your help. Turns out the hours were a key factor in deciding the age of an item. I don't really need it to be accurate to the hour, just to the date.
I would just use this to get a date six months ago
var sixMonthsAgo = DateTime.Now.AddDays(-180);
and then compare it with whatever you want to compare. I guess
if (Convert.ToDateTime(e.DateCreated) >= sixMonthsAgo)
in your case.
EDIT:
I performed a test with a test value provided in comments.
var input = DateTime.Parse("2013-06-23 18:14:47.937");
My current date is 21.12.2013 and time is about 11:00 AM.
With that defined, your code yields a result
180.16:39...
So it still meets your requirements, since it is exactly 180 days old + few hours and minutes.
My code yields a result
24.6.2013 about 11:00 AM
and since your date is 23.6. then it is older then the result and therefore does not meet your requirements.
As you can see, the hours play a big role here. So in the end, it very much depends on how you define "180 days ago". If you still feel that neither of the variants work well, give me at least 10 days you compare, both where it works and where it does not work and mark which should be older and which not.
TimeSpan ts = DateTime.Now - Convert.ToDateTime(e.datecreated);
if (ts.TotalDays <= 180)
{
//perform some task
}

Proportionately distribute (prorate) a value across a set of values [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Proportionately distribute (prorate) a value across a set of values
I have been looking for an algorithm to distibute the total amount monthly based on the number of days of the year in C# so that the sum of all proportons is equal to the total value.
A date range within a year, and total amount is given.
Example:
for a value 19550 and date range 9/1/2011 to 6/30/2012
September 1,929.28
October 1,993.59
November 1,929.28
December 1,993.59
January 1,993.59
February 1,864.97 - 28 days
March 1,993.59 - 31 days
April 1,929.28 - 30 days
May 1,993.59
June 1,929.28
but the total is 19,550.04 which is .04 more than the total.
Along with Ricky's answer:
It is not always possible to evenly distribute a given amount over a certain time period. Actually, it is quite rare that an amount is evenly distributed over a given time period.
This is generally accounted for in finance by allowing the last number be less than the average normal number in order to make up the difference.
For example, in your situation the amount for june should be 1929.24.
Generally you keep track of the amount assignment as you are building out the chart. Once you get to the end you have a choice. Either allow the amount to be higher or do one more payment for a much lower amount.
Basically, you need to change your algorithm that generates monthly amounts. Put a check in there to ensure that the amount you calculated is still available. If it's not take the lower of the two values.
Possible related SO answer: Proportionately distribute (prorate) a value across a set of values
Strange that it has the same title as your question...
It sounds like you already have code for proportional distribution; but you are rounding to the nearest cent, so now all you need is to get the exact sum you want. I have two ideas:
Simply compute the difference between the total you wanted and the total you got, then add that amount to one of the months
After computing the value for one month, remove it from the total. For instance, after you compute the value 1929.28 for September, subtract 1929.28 from 19550 and subtract 30 from the number of days. Now your problem changes: instead of distributing 19550 over 9/1/2011 to 6/30/2012, you have to distribute 17620.72 over 10/1/2011 to 6/30/2012. The rounding error will naturally disappear this way, as the final month will get 100% of whatever is left over.

Convert DateTime.Ticks to MySQL DateTime in query

I have a integer column in MySql storing the DateTime.Ticks.
A single tick represents one hundred nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond.
The value of this property represents the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001
How can I convert this to a DateTime in a query? I've tried many things, but cannot get it to work.
For the ticks 634128921500016150 I hope to get the mysql datetime '2010-06-23 12:06:50'
I would have believed the following should work, but it gives '4009-06-22 12:15:50.001600'. It seems it's off by 2001 years, 1 day and 9 minutes... If the years and days is consistent, I can just fix it manually, but the minutes seems a little odd.
SELECT DATE_ADD('0000-01-01 00:00:00',
INTERVAL 634128921500016150/10000000 SECOND_MICROSECOND);
I've tried adding more zeros, but it never matches :|
I also tried Jon Skeet's suggestion, but it gives nearly the same result (some fraction of a second different)
Rather than adding using SECOND_MICROSECOND, try just adding via MICROSECOND:
SELECT DATE_ADD('0001-01-01 00:00:00',
INTERVAL 634121049314500000/10 MICROSECOND);
EDIT: I've just worked out why the years are so wrong. MySQL's minimum date is the year 1000. So I suggest you change it to:
SELECT DATE_ADD('0001-01-01 00:00:00',
INTERVAL (634121049314500000 - base_ticks)/10 MICROSECOND);
where base_ticks is the value of the ticks from new DateTime(1001, 1, 1).Ticks.
Heck, you could rebase wherever you want (e.g. 2000) - that might even work round the 9 minutes issue. It's possible that it's making up for leap seconds over the years, or something like that.
Found myself doing the same thing today. Between Jon's answer and the comments I was able to figure it out, but here it is as a function, all wrapped up with a nice bow on it:
CREATE FUNCTION TicksToDateTime(ticks BIGINT) RETURNS datetime DETERMINISTIC
RETURN CAST(DATE_ADD('2001-01-01 00:00:00',
INTERVAL (ticks - 631139040000000000)/10 MICROSECOND) AS DATETIME);
And for those of us coding against SQL Server Compact Edition, the above bow wrapped function is written in a query as:
Select DATEADD(second, (CAST(([TickField]-631139040000000000) AS
FLOAT)/10000000), '2001-01-01 00:00:00' ) From [Table]
The previous code does not work in Compact Edition. It took a while to figure out, so I thought worth including.
I suppose it would work in other SQL versions too but haven't tested it. It has the advantage of being part of a query, so no function needs to be created.
Cheers.

Categories

Resources