How to convert fractional years (say 1.25 years) to number of days - c#-3.0

I have a table that shows periods like 1 year to 10 years. I want to calculate number of days (approximately 365 days in a year and no need to include leap year). If it was just years, it is easy to calculate days ( like 2 years = 2*365 days). But how can convert for 1.5 years or 1.75 years into days?
what is the efficient way to calculate days if the years are specified in terms of fractional years.
Thanks
nath

Try:
float year = 1.5;
int days = Math.Round(year * 365);

Since the original question is trivial, I'll answer the more interesting question where leap years and other date/time oddities are to be considered. Since the exact number of days in a year is dependent on the year in question, the only sensible approach would be to calculate it relative to a given date. The first step would be an AddYears overload that accepts double values:
public static DateTime AddYears(this DateTime dateTime, double years)
{
int roundedYears = (int) Math.Floor(years);
var roundedDate = dateTime.AddYears(roundedYears);
var lastYearSpan = roundedDate.AddYears(1) - roundedDate;
return roundedDate.AddDays((years % 1) * lastYearSpan.TotalDays);
}
Now you can get the number of days that make sense for you, for example:
var now = DateTime.UtcNow;
Console.WriteLine((now.AddYears(1.25) - now).TotalDays);
Sample tests:
public void TestAddYearsDouble()
{
var date = new DateTime(2000, 1, 15); //middle of the month to keep things simple
Assert.AreEqual(date.Year + 1, date.AddYears(1.0).Year);
Assert.AreEqual(date.Month, date.AddYears(1.0).Month);
Assert.AreEqual(date.Year, date.AddYears(0.0833).Year);
Assert.AreEqual(date.Month + 1, date.AddYears(0.0833).Month);
Assert.AreEqual(date.Year + 8, date.AddYears(8.5).Year);
Assert.AreEqual(date.Month + 6, date.AddYears(8.5).Month);
}

Related

How to calculate the numbered day of the week using DateTime

What is the best way to calculate the numbered day of the week over an 8 week period?
For example, my app tracks a users progress over an 8 week course.
I'm stuck on how to determine the current numbered day of the week according to the weeks progress, for example, Week 6 - Day 5
I have the users course start date as DateTime from Firebase, and can obviously get DateTime.now() to calculate the difference between course start date and now. How do I go from this so that I can display for example:
Week 2 - Day 3 or Week 6 - Day 4
Let's say the course is started 15 days ago, you can get what you want by something like this:
DateTime now = DateTime.now();
DateTime start = now.subtract(Duration(days:15));
int allDays = now.difference(start).inDays;
int w = allDays ~/ 7 + 1;
int d = allDays % 7;
print('Week $w - day $d');
~/ is the Truncating Division Operator which gives you the Integer result of a division

Format date into a month count and years

We have a DateTime value returning from JSON its coming thru as "10/9/2016 4:46:48 PM" .
What we need to do with it is format it to months or years past like so:
10/9/2016 = 3 years in the past.
The value 10/20/2019 = 3 months
Is this possible?
I'm guessing we would need to grab the month and year and subtract from today's date.
So I would create a function which will calculate difference between today's date and DateTime passed to it. It would look like this
String calculateDifference(DateTime dateTime) {
String text = "months";
double difference = DateTime.now().difference(dateTime).inDays / 30;
if (difference > 11) {
difference = difference / 12;
text = "years";
}
return "${difference.toStringAsFixed(0)} $text";
}
So you just need to parse the date from your JSON to DateTime object and pass it to a variable. You can also add one more condition to return value for days
You can use .difference on DateTime
final dateInThePast = DateTime(2018, 1, 7);
final dateNow = DateTime.now();
final difference = dateNow.difference(dateInThePast).inDays;
And then calculate from Days to Months / Years

Codename One days left in current week or month

I am building a calendar application that needs to calculate the remaining days of (1) the current week and (2) the current month.
What I have tried was using the java.util.Calendar API, but it seems not to be fully supported.
int days = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
How would I do this in CN1?
Many thanks in advance.
We would love to add support for JSR310 in the future which would probably solve this in a more elegant way. This is something that can be done as a cn1lib without modifying Codename One but would require some work...
A bit of a hack to do this is:
int month = cal.get(Calendar.MONTH);
cal.set(Calendar.DAY_OF_MONTH, 1);
if(month == cal.DECEMBER) {
cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) + 1);
cal.set(Calendar.MONTH, Calendar.JANUARY);
} else {
cal.set(Calendar.MONTH, month + 1);
}
int day = 24 * 60 * 60000;
cal.setTime(new Date(cal.getTime().getTime() - day));
I don't know CN1, but you can calculate the values using a subtraction between the max and the current value:
(1) cal.getActualMaximum(Calendar.DAY_OF_WEEK) - cal.get(Calendar.DAY_OF_WEEK)
(2) cal.getActualMaximum(Calendar.DAY_OF_MONTH) - cal.get(Calendar.DAY_OF_MONTH)
For your notification: The first day of the week is sunday in the api of calendar. When your week should start with monday you have to reduce the offset by 1.

java.time.Instant.plus(long amountToAdd, TemporalUnit unit) Unsupported unit

I trying to add few years to current time. My code looks like:
// ten yeas ago
int backYears = 10;
Instant instant = ChronoUnit.YEARS.addTo(Instant.now(), -backYears);
But I got an exception:
java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Years
at java.time.Instant.plus(Instant.java:862)
When I opened the method Instant.plus I see the following:
#Override
public Instant plus(long amountToAdd, TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
switch ((ChronoUnit) unit) {
case NANOS: return plusNanos(amountToAdd);
case MICROS: return plus(amountToAdd / 1000_000, (amountToAdd % 1000_000) * 1000);
case MILLIS: return plusMillis(amountToAdd);
case SECONDS: return plusSeconds(amountToAdd);
case MINUTES: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_MINUTE));
case HOURS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_HOUR));
case HALF_DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY / 2));
case DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY));
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
return unit.addTo(this, amountToAdd);
}
As you can see MONTHS and YEARS are unsupported. But why?
With an old java.util.Calendar I can do that easily:
Calendar c = Calendar.getInstance();
c.setTime(date);
c.add(Calendar.YEAR, amount);
return c.getTime();
The only one reason what I guess is that we don't know how many days in a month and year because of leap day 29 Feb.
But to be honest we also have a leap second.
Thus I think that this is a bug and all ChronoUnits should be supported.
The only one question is: do we need to take in account leap second and leap day.
As for my needs it's okay just to assume that month has 30 days and year 365.
I don't need to make something like Calendar.roll() but this can satisfy me too.
Let’s try something out. I am taking an instant as ZonedDateTime and subtracting 10 years in different time zones.
OffsetDateTime origin = OffsetDateTime.of(2018, 3, 1, 0, 0, 0, 0, ZoneOffset.UTC);
Instant originInstant = origin.toInstant();
Instant tenYearsBackKyiv = origin.atZoneSameInstant(ZoneId.of("Europe/Kiev"))
.minusYears(10)
.toInstant();
long hoursSubtractedKyiv = ChronoUnit.HOURS.between(tenYearsBackKyiv, originInstant);
System.out.println("Hours subtracted in Київ: " + hoursSubtractedKyiv);
Instant tenYearsBackSaoPaulo = origin.atZoneSameInstant(ZoneId.of("America/Sao_Paulo"))
.minusYears(10)
.toInstant();
long hoursSubtractedSaoPaulo = ChronoUnit.HOURS.between(tenYearsBackSaoPaulo, originInstant);
System.out.println("Hours subtracted in São Paulo: " + hoursSubtractedSaoPaulo);
The output is:
Hours subtracted in Київ: 87648
Hours subtracted in São Paulo: 87672
As you can see, 24 hours more (1 day more) is subtracted in São Paulo compared to Київ (Kyiv, Kiev). You may already have figured out that it’s because there we pass from 1 March to 29 February three times in leap years, in Київ only twice.
The old and now outdated Calendar class always had a time zone in it, so knew in which time zone to subtract years (another thing is it was happy to give you a result even in situations where it was unclear which result you wanted). The modern classes ZonedDateTime, OffsetDateTime and LocalDateTime can do the same. So use them. An Instant conceptually doesn’t have a time zone, so refuses to do operations that depend on time zone (I know it’s implemented using UTC, but we should regard this as an irrelevant implementation detail, not as a part of the specification of the interface to the class).
Neither the old nor the modern classes take leap seoncds into account, and you are right, only therefore can an Instant add and subtract days, hours and minutes.

Given Year, Month,Day and the Week number, is it possible to get the Date in C#? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Calculate date from week number
Given Year, Month,Day and the Week number, is it possible to get the Date?
e.g. Year = 2010
Month =Jan
Day = Sun
WeekNumber = 3
output : 2010-01-10
I am trying it in c#
Thanks
I would make it like this:
int Year = 2010;
int Month = 1; //Jan=1, Feb=2, ...
int Day = 0; //Sun=0, Mon=1, ...
int WeekNumber = 3; // greater than 0
DateTime dateValue = new DateTime(Year, Month, 1);
int firstDay = (int)dateValue.DayOfWeek;
dateValue = dateValue.AddDays(Day - firstDay + (WeekNumber - 1) * 7);
I don't think there's something for such date calculations in plain .NET BCL. But there are libraries that can help you, see i.e. Fluent DateTime. Using this library, you can try something like that:
var firstWeekInYearBeginning = new DateTime(2010, 1, 2).Previous(DayOfWeek.Monday); // note 2 to not miss a week if the year begins on Monday
var expectedDate = 3.Weeks().From(firstWeekInYearBeginning);
Based on the APIs here, don't this its possible to initialize a DateTime Object from the information given. You would need to develop an algorithm to get the exact date of the year. A simple strategy would be to get the first Day of the month and based on that, find first Monday of the month. This is the start of WeekNumber 1 for that month, and you can locate your required Week by simpl loop and locate the exact date. You would then know the calendar date you are interested in.
BTW: I am assuming WeekNumber of a year/month starts from the first Monday of that Year/Month. Someone please correct me if I am wrong.
Maybe you should check out System.Globalization.Calendar class. It might be useful.