Difference between two dates expressed as years, months, days (in one column) - date

I have a set of columns set up in Google Sheets that display the difference between two dates using the DATEDIF function:
=DATEDIF (AS2, TODAY(), "D")
(number of days passed today since a certain date)
=DATEDIF (AR11, AS11, "D")
(number of days passed between two certain dates)
The values are represented as a number (of days). This is fine for shorter durations, but for something like 987 days I would like to display the value into something more intuitive, such as:
| 2 Years, 8 months, 17 days |
If that is not possible within the same column, I would at least like to have a set of three columns that display this time duration in three separate value types:
| 2 Years | 8 months | 17 days |
Just changing the value type for each column (from days to months for example) would, of course, be simple enough, but I'm not sure how to proceed in keeping the values displayed in relation to each other (and not just have the same value be displayed in different duration types).
Any suggestions, please?

=IF(DATEDIF(A1, B1, "D")>365, QUOTIENT(DATEDIF(A1, B1, "D"), 365)&" year(s) "&
QUOTIENT(MOD(DATEDIF(A1, B1, "D"), 365), 30)&" month(s) "&
MOD(QUOTIENT(MOD(DATEDIF(A1, B1, "D"), 365), 30), 30)&" day(s)",
IF(DATEDIF(A1, B1, "D")>30, QUOTIENT(DATEDIF(A1, B1, "D"), 30)&" month(s) "&
MOD(DATEDIF(A1, B1, "D"), 30)&" day(s)",
DATEDIF(A1, B1, "D")&" day(s)"))

I will interpret your question as requiring an answer in complete years, complete calendar months and any remaining days. This should be fairly straightforward, except where the month containing the start date has more days then the month before the month containing the end date*.
Example:
Start Date End Date Result
28/1/19 1/3/19 1 month and 1 day
29/1/19 1/3/19 1 month and 1 day
30/1/19 1/3/19 1 month and 1 day
31/1/19 1/3/19 1 month and 1 day
If you accept this, then the following formulas should work:
Year
=datedif(A1,B1,"Y")
Month
=mod(datedif(A1,B1,"m"),12)
Day
=IF(DAY(B1)>=DAY(A1),DAY(B1)-DAY(A1),DAY(EOMONTH(B1,-1))+DAY(B1)-MIN(DAY(A1),DAY(EOMONTH(B1,-1))))
EDIT
*Have checked this on this website and found that it makes the same assumption - you get the same duration (1 month and one day) for 28/1/19 to 1/3/19 as 31/1/19 to 1/3/19 although the total number of days (32 or 29) is different.
Possible workaround is to take the days remaining in the start month
=IF(DAY(B1)>=DAY(A1),DAY(B1)-DAY(A1),DAY(EOMONTH(A1,0))-DAY(A1)+DAY(B1))
which seems to agree with this website
You can also use the MD argument to Datedif:
=datedif(A1,B1,"MD")
But in both Google Sheets and Excel this can produce a negative number as warned in the Excel documentation:
The "MD" argument may result in a negative number, a zero, or an inaccurate result. If you are trying to calculate the remaining days after the last completed month...

=IF( DATEDIF(A2, B2, "D")> 365,
SPLIT(QUOTIENT(DATEDIF(A2, B2, "D"), 365)&" "&
QUOTIENT(MOD(DATEDIF(A2, B2, "D"), 365), 30)&" "&
MOD(QUOTIENT(MOD(DATEDIF(A2, B2, "D"), 365), 30), 30), " "),
IF( DATEDIF(A2, B2, "D")> 30,
{"", SPLIT(QUOTIENT(DATEDIF(A2, B2, "D"), 30)&" "&
MOD(DATEDIF(A2, B2, "D"), 30), " ")},
{"", "", DATEDIF(A2, B2, "D")}))
demo spreadsheet

This is based on already having a field with days difference, in this case field A1 (eg. converts number of days to YMD)
=FLOOR(A1/365)&"y "&FLOOR((A1-(FLOOR(A1/365)*365))/30)&"m "&CEILING(A1-((FLOOR((A1-(FLOOR(A1/365)*365))/30)*30)+((FLOOR(A1/365))*365)))&"d"
It's based on a simplified 365-day year, 30-day month calculation, so not perfectly accurate - however this seems to be the method others have used. It also rounds the days up to full days for my example - this could be rounded down with FLOOR instead of CEILING

The 'Recommended Answer' uses manual calculation i.e assumes 365 days in a year & 30 days in a month. To get more precise answer use this formula in Google Sheets:
=ARRAYFORMULA(DATEDIF(B2:B13,C2:C13,"Y")&" years "& DATEDIF(B2:B13,C2:C13,"YM")&" months "& DATEDIF(B2:B13,C2:C13,"MD")&" days")
If you want to use without the Arrayformula:
=DATEDIF(B2,C2,"Y")&" years " & DATEDIF(B2,C2,"YM")&" months " & DATEDIF(B2,C2,"MD")&" days"
Column B: Start Date
Column C: End Date
Thanks

Related

How to convert respectively four column to date formatting at MATLAB?

Excel file(104976x10) includes large data.
A column: Time (unit year)
B column: Year
C column: Day of the year
D column: Hour
E column: Minute
and others including values
I would like to convert column which begins with B column until E column to date format like 'dd/mm/yyyy HH:MM'.
Example for the data:
1998,41655251 1998 152 1 0 12,5 12,0 11,8 11,9 12,0
I would like to do date instead of 2-th, 3-th, 4-th and 5-th columns.
1998,41655251 01/06/1998 01:00 12,5 12,0 11,8 11,9 12,0
or
1998,41655251 01/06/1998 01:00 1998 152 1 0 12,5 12,0 11,8 11,9 12,0
Welcome to SO.
Matlab has two types of date-format:
datetime, introduced in 2014b.
datenum, introcuced in long ago (before 2006b), it is basically a double precision value giving the number of days from January 0, 0000.
I think the best way is to use datetime, and give it the year, month, day, hour and minute values like this:
t=datetime(1998,0,152,1,0,0)
t= '01-May-1998 01:00:00'
As you can see the days automatically overflow into the months. But I end up 1st of may, not 1st of june like in your example.
to change the format:
t.Format='dd/MM/yyyy hh:mm'
t= '01/05/1998 01:00'
to convert it to a string, you can simply use string(t)
This is an example that combines the above functions to read an xlsx file and writes a new one with the updated column.
data=xlsread('test.xlsx');
S = size(data);
t = datetime(data(:,2),0,data(:,3),data(:,4),data(:,5),0);
t.Format='dd/MM/yyyy HH:mm';
data2=num2cell(data(:,1));
data2(:,2)=cellstr(string(t));
data2(:,3:S(2)-3)=num2cell(data(:,6:end));
xlswrite('test2.xlsx',data2);

Subtracting 1 ISO 8601 year from a date in BigQuery

I'm trying to manipulate a date value to go back in time exactly 1 ISO-8601 year.
The following does not work, but best describes what I want to accomplish:
date_add(date '2018-01-03', interval -1 isoyear)
I tried string conversion as an intermediate step, but that doesn't work either:
select parse_date('%G%V%u',safe_cast(safe_cast(format_date('%G%V%u',date '2018-01-03') as int64)-1000 as string))
The error provided for the last one is "Failed to parse input string "2017013"". I don't understand why, this should always resolve to a unique date value.
Is there another way in which I can subtract an ISO year from a date?
This gives the corresponding day of the previous ISO year by subtracting the appropriate number of weeks from the date. I based the calculation on the description of weeks per year from the Wikipedia page:
CREATE TEMP FUNCTION IsLongYear(d DATE) AS (
-- Year starting on Thursday
EXTRACT(DAYOFWEEK FROM DATE_TRUNC(d, YEAR)) = 5 OR
-- Leap year starting on Wednesday
(EXTRACT(DAY FROM DATE_ADD(DATE(EXTRACT(YEAR FROM d), 2, 28), INTERVAL 1 DAY)) = 29
AND EXTRACT(DAYOFWEEK FROM DATE_TRUNC(d, YEAR)) = 4)
);
CREATE TEMP FUNCTION PreviousIsoYear(d DATE) AS (
DATE_SUB(d, INTERVAL IF(IsLongYear(d), 53, 52) WEEK)
);
SELECT PreviousIsoYear('2018-01-03');
This returns 2017-01-04, which is the third day of the 2017 ISO year. 2018-01-03 is the third day of the 2018 ISO year.

convert year-month string into daily dates

recently I asked how to convert calendar weeks into a list of dates and received a great and most helpful answer:
convert calendar weeks into daily dates
I tried to apply the above method to create a list of dates based on a column with "year - month". Alas i cannot make out how to account for the different number of days in different months.
And I wonder whether the package lubridate 'automatically' takes leap years into account?
Sample data:
df <- data.frame(YearMonth = c("2016 - M02", "2016 - M06"), values = c(28,60))
M02 = February, M06 = June (M11 would mean November, etc.)
Desired result:
DateList Values
2016-02-01 1
2016-02-02 1
ect
2016-02-28 1
2016-06-01 2
etc
2016-06-30 2
Values would something like
df$values / days_in_month()
Thanks a million in advance - it is honestly very much appreciated!
I'll leave the parsing of the line to you.
To find the last day of a month, assuming you have GNU date, you can do this:
year=2016
month=02
last_day=$(date -d "$year-$month-01 + 1 month - 1 day" +%d)
echo $last_day # => 29 -- oho, a leap year!
Then you can use a for loop to print out each day.
thanks to answer 6 at Add a month to a Date and answer for (how to extract number with leading 0) i got an idea to solve my own question using lubridate. It might not be the most elegant way, but it works.
sample data
data <- data_frame(mon=c("M11","M02"), year=c("2013","2014"), costs=c(200,300))
step 1: create column with number of month
temp2 <- gregexpr("[0-9]+", data$mon)
data$monN <- as.numeric(unlist(regmatches(data$mon, temp2)))
step 2: from year and number of month create a column with the start date
data$StartDate <- as.Date(paste(as.numeric(data$year), formatC(data$monN, width=2, flag="0") ,"01", sep = "-"))
step 3: create a column EndDate as last day of the month based on startdate
data$EndDate <- data$StartDate
day(data$EndDate) <- days_in_month(data$EndDate)
step 4: apply answer from Apply seq.Date using two dataframe columns to create daily list for respective month
data$id <- c(1:nrow(data))
dataL <- setDT(data)[,list(datelist=seq(StartDate, EndDate, by='1 day'), costs= costs/days_in_month(EndDate)) , by = id]

Check if the difference between dates is exactly 'n' months in expression SSRS

In my quarterly report Im trying to validate the two parameters StartDate and EndDate.
I first check if the difference between the dates is 2 months:
Switch(DateDiff(
DateInterval.Month, Parameters!StartDate.Value, Parameters!EndDate.Value) <> 2,
"Error message")
Then I try to add whether the StartDate is the first day of month AND EndDate is last day of month:
And (Day(Parameters!StartDate.Value) <> 1
And Day(DATEADD(DateInterval.Day,1,Parameters!EndDate.Value)))
So the whole expression looks like this:
Switch(DateDiff(DateInterval.Month, Parameters!StartDate.Value, Parameters!EndDate.Value) <> 2
And
Parameters!IsQuarterly.Value = true
And
Day(Parameters!StartDate.Value) <> 1
And
Day(DATEADD(DateInterval.Day,1,Parameters!EndDate.Value))<>1),
"Error: Quarterly report must include 3 months")
But It works wrong when the difference between dates is still 2 months, but StartDate and EndDate are not first and last day of the whole period.
I'd appreciate any help :)
I would say just change the implementation Add another two Parameter With Quarter and Year
Quarter like Q1,Q2,Q3 & Q4 with Value 1,2,3 & 4 respectively and year 2012,2013,2014 & so on
Now based on the parameter selected Qtr & Year set Default value of start & End Date
=DateSerial(Parameters!Year.Value), (3*Parameters!Qtr.Value)-2, 1) --First day of Quarter
=DateAdd("d",-1,DateAdd("q",1,Parameters!Year.Value, (3*Parameters!Qtr.Value)-2, 1))) --Last day of quarter
Doing this no need to do any validation bcz its always get the correct Date Difference.
Other Reference
First day of current quarter
=DateSerial(Year(Now()), (3*DatePart("q",Now()))-2, 1)
Last day of current quarter
=DateAdd("d",-1,DateAdd("q",1,DateSerial(Year(Now()), (3*DatePart("q",Now()))-2, 1)))

Crystal Reports show current month as a 2 digit field

I wonder if anyone could help on this please? I need to show the current month as a 2 digit field. IE
January as 01
February as 02
March as 03
etc until
October as 10
November as 11
December as 12
The formula I am using is: ToText ("0"& Month(CurrentDate))
but shows January as 01.00
ie need to remove the decimal point and the decimal places
Many thanks, Rob
Try this:
ToText( CurrentDate, "MM")
The ToText function will automatically convert the date you are supplying to whatever format you want. You don't need to use the Month function. Per the documentation, you just supply the date and the output format. For the month, you use "MM".
ToText(CurrentDate, "MM")
According to the documention, these are the valid strings you can use
Pattern Result
d Numeric day of month without leading zero (1, 7, 31)
dd Numeric day of month with leading zero (01, 07, 31)
ddd Three day abbreviation of day of week (Mon, Sat)
dddd Full name of day of week (Monday, Saturday)
M Numeric month without leading zero (1, 7, 12)
MM Numeric month with leading zero (01, 07, 12)
MMM Three letter abbreviation of month (Jan, Feb, Mar)
MMMM Full name of month (January, February, March)
yy Last two digits of year (11, 14, 22)
yyyy Full four digits of year (2011, 2014, 2022)
To add to the above, if you need to return something like Mar-17 then:
totext({Command.DocDate},"MMM") + '-' + totext({Command.DocDate},"yy")