Using NSDateIntervalFormatter (or similar) to get "1 year and 2 months" - ios7

Is it possible to use NSDateIntervalFormatter or similar to get a properly (and automatic) localized string like "1 year and 2 months" or "1 year, 2 months" or similar?
I guess I have to use the dateTemplate method and set up it using:
http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns
But reading that document, I don´t have a clear idea about how to get the words "year", "years", "month", "months"...
Basically I want to show a localized time interval using months and years in an app that is used around the world.
Any suggestion? I want to avoid having to do it manually.

Use NSDateComponentsFormatter. For example:
let now = NSDate()
let past = NSDate(timeIntervalSinceNow: -100000000)
let formatter = NSDateComponentsFormatter()
formatter.unitsStyle = NSDateComponentsFormatterUnitsStyle.Full
formatter.allowedUnits = [NSCalendarUnit.Year, NSCalendarUnit.Month]
let intervalString = formatter.stringFromDate(past, toDate: now)
For those two dates, intervalString is now "3 years, 2 months", and will be localized by iOS. There are other methods to get strings from (for example) a time interval instead of two date objects.

Related

Quicksight parse date into 3 days

I know Quicksight could help parse the time into DAY, WEEK, MONTH and YEAR in Field Wells, but how could I customize it into 3 days(72 hrs)? Is there any windowsFunction I could use?
You can introduce a calculated field with formula looking something like that:
addDateTime((extract("DD", {create_time})/3)*3, "DD", truncDate("DD", {create_time}))
And use it for grouping. Depends on your desired time interval it possibly will not do exactly what you need - cause it will group days in month by three, but you can use dateDiff and either some fixed date as starting point. For example:
addDateTime((dateDiff(parseDate("2020-01-01"), truncDate("DD", {create_time}))/3)*3, "DD", parseDate("2020-01-01"))

Adding Period to startDate doesn't produce endDate

I have two LocalDates declared as following:
val startDate = LocalDate.of(2019, 10, 31) // 2019-10-31
val endDate = LocalDate.of(2019, 9, 30) // 2019-09-30
Then I calculate the period between them using Period.between function:
val period = Period.between(startDate, endDate) // P-1M-1D
Here the period has the negative amount of months and days, which is expected given that endDate is earlier than startDate.
However when I add that period back to the startDate, the result I'm getting is not the endDate, but the date one day earlier:
val endDate1 = startDate.plus(period) // 2019-09-29
So the question is, why doesn't the invariant
startDate.plus(Period.between(startDate, endDate)) == endDate
hold for these two dates?
Is it Period.between who returns an incorrect period, or LocalDate.plus who adds it incorrectly?
If you look how plus is implemented for LocalDate
#Override
public LocalDate plus(TemporalAmount amountToAdd) {
if (amountToAdd instanceof Period) {
Period periodToAdd = (Period) amountToAdd;
return plusMonths(periodToAdd.toTotalMonths()).plusDays(periodToAdd.getDays());
}
...
}
you'll see plusMonths(...) and plusDays(...) there.
plusMonths handles cases when one month has 31 days, and the other has 30. So the following code will print 2019-09-30 instead of non-existent 2019-09-31
println(startDate.plusMonths(period.months.toLong()))
After that, subtracting one day results in 2019-09-29. This is the correct result, since 2019-09-29 and 2019-10-31 are 1 month 1 day apart
The Period.between calculation is weird and in this case boils down to
LocalDate end = LocalDate.from(endDateExclusive);
long totalMonths = end.getProlepticMonth() - this.getProlepticMonth();
int days = end.day - this.day;
long years = totalMonths / 12;
int months = (int) (totalMonths % 12); // safe
return Period.of(Math.toIntExact(years), months, days);
where getProlepticMonth is total number of months from 00-00-00. In this case, it's 1 month and 1 day.
From my understanding, it's a bug in a Period.between and LocalDate#plus for negative periods interaction, since the following code has the same meaning
val startDate = LocalDate.of(2019, 10, 31)
val endDate = LocalDate.of(2019, 9, 30)
val period = Period.between(endDate, startDate)
println(endDate.plus(period))
but it prints the correct 2019-10-31.
The problem is that LocalDate#plusMonths normalises date to be always "correct". In the following code, you can see that after subtracting 1 month from 2019-10-31 the result is 2019-09-31 that is then normalised to 2019-10-30
public LocalDate plusMonths(long monthsToAdd) {
...
return resolvePreviousValid(newYear, newMonth, day);
}
private static LocalDate resolvePreviousValid(int year, int month, int day) {
switch (month) {
...
case 9:
case 11:
day = Math.min(day, 30);
break;
}
return new LocalDate(year, month, day);
}
I believe that you are simply out of luck. The invariant that you have invented sounds reasonable, but doesn’t hold in java.time.
It seems that the between method just subtracts the month numbers and the days of month and since the results have the same sign, is content with this result. I think I agree that probably a better decision could have been taken here, but as #Meno Hochschild has correctly stated, math involving the 29, 30 or 31 of months can hardly be clearcut, and I dare not suggest what the better rule would have been.
I bet they are not going to change it now. Not even if you file a bug report (which you can always try). Too much code is already relying on how it’s been working for more than five and a half years.
Adding P-1M-1D back into the start date works the way I would have expected. Subtracting 1 month from (really adding –1 month to) October 31 yeilds September 30, and subtracting 1 day yields September 29. Again, it’s not clear-cut, you could argue in favour of September 30 instead.
Analyzing your expectation (in pseudo code)
startDate.plus(Period.between(startDate, endDate)) == endDate
we have to discuss several topics:
how to handle separate units like months or days?
how is the addition of a duration (or "period") defined?
how to determine the temporal distance (duration) between two dates?
how is the subtraction of a duration (or "period") defined?
Let's first look at the units. Days are no problem because they are the smallest possible calendar unit and every calendar date differs by any other date in full integers of days. So we always have in pseudo code equal if positive or negative:
startDate.plus(ChronoUnit.Days.between(startDate, endDate)) == endDate
Months however are tricky because the gregorian calendar defines calendar months with different lengths. So the situation can arise that the addition of any integer of months to a date can cause an invalid date:
[2019-08-31] + P1M = [2019-09-31]
The decision of java.time to reduce the end date to a valid one - here [2019-09-30] - is reasonable and corresponds to the expectations of most users because the final date still preserves the calculated month. However, this addition including an end-of-month-correction is NOT reversible, see the reverted operation called subtraction:
[2019-09-30] - P1M = [2019-08-30]
The result is also reasonable because a) the basic rule of month addition is to keep the day-of-month as much as possible and b) [2019-08-30] + P1M = [2019-09-30].
What is the addition of a duration (period) exactly?
In java.time, a Period is a composition of items consisting of years, months and days with any integer partial amounts. So the addition of a Period can be resolved to the addition of the partial amounts to the starting date. Since years are always convertible to 12-multiples of months, we can first combine years and months and then add the total in one step in order to avoid strange side effects in leap years. The days can be added in the last step. A reasonable design as done in java.time.
How to determine the right Period between two dates?
Let's first discuss the case when the duration is positive, meaning the starting date is before the ending date. Then we can always define the duration by first determining the difference in months and then in days. This order is important to achieve a month component because otherwise every duration between two dates would only consist of days. Using your example dates:
[2019-09-30] + P1M1D = [2019-10-31]
Technically, the starting date is first moved forward by the calculated difference in months between start and end. Then the day delta as difference between the moved start date and the end date is added to the moved start date. This way we can calculate the duration as P1M1D in the example. So far so reasonable.
How to subtract a duration?
Most interesting point in the previous addition example is, there is by accident NO end-of-month-correction. Nevertheless java.time fails to do the reverse subtraction.
It first subtracts the months and then the days:
[2019-10-31] - P1M1D = [2019-09-29]
If java.time had instead tried to reverse the steps in the addition before then the natural choice would have been to first subtract the days and then the months. With this changed order, we would get [2019-09-30]. The changed order in the subtraction would help as long as there was no end-of-month-correction in the corresponding addition step. This is especially true if the day-of-month of any starting or ending date is not bigger than 28 (the minimum possible month length). Unfortunately java.time has defined another design for the subtraction of Period which leads to less consistent results.
Is the addition of a duration reversible in the subtraction?
First we have to understand that the suggested changed order in the subtraction of a duration from a given calendar date does not guarantee the reversibility of the addition. Counter example which has an end-of-month-correction in the addition:
[2011-03-31] + P3M1D = [2011-06-30] + P1D = [2011-07-01] (ok)
[2011-07-01] - P3M1D = [2011-06-30] - P3M = [2011-03-30] :-(
Changing the order is not bad because it yields more consistent results. But
how to cure the remaining deficiencies? The only way left is to change the calculation of the duration, too. Instead of using P3M1D, we can see that the duration P2M31D will work in both directions:
[2011-03-31] + P2M31D = [2011-05-31] + P31D = [2011-07-01] (ok)
[2011-07-01] - P2M31D = [2011-05-31] - P2M = [2011-03-31] (ok)
So the idea is to change the normalization of the computed duration. This can be done by looking if the addition of the computed month delta is reversible in a subtraction step - i.e. avoids the need for an end-of-month-correction. java.time does unfortunately not offer such a solution. It is not a bug, but can be considered as a design limitation.
Alternatives?
I have enhanced my time library Time4J by reversible metrics which deploy the ideas given above. See following example:
PlainDate d1 = PlainDate.of(2011, 3, 31);
PlainDate d2 = PlainDate.of(2011, 7, 1);
TimeMetric<CalendarUnit, Duration<CalendarUnit>> metric =
Duration.inYearsMonthsDays().reversible();
Duration<CalendarUnit> duration =
metric.between(d1, d2); // P2M31D
Duration<CalendarUnit> invDur =
metric.between(d2, d1); // -P2M31D
assertThat(d1.plus(duration), is(d2)); // first invariance
assertThat(invDur, is(duration.inverse())); // second invariance
assertThat(d2.minus(duration), is(d1)); // third invariance

VB - Fill cell background based on date comparing today to cell value

I have a column that returns dates in this form:
"2016-06-01 23:29:34.283"
I am wondering how I can fill the cell background green if the day matches today, and red if its not today (hour and minute doesn't matter).
I tried this but no luck:
=Switch(Fields!Last_Upload.value = Today(), "Green", Fields!Last_Upload.value != Today(), "Red").
Edit: This is using VS Data Tools
Of course the problem is comparing the date without the timestamp. You can use the DateValue function for this like so:
=IIf(DateValue(Fields!Last_Upload.value) = Today, "Green", "Red")

How to get month within a range vb2010

I just don't know how to go about this.
I designed a program that uses MS Access as its database. I have a field for month and year (the field data type is text) where user can register details. The program will register the month and year the user have chosen e.g month= September, year=2011.
My problem now is how to chose a range of data to view by the user using the month and year as a criteria e.g the User may want to view data range from (September 2011 to July 2013).
I couldn't figure out even how to try. Help will be highly appreciated.
Perhaps you could change your application logic to store the month and year as their respective numbers rather than text and change the field data types to numeric.
You could then construct a DateTime object from them, for example September would be 9 and you could use code like the following:
var startDate = new DateTime(year, month, 1); // get year and month as integers from database, uses the first as the date
var endDate = new DateTime(year, month, 10); // change the date but keeps the month and year the same
var endDate2 = startDate.AddMonths(1); // adds 1 month to the date
Alternatively, you could try using a calendar control to allow the user to select two dates instead of building it from a number of fields. Depending on what you are using this could be achieved a number of ways, for example in ASP.Net or WPF you could use two calendar controls and just use their SelectedDate properties as your range.
A range is from a startpoint until an end point. For the startpoint you can add automatically the first of Month. For the endpoint is it more complicated because there is no fix endpoint. What you can do is following:
Write an array that contains for each month the days (e.g. 30 or 31). Except for Febrauary there is a fix pattern.
for Febrauary use the selected year to check is the year a leap year or not. If not add 28, else add 29.
After that create the date string for your SQL:
Startdate 1.9.2011. Do for the entdate the same.
After that, I think you can use the keyword between in your SQL query.
You can assume that everything is entered on the first day of each month. I would pull the information using a query to the database.
select * from [tablename] where DateSerial([colYear], [colMonth], 1) between DateSerial([fromYear], [fromMonth], 1) and DateSerial([toYear], [toMonth], 1)
In this question are some ways to do this:
First. Filter the dates in a range assuming that you use a date like '07-12-2012'
i.e. September 2011 to July 2013
Where DateColumn > '09-01-2011' and DateColumn < '07-31-2013'
OR
Specify a Date and a Year
Where month(DateColumn)='1' and year(DateColumn)='2016'
Note:
There are many ways to do this.
You can Manipulate your statement depending on your desired output.

Rails 3 Finding day of week

I'm trying to make my own calendar because i cant seem to get any help with event calendar so what im trying to do is Display the day of the week ie.. January 1 2011 is a Saturday is there an easy command to get that day or do i need something else
You can also get the string, like "Wednesday", using time.strftime("%A")
Can't you use time.wday, 0 = sunday and so on
Actively using in Rails 4 - should in most other versions as well...
Both of these options will give you the day string (eg. "Saturday") for the date specified:
Specific date:
Date.new(2011, 1, 1).strftime('%A') # returns "Saturday"
Today:
Date.today.strftime('%A')
If you're attempting to write your own calendar from scratch and want to write a function to do day lookup, you might want to check out Conway's Doomsday Algorithm, which is an interesting method for determining the day of the week on any given date. Otherwise the standard time class has a wday method which returns a number from 0-6 (0 is Sunday, 1 is Monday, etc).
We can use Time.now.utc.wday to get day of week without considering zone.
No need to use the Time class. date.cwday will return 1 for Monday, 2 for Tuesday etc.